DIRECTORY BootFile USING[ Entry, Header, maxEntriesPerHeader, maxEntriesPerTrailer, MemorySizeToFileSize, Trailer ], 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, GetRoot, Handle, Info, IsDebugger, Open, PageCount, PageNumber, Read, SetRoot, SetSize, SystemVolume, Volume, VolumeFile, wordsPerPage, Write ], PrincOpsUtils USING[ IsVacant ], VM USING[ PageNumberForAddress, Allocate, Free, Interval, MakeUnchanged, PageNumber, AddressForPageNumber, Pin, State, Unpin, PagesForWords ], VMSideDoor USING[ rmPages ], WorldVM USING[ AddressFault, BadWorld ], WVMPrivate; WVMOutLd: MONITOR IMPORTS BootFile, Booting, DebuggerFormat, Disk, File, PrincOpsUtils, VM, VMSideDoor, WorldVM, WVMPrivate EXPORTS WVMPrivate = BEGIN -- Management of outload files -- debugger: File.Handle; debuggee: File.Handle; SetupFiles: ENTRY PROC RETURNS[ok: BOOL] = BEGIN ENABLE UNWIND => NULL; sysVol: File.Volume = File.SystemVolume[]; size: File.PageCount = BootFile.MemorySizeToFileSize[VMSideDoor.rmPages]+257; changed: BOOLEAN _ FALSE; IF NOT File.IsDebugger[sysVol] THEN RETURN[FALSE]; ok _ TRUE; debugger _ VerifyFile[sysVol, debugger, size]; debuggee _ VerifyFile[sysVol, debuggee, size]; END; VerifyFile: INTERNAL PROC[sysVol: File.Volume, which: File.VolumeFile, size: File.PageCount] RETURNS[ new: File.Handle ] = BEGIN changed: BOOL _ FALSE; oldFP: File.FP = File.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 File.SetRoot[which, new]; END; 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: LONG POINTER TO ARRAY [0..0) OF BootFile.Entry]; BFMPointer: TYPE = REF BootFileMapItem; bfmHead: BFMPointer _ NIL; OpenOutLdFile: INTERNAL PROC = BEGIN bfm: BFMPointer; bfh: LONG POINTER TO BootFile.Header; entries: LONG POINTER TO ARRAY [0..0) OF BootFile.Entry; curmax: CARDINAL _ BootFile.maxEntriesPerHeader; curbase: File.PageNumber _ [0]; OutLdPageSpace: PROC RETURNS[vm: LONG POINTER] = -- returns pointer into vm containing data from outload file map page -- BEGIN space: VM.Interval = VM.Allocate[vmPagesPerFilePage]; vm _ VM.AddressForPageNumber[space.page]; File.Read[debuggee, curbase, 1, vm]; VM.MakeUnchanged[space]; END; pagesremaining: CARDINAL; bfmHead _ NIL; bfh _ OutLdPageSpace[]; entries _ @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[] + SIZE[BootFile.Trailer]; bfm.link _ NEW[BootFileMapItem]; bfm _ bfm.link; ENDLOOP; END; CloseOutLdFile: INTERNAL PROC = BEGIN 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; END; SearchOutLdFile: INTERNAL PROCEDURE [mempage: WVMPrivate.PageNumber] RETURNS[ entry: LONG POINTER TO BootFile.Entry ] = BEGIN -- Returns [NIL,NIL] if page isn't in file -- FOR bfm: BFMPointer _ bfmHead, bfm.link UNTIL bfm = NIL DO IF mempage <= bfm.lastMemPage THEN BEGIN -- 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 => BEGIN ReadOutLdPage[[bfm.filePageOffset+i]]; RETURN[ @bfm.entries[i] ]; END REPEAT FINISHED => ERROR ENDLOOP; END; REPEAT FINISHED => RETURN[NIL] ENDLOOP; END; -- Transfers to/from outload file -- ReadOtherCore: PUBLIC ENTRY PROC[data: REF WVMPrivate.PageData, mempage: WVMPrivate.PageNumber] RETURNS[ok: BOOLEAN] = BEGIN 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 -- BEGIN IF PrincOpsUtils.IsVacant[mempage] THEN ERROR WorldVM.AddressFault[mempage]; data^ _ LOOPHOLE[WVMPrivate.PageAddress[mempage], LONG POINTER TO WVMPrivate.PageData]^; ok _ TRUE; END ELSE RETURN[FALSE] ELSE BEGIN data^ _ LOOPHOLE[outLdAddress, LONG POINTER TO WVMPrivate.PageData]^; ok _ TRUE; END; END; WriteOtherCore: PUBLIC ENTRY PROC[data: REF WVMPrivate.PageData, mempage: WVMPrivate.PageNumber] RETURNS[readOnly: BOOL] = BEGIN 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.flags.readonly; IF NOT readOnly THEN entry.value.flags.dirty _ TRUE; END; -- 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] = BEGIN 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; END; -- Control transfers -- -- switch indicating that the client outload file should be believed. -- CantGetHere: ERROR = CODE; CantFindInloadFlag: ERROR = CODE; MyCheckpoint: ENTRY Booting.CheckpointProc = TRUSTED BEGIN ENABLE UNWIND => NULL; CloseOutLdFile[]; InvalidateOutLdPage[]; END; MyRollback: ENTRY Booting.RollbackProc = TRUSTED BEGIN ENABLE UNWIND => NULL; BEGIN -- patch the inloadedOnce boolean in the outload file! mempage: VM.PageNumber = VM.PageNumberForAddress[@Booting.inloadedOnce]; bfh: LONG POINTER TO BootFile.Header; entries: LONG POINTER TO ARRAY [0..0) OF BootFile.Entry; curmax: CARDINAL _ BootFile.maxEntriesPerHeader; curbase: File.PageNumber _ [0]; pagesremaining: CARDINAL; File.Read[debugger, curbase, 1, outLdAddress]; bfh _ outLdAddress; entries _ @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 -- BEGIN FOR i: BFMEntryIndex IN [0..entryCount] DO SELECT LONG[entries[i].page] FROM < mempage => NULL; > mempage => ERROR CantFindInloadFlag[]; ENDCASE => BEGIN 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; END REPEAT FINISHED => ERROR ENDLOOP; END; pagesremaining _ pagesremaining - entryCount; IF pagesremaining = 0 THEN ERROR CantFindInloadFlag[]; curbase _ [filePageOffset+entryCount]; curmax _ BootFile.maxEntriesPerTrailer; File.Read[debugger, curbase, 1, outLdAddress]; entries _ outLdAddress + SIZE[BootFile.Trailer]; ENDLOOP; EXITS done => InvalidateOutLdPage[]; END; OpenOutLdFile[]; END; LocateOther: PUBLIC PROC = BEGIN 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] ] END; GoOther: PUBLIC PROC = { [] _ Booting.Boot[ boot: [logical[root: debuggee]], switches: ALL[FALSE] ] }; END. œCedar Remote Debugging: access to world-swap client memory WVMOutLd.mesa Andrew Birrell September 20, 1983 3:24 pm 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 Ê È˜Jšœ:™:Jšœ ™ Jšœ*™*J˜šÏk ˜ Jšœ œ\˜jJšœœN˜[Jšœœ˜&JšœœL˜VJšœ œ ˜Jšœœœ’˜¯Jšœœ ˜ Jšœœ†˜ŽJšœ œ ˜Jšœœ˜(J˜ —J˜šœ ˜Jšœ?œ!˜iJšœ ˜—J˜Jš˜J˜JšÏc!˜!J˜J˜J˜J˜š Ïn œœœœœ˜*Jš˜Jšœœœ˜J˜*JšœM˜MJšœ œœ˜Jš œœœœœ˜2Jšœœ˜ Jšœ.˜.Jšœ.˜.Jšœ˜J˜—šŸ œœœC˜\Jšœ˜Jš˜Jšœ œœ˜Jšœ œ"˜0Jšœ6œœ˜GJšœœœ œ$˜FJšœœ œ˜OJšœ œ˜)Jšœ˜—J˜Jšœœœ"˜>Jšœ œ œ˜:Jšœœœ˜)Jšœœœœ'˜FJ˜šŸ œœœ˜5šœœœ8˜RJ˜——šŸœœœ˜Jšœ5˜5J˜—šŸœœœ˜$Jšœœœ˜J˜—Jšž&˜&J˜šœœœ˜;J˜ J˜—šœœœ˜ Jšœœ˜J˜#J˜ J˜Jš œ œœœœœ˜9J˜—Jšœ œœ˜'J˜Jšœœ˜J˜šŸ œœœ˜Jš˜J˜Jšœœœœ˜%Jš œ œœœœœ˜8Jšœœ ˜0J˜š Ÿœœœœœ˜0JšžH˜HJš˜J˜5Jšœ)˜)J˜$J˜Jšœ˜—Jšœœ˜Jšœ œ˜J˜J˜J˜Jšœœ˜%šœ˜Jšœœ˜-J˜5J˜!J˜1Jšœœœ˜ J˜.J˜'Jšœœ˜4Jšœ œ˜ J˜—Jšœ˜Jšœ˜J˜—šŸœœœ˜Jš˜Jšœ+œ ˜@šœ˜šœ˜JšœK˜K—Jšœ œœ˜Jšœœœœ˜!Jš œœœ)œ œœ˜Mšœ ˜Jšœ3œ#˜X—Jšœ ˜—Jšœ˜Jšœ œ˜Jšœ˜J˜—šŸœœ œ!˜DJšœ œœœ˜2Jš˜Jšž-˜-Jšœ%œ˜7šœœ˜ šœœž*˜5Jšœœ˜+šœœœ˜(Jšœ œ˜Jšœ œœ˜šœ˜ Jš˜J˜&Jšœ˜Jš˜——Jšœœ˜Jšœ˜Jšœ˜——Jšœœœœ˜Jšœ˜Jšœ˜J˜J˜—Jšž$˜$J˜š Ÿ œœœœœ˜?J˜Jšœœ˜Jš˜Jšœœœ˜Jšœœœœ+˜AJšœ ˜šœœ œ ˜šœžO˜TJš˜Jšœ!œœ˜Lšœœ!˜1Jšœœœ˜&—Jšœœ˜ Jš˜—Jšœœœ˜—šœ˜ Jš œœœœœ˜EJšœœ˜ Jšœ˜—Jšœ˜J˜—š Ÿœœœœœ˜@Jšœ œ œ˜9Jš˜Jšœœœ˜Jšœœœœ+˜AJšœ œœœ˜8Jšœœœœ˜EJ˜Jšœ&˜&Jšœœ œœ˜4Jšœ˜J˜J˜J˜—Jšž%˜%J˜J˜*šœ œœœ˜1Jšœ(˜*—Jšœœœ˜Jšœ œœ˜J˜š Ÿœœœœœ˜CJ˜'J˜Jš˜Jšœœœ˜J˜Jšœ˜Jšœ*œ˜LJšœ ˜šœ˜Jšœ œ˜ J˜Jšœ œ˜Jšœ?˜?Jšœœœœ˜D˜Jšœ(˜(Jšœ˜J˜3J˜ —J˜J˜7J˜Jšœ˜JšœC˜EJšœœ˜Jšœœœ˜7Jšœœœ˜ J˜˜Jšœ(˜(Jšœ˜J˜6J˜ —J˜Jšœ8ž˜IJ˜Jšœœœ˜-Jš˜—Jšœœœ˜(Jšœ˜Jšœ˜J˜J˜—Jšž˜J˜JšœI™IJšœK™KJšœI™IJšžH˜HJ˜Jšœ œœ˜Jšœœœ˜!J˜šœœ˜4Jš˜Jšœœœ˜J˜J˜Jšœ˜—J˜šœ œ˜0Jš˜Jšœœœ˜šœž6˜J˜6šœœœ œ˜PJšœ œœ˜—Jšœ˜J˜—šŸœœœ˜JšœA™AJšœ@œœ˜OJ˜—Jšœ˜J˜J˜—…—'f5Ê