DIRECTORY BootFile USING[Entry, Header, maxEntriesPerHeader, maxEntriesPerTrailer, MemorySizeToFileSize, TrailerStart ], Booting USING[ Boot, CheckpointProc, inloadedOnce, RegisterProcs, RollbackProc, switches ], DebuggerFormat USING[ LabelChecksum ], Disk USING[ Channel, DoIO, DriveAttributes, Label, NextChannel, ok, Request, Status ], DiskFace USING[ Type ], File USING[Create, Error, FP, Handle, Info, Open, PageCount, PageNumber, Read, SetSize, SystemVolume, Volume, VolumeFile, wordsPerPage, Write ], FileBackdoor USING[GetRoot, IsDebugger, SetRoot], PrincOps USING[ maxPagesInVM, PageValue, wordsPerPage ], VM USING[PageNumberForAddress, Allocate, Free, Interval, MakeUnchanged, PageNumber, AddressForPageNumber, Pin, State, Unpin, PagesForWords ], VMInternal USING[ IsVacant ], VMSideDoor USING[ rmPages ], WorldVM USING[ AddressFault, BadWorld ], WVMPrivate; WVMOutLd: MONITOR IMPORTS BootFile, Booting, DebuggerFormat, Disk, File, FileBackdoor, VM, VMInternal, VMSideDoor, WorldVM, WVMPrivate EXPORTS WVMPrivate = { EntrySeq: TYPE = LONG POINTER TO EntrySeqRep; EntrySeqRep: TYPE = RECORD [SEQUENCE COMPUTED CARDINAL OF BootFile.Entry]; -- Management of outload files -- debugger: File.Handle; debuggee: File.Handle; pagesInMap: INT = PrincOps.maxPagesInVM / (PrincOps.wordsPerPage / SIZE[PrincOps.PageValue]); SetupFiles: ENTRY PROC RETURNS[ok: BOOL] = { ENABLE UNWIND => NULL; sysVol: File.Volume = File.SystemVolume[]; size: File.PageCount = BootFile.MemorySizeToFileSize[VMSideDoor.rmPages]+pagesInMap+2; changed: BOOLEAN _ FALSE; IF NOT FileBackdoor.IsDebugger[sysVol] THEN RETURN[FALSE]; ok _ TRUE; debugger _ VerifyFile[sysVol, debugger, size]; debuggee _ VerifyFile[sysVol, debuggee, size]; }; VerifyFile: INTERNAL PROC[sysVol: File.Volume, which: File.VolumeFile, size: File.PageCount] RETURNS[ new: File.Handle ] = { changed: BOOL _ FALSE; oldFP: File.FP = FileBackdoor.GetRoot[sysVol, which].fp; new _ File.Open[sysVol, oldFP ! File.Error => { new _ NIL; CONTINUE} ]; IF new = NIL THEN { changed _ TRUE; new _ File.Create[sysVol, size] }; IF File.Info[new].size < size THEN { changed _ TRUE; File.SetSize[new, size] }; IF changed THEN FileBackdoor.SetRoot[which, new]; }; vmPagesPerFilePage: INT = VM.PagesForWords[File.wordsPerPage]; outLdSpace: VM.Interval = VM.Allocate[vmPagesPerFilePage]; outLdPage: File.PageNumber _ [LAST[INT]]; outLdAddress: LONG POINTER = VM.AddressForPageNumber[outLdSpace.page]; ReadOutLdPage: INTERNAL PROC[page: File.PageNumber] = { IF outLdPage # page THEN File.Read[debuggee, outLdPage_page, 1, outLdAddress] }; WriteOutLdPage: INTERNAL PROC = { File.Write[debuggee, outLdPage, 1, outLdAddress] }; InvalidateOutLdPage: INTERNAL PROC = { outLdPage _ [LAST[INT]] }; -- Layout of boot and outload files -- BFMEntryIndex: TYPE = [0..MAX[BootFile.maxEntriesPerHeader, BootFile.maxEntriesPerTrailer]]; BootFileMapItem: TYPE = RECORD [ link: BFMPointer _ NIL, lastMemPage: WVMPrivate.PageNumber, filePageOffset: File.PageNumber, entryCount: BFMEntryIndex, entries: EntrySeq]; BFMPointer: TYPE = REF BootFileMapItem; bfmHead: BFMPointer _ NIL; OpenOutLdFile: INTERNAL PROC = { bfm: BFMPointer; bfh: LONG POINTER TO BootFile.Header; entries: EntrySeq; curmax: CARDINAL _ BootFile.maxEntriesPerHeader; curbase: File.PageNumber _ [0]; OutLdPageSpace: PROC RETURNS[vm: LONG POINTER] = { space: VM.Interval = VM.Allocate[vmPagesPerFilePage]; vm _ VM.AddressForPageNumber[space.page]; File.Read[debuggee, curbase, 1, vm]; VM.MakeUnchanged[space]; }; pagesremaining: CARDINAL; bfmHead _ NIL; bfh _ OutLdPageSpace[]; entries _ LOOPHOLE[@bfh.entries]; pagesremaining _ bfh.countData; bfmHead _ bfm _ NEW[BootFileMapItem]; DO bfm.entries _ entries; bfm.entryCount _ MIN[curmax, pagesremaining]; bfm.lastMemPage _ bfm.entries[bfm.entryCount-1].page; bfm.filePageOffset _ [curbase+1]; pagesremaining _ pagesremaining - bfm.entryCount; IF pagesremaining = 0 THEN EXIT; curbase _ [bfm.filePageOffset+bfm.entryCount]; curmax _ BootFile.maxEntriesPerTrailer; entries _ OutLdPageSpace[] + BootFile.TrailerStart; bfm.link _ NEW[BootFileMapItem]; bfm _ bfm.link; ENDLOOP; }; CloseOutLdFile: INTERNAL PROC = { FOR bfmPtr: BFMPointer _ bfmHead, bfmPtr.link UNTIL bfmPtr = NIL DO space: VM.Interval = [page: VM.PageNumberForAddress[bfmPtr.entries], count: vmPagesPerFilePage]; changed: BOOL _ FALSE; FOR i: NAT IN NAT[0..space.count) DO IF VM.State[space.page+i].dataState = changed THEN changed _ TRUE ENDLOOP; IF changed THEN File.Write[debuggee, [bfmPtr.filePageOffset-1], 1, VM.AddressForPageNumber[space.page]]; VM.Free[space]; ENDLOOP; bfmHead _ NIL; }; SearchOutLdFile: INTERNAL PROCEDURE [mempage: WVMPrivate.PageNumber] RETURNS[ entry: LONG POINTER TO BootFile.Entry ] = { FOR bfm: BFMPointer _ bfmHead, bfm.link UNTIL bfm = NIL DO IF mempage <= bfm.lastMemPage THEN { -- it's in this page of the bootFileMap -- FOR i: BFMEntryIndex IN [0..bfm.entryCount] DO SELECT LONG[bfm.entries[i].page] FROM < mempage => NULL; > mempage => RETURN[NIL]; ENDCASE => { ReadOutLdPage[[bfm.filePageOffset+i]]; RETURN[ @bfm.entries[i] ]; } REPEAT FINISHED => ERROR ENDLOOP; }; REPEAT FINISHED => RETURN[NIL] ENDLOOP; }; -- Transfers to/from outload file -- ReadOtherCore: PUBLIC ENTRY PROC[data: REF WVMPrivate.PageData, mempage: WVMPrivate.PageNumber] RETURNS[ok: BOOLEAN] = { ENABLE UNWIND => NULL; entry: LONG POINTER TO BootFile.Entry = SearchOutLdFile[mempage]; IF entry = NIL THEN IF mempage IN [376B..377B] THEN -- kludge: Germ doesn't write io pages to outload file, so read ours instead -- { IF VMInternal.IsVacant[mempage] THEN ERROR WorldVM.AddressFault[mempage]; data^ _ LOOPHOLE[WVMPrivate.PageAddress[mempage], LONG POINTER TO WVMPrivate.PageData]^; ok _ TRUE; } ELSE RETURN[FALSE] ELSE { data^ _ LOOPHOLE[outLdAddress, LONG POINTER TO WVMPrivate.PageData]^; ok _ TRUE; }; }; WriteOtherCore: PUBLIC ENTRY PROC[data: REF WVMPrivate.PageData, mempage: WVMPrivate.PageNumber] RETURNS[readOnly: BOOL] = { ENABLE UNWIND => NULL; entry: LONG POINTER TO BootFile.Entry = SearchOutLdFile[mempage]; IF entry = NIL THEN ERROR WorldVM.AddressFault[mempage]; LOOPHOLE[outLdAddress, LONG POINTER TO WVMPrivate.PageData]^ _ data^; WriteOutLdPage[]; readOnly _ entry.value.state.flags.readonly; IF NOT readOnly THEN entry.value.state.flags.dirty _ TRUE; }; -- Transfers to/from backing store -- bufferSpace: VM.Interval = VM.Allocate[1]; bufferData: LONG POINTER TO WVMPrivate.PageData = VM.AddressForPageNumber[bufferSpace.page]; UnknownDrive: ERROR = CODE; BadTransfer: ERROR = CODE; MoveLocalDiskPage: PUBLIC ENTRY PROC[data: REF WVMPrivate.PageData, direction: WVMPrivate.ChannelDirection, addr: WVMPrivate.DiskAddress] = { ENABLE UNWIND => NULL; req: Disk.Request; label: Disk.Label; FOR channel: Disk.Channel _ Disk.NextChannel[NIL], Disk.NextChannel[channel] UNTIL channel = NIL DO type: DiskFace.Type; ordinal: INT; status: Disk.Status; countDone: INT; [type: type, ordinal: ordinal] _ Disk.DriveAttributes[channel]; IF type # addr.deviceType OR ordinal # addr.deviceOrdinal THEN LOOP; req _ [ diskPage: [addr.diskPage + addr.offset], data: bufferData, command: [header: verify, label: read, data: read], count: 1 ]; VM.Pin[bufferSpace]; [status, countDone] _ Disk.DoIO[channel, @label, @req]; VM.Unpin[bufferSpace]; IF status # Disk.ok OR DebuggerFormat.LabelChecksum[label, addr.offset] # addr.labelCheck THEN ERROR BadTransfer[]; IF direction = read THEN { data^ _ bufferData^; EXIT }; IF direction # write THEN ERROR; bufferData^ _ data^; req _ [ diskPage: [addr.diskPage + addr.offset], data: bufferData, command: [header: verify, label: verify, data: write], count: 1 ]; VM.Pin[bufferSpace]; [status, countDone] _ Disk.DoIO[channel, @label, @req]; -- write the data VM.Unpin[bufferSpace]; IF status # Disk.ok THEN ERROR BadTransfer[]; EXIT REPEAT FINISHED => ERROR UnknownDrive[]; ENDLOOP; }; -- Control transfers -- -- switch indicating that the client outload file should be believed. -- CantGetHere: ERROR = CODE; CantFindInloadFlag: ERROR = CODE; MyCheckpoint: ENTRY Booting.CheckpointProc = TRUSTED { ENABLE UNWIND => NULL; CloseOutLdFile[]; InvalidateOutLdPage[]; }; MyRollback: ENTRY Booting.RollbackProc = TRUSTED { ENABLE UNWIND => NULL; { -- patch the inloadedOnce boolean in the outload file! mempage: VM.PageNumber = VM.PageNumberForAddress[@Booting.inloadedOnce]; bfh: LONG POINTER TO BootFile.Header; entries: EntrySeq _ NIL; curmax: CARDINAL _ BootFile.maxEntriesPerHeader; curbase: File.PageNumber _ [0]; pagesremaining: CARDINAL; File.Read[debugger, curbase, 1, outLdAddress]; bfh _ outLdAddress; entries _ LOOPHOLE[@bfh.entries]; pagesremaining _ bfh.countData; DO filePageOffset: File.PageNumber = [curbase+1]; entryCount: CARDINAL = MIN[curmax, pagesremaining]; IF mempage <= entries[entryCount-1].page THEN -- it's in this page of the bootFileMap -- { FOR i: BFMEntryIndex IN [0..entryCount] DO SELECT LONG[entries[i].page] FROM < mempage => NULL; > mempage => ERROR CantFindInloadFlag[]; ENDCASE => { diskInLoaded: LONG POINTER TO BOOL; File.Read[debugger, [filePageOffset+i], 1, outLdAddress]; diskInLoaded _ LOOPHOLE[outLdAddress + (LONG[@Booting.inloadedOnce]-VM.AddressForPageNumber[mempage])]; diskInLoaded^ _ TRUE; File.Write[debugger, [filePageOffset+i], 1, outLdAddress]; GOTO done; } REPEAT FINISHED => ERROR ENDLOOP; }; pagesremaining _ pagesremaining - entryCount; IF pagesremaining = 0 THEN ERROR CantFindInloadFlag[]; curbase _ [filePageOffset+entryCount]; curmax _ BootFile.maxEntriesPerTrailer; File.Read[debugger, curbase, 1, outLdAddress]; entries _ outLdAddress + BootFile.TrailerStart; ENDLOOP; EXITS done => InvalidateOutLdPage[]; }; OpenOutLdFile[]; }; LocateOther: PUBLIC PROC = { ENABLE UNWIND => NULL; -- This is called successfully only once per run -- IF NOT SetupFiles[] THEN RETURN WITH ERROR WorldVM.BadWorld[]; Booting.RegisterProcs[c: MyCheckpoint, r: MyRollback]; [] _ Booting.Boot[ boot: IF Booting.switches[w] THEN [noOp[]] ELSE [physical[]], switches: ALL[FALSE] ] }; GoOther: PUBLIC PROC = { [] _ Booting.Boot[ boot: [logical[root: debuggee]], switches: ALL[FALSE] ] }; }. ^WVMOutLd.mesa - access to world-swap client memory Copyright c 1985 by Xerox Corporation. All rights reserved. Andrew Birrell September 20, 1983 3:24 pm Russ Atkinson, February 6, 1985 9:33:47 pm PST returns pointer into vm containing data from outload file map page Returns [NIL,NIL] if page isn't in file Mechanism for handling "inloaded twice". If we're inloaded a second time we cannot proceed, because various pilot caches may not reflect the correct state of the disk(s). In that case, we re-boot our logical volume with a Easy! All the hard stuff is in our Checkpoint and Rollback procs Κ ˜codešœ2™2Kšœ Οmœ1™žœ-˜tKšžœ˜—K˜Kš œ žœžœžœžœ ˜-Kš œ žœžœžœžœžœžœ˜JK˜KšΟc!˜!K˜K˜K˜K˜šœ žœ˜Kšœ1žœ˜K—K˜š Οn œžœžœžœžœ˜,Kšžœžœžœ˜K˜*šœ˜Kšœ?˜?—Kšœ žœžœ˜Kš žœžœ!žœžœžœ˜:Kšœžœ˜ Kšœ.˜.Kšœ.˜.Kšœ˜K˜—š  œžœžœCžœ˜|Kšœ žœžœ˜Kšœ žœ*˜8Kšœ6žœžœ˜GKšžœžœžœ žœ$˜FKšžœžœ žœ˜OKšžœ žœ"˜1Kšœ˜—K˜Kšœžœžœ"˜>Kšœ žœ žœ˜:Kšœžœžœ˜)Kšœžœžœžœ'˜FK˜š  œžœžœ˜7Kšžœžœ8˜PK˜—š œžœžœ˜!Kšœ3˜3K˜—š œžœžœ˜&Kšœ žœžœ˜K˜—KšŸ&˜&K˜šœžœžœ˜;Kšœ ˜ K˜—šœžœžœ˜ Kšœžœ˜K˜#K˜ K˜Kšœ˜K˜—Kšœ žœžœ˜'K˜Kšœžœ˜K˜š  œžœžœ˜ K˜Kšœžœžœžœ˜%Kšœ˜Kšœžœ ˜0K˜š  œžœžœžœžœ˜2KšœB™BKšœžœ žœ˜5Kšœžœ"˜)K˜$Kšžœ˜Kšœ˜—Kšœžœ˜Kšœ žœ˜K˜Kšœ žœ˜!K˜Kšœžœ˜%šžœ˜Kšœžœ˜-K˜5K˜!K˜1Kšžœžœžœ˜ K˜.Kšœ'˜'Kšœ3˜3Kšœ žœ˜ K˜—Kšžœ˜Kšœ˜K˜—š œžœžœ˜!šžœ+žœ žœžœ˜Dšœ˜KšœK˜K—Kšœ žœžœ˜Kšžœžœžœžœ˜!Kš žœžœžœ)žœ žœžœ˜Mšžœ ž˜Kšœ3žœ#˜X—Kšžœ ˜—Kšžœ˜Kšœ žœ˜Kšœ˜K˜—š œžœž œ"žœ žœžœžœ˜yKšœ'™'šžœ%žœž˜:šžœ˜šžœŸ*˜1šžœžœž˜.šžœžœž˜%Kšœ žœ˜Kšœ žœžœ˜šžœ˜ K˜&Kšžœ˜Kšœ˜——Kšžœžœž˜Kšžœ˜—Kšœ˜——Kšžœžœžœžœ˜Kšžœ˜—Kšœ˜K˜K˜—KšŸ$˜$K˜š  œžœžœžœžœ5žœžœ˜xKšžœžœžœ˜Kšœžœžœžœ+˜AKšžœ ž˜šžœžœ žœ ˜šžœŸO˜TKšœ˜Kšžœžœžœ˜Išœžœ!˜1Kšžœžœžœ˜&—Kšœžœ˜ Kšœ˜—Kšžœžœžœ˜—šžœ˜Kš œžœžœžœžœ˜EKšœžœ˜ Kšœ˜—Kšœ˜K˜—š œžœžœžœžœ6žœ žœ˜|Kšžœžœžœ˜Kšœžœžœžœ+˜AKšžœ žœžœžœ˜8Kšžœžœžœžœ˜EK˜Kšœ,˜,Kšžœžœ žœ!žœ˜:Kšœ˜K˜K˜K˜—KšŸ%˜%K˜K˜*Kš œ žœžœžœžœ(˜\Kšœžœžœ˜Kšœ žœžœ˜K˜š  œžœžœžœžœ_˜Kšžœžœžœ˜K˜Kšœ˜Kšžœ*žœ˜LKšžœ ž˜šžœ˜Kšœ žœ˜ K˜Kšœ žœ˜Kšœ?˜?Kšžœžœžœžœ˜D˜Kšœ(˜(Kšœ˜K˜3K˜ —K˜K˜7K˜Kšžœ˜KšžœC˜EKšžœžœ˜Kšžœžœžœ˜7Kšžœžœžœ˜ K˜˜Kšœ(˜(Kšœ˜K˜6K˜ —K˜Kšœ8Ÿ˜IK˜Kšžœžœžœ˜-Kšž˜—Kšžœžœžœ˜(Kšžœ˜Kšœ˜K˜K˜—KšŸ˜K˜KšœI™IKšœK™KKšœI™IKšŸH˜HK˜Kšœ žœžœ˜Kšœžœžœ˜!K˜šœžœžœ˜6Kšžœžœžœ˜K˜K˜Kšœ˜—K˜šœ žœžœ˜2Kšžœžœžœ˜šœŸ6˜8KšœH˜HKšœžœžœžœ˜%Kšœžœ˜Kšœžœ ˜0K˜Kšœžœ˜Kšœ.˜.K˜Kšœ žœ˜!K˜šžœ/˜1Kšœ žœžœ˜3Kšžœ&˜(šžœŸ*˜/Kšœ˜Kšžœžœ˜'šžœžœžœž˜$Kšœ žœ˜Kšœ žœ˜(šžœ˜ Kšœ˜Kš œžœžœžœžœ˜#Kšœ9˜9šœžœ˜&Kšœžœ;˜@—Kšœžœ˜Kšœ:˜:Kšžœ˜ Kšœ˜——Kšžœžœž˜Kšžœ˜Kšœ˜—K˜-Kšžœžœžœ˜6K˜&Kšœ'˜'Kšœ.˜.Kšœ/˜/—Kšžœ˜Kšžœ˜$—Kšœ˜K˜Kšœ˜—K˜š  œžœžœ˜Kšžœžœžœ˜KšŸ3˜3Kš žœžœžœžœžœžœ˜>K˜6šœžœžœ žœ˜PKšœ žœžœ˜—Kšœ˜K˜—š œžœžœ˜KšœA™AKšœ@žœžœ˜OK˜—Kšœ˜K˜K˜—…—'v6S