-- MakeImage.Mesa Edited by Sandman on September 24, 1980 10:46 AM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY AllocDefs USING [ AddSwapStrategy, RemoveSwapStrategy, SwappingProcedure, SwapStrategy], AltoDefs USING [BytesPerPage, PageCount, PageNumber, PageSize], AltoDisplay USING [DCBchainHead], AltoFileDefs USING [CFA, CFP, eofDA, fillinDA, FP, vDA], BcdDefs USING [VersionStamp], BcdMergeOps USING [MergeBcd], BcdOps USING [ProcessModules], SymbolOps: FROM "BcdSymbolOps" USING [FindString], BFSDefs USING [ActOnPages, GetNextDA], ControlDefs USING [ AllocationVector, AllocationVectorSize, AV, ControlLink, EntryVectorItem, FrameHandle, FrameVec, GFT, GFTIndex, GlobalFrameHandle, LargeReturnSlot, LastAVSlot, PrefixHandle, ProcDesc, SpecialReturnSlot, StateVector, SVPointer], CoreSwapDefs USING [level], DiskDefs USING [ DA, DiskPageDesc, DiskRequest, StandardDisk, SwapPages, sysDisk, VirtualDA], DiskKDDefs USING [CloseDiskKD, InitializeDiskKD], FrameDefs USING [GlobalFrame, SwapOutCode], FrameOps USING [ CodeHandle, FlushLargeFrames, Free, GetReturnLink, MyGlobalFrame, MyLocalFrame], ImageDefs USING [ FileRequest, ImageVersion, PuntMesa, StopMesa, UserCleanupProc], ImageFormat USING [ FirstImageDataPage, HeaderPages, ImageHeader, MapItem, MapSpace, VersionID], InlineDefs USING [BITAND, COPY], LoadStateOps USING [ForceDirty, initstate, ReleaseLoadState, state], MiscDefs USING [CurrentTime, GetNetworkNumber, SetBlock, Zero], MakeImageOps USING [ AddFileRequest, BashFile, BashHint, DAofPage, DropFileRequest, FillInCAs, FreeAllSpace, InitFileRequest, InitLoadStates, InitSpace, KDSegment, LockCodeSegment, ProcessBcds, ProcessFileRequests, UnlockCodeSegment], NucleusOps USING [ BFS, Directory, DiskKD, Faults, Files, FSP, HyperRegion, LoadState, MesaInit, Miscellaneous, Modules, NonResident, OurProcess, SegmentsA, SegmentsB, StreamsA, StreamsB, StreamsC, StringsA, StringsB], OsStaticDefs USING [OsStatics], ProcessDefs USING [ CV, DisableInterrupts, DIW, EnableInterrupts, Priority, SetPriority], ProcessOps USING [ ActiveWord, CurrentPSB, CurrentState, FirstProcess, LastProcess, NullQueueHandle, Queue, ReadWDC, ReadyList, Requeue, WakeupsWaiting, WriteWDC], PSBDefs USING [ProcessHandle, PSB], Region USING [Node, NodeObject], SDDefs USING [ sAddFileRequest, sAllocTrap, SD, sGoingAway, sSwapTrap, sXferTrap], SegmentDefs USING [ AddressFromPage, Append, CloseFile, DataSegmentAddress, DataSegmentHandle, DefaultMDSBase, DefaultVersion, DeleteDataSegment, EasyDown, EnumerateDataSegments, EnumerateFiles, EnumerateFileSegments, FileError, FileHandle, FileHint, FileSegmentAddress, FileSegmentHandle, HardDown, MakeDataSegment, NewFile, Object, ObjectHandle, Read, ReleaseFile, SetEndOfFile, SetFileSegmentDA, SwapOut, Unlock, Write], StreamDefs USING [StreamHandle], SwapperOps USING [ AllocateObject, LiberateObject, PositionSeg, mdsNodes, MoveCode, DisableHyperspace, EnableHyperspace, InitMemoryConfig], Storage USING [Prune, PagesForWords], Table USING [Allocate], TrapOps USING [ReadATP, ReadOTP, ReadXTS, WriteXTS]; MakeImage: PROGRAM IMPORTS AllocDefs, BcdMergeOps, BcdOps, SymbolOps, BFSDefs, CoreSwapDefs, DiskDefs, DiskKDDefs, FrameDefs, FrameOps, ImageDefs, InlineDefs, LoadStateOps, MiscDefs, MakeImageOps, NucleusOps, ProcessDefs, ProcessOps, SegmentDefs, SwapperOps, Storage, Table, TrapOps EXPORTS ImageDefs SHARES ProcessDefs, DiskDefs, SegmentDefs, ControlDefs, ImageDefs = BEGIN OPEN DiskDefs, ImageDefs, ControlDefs, SegmentDefs, MakeImageOps; CFA: TYPE = AltoFileDefs.CFA; DataSegmentHandle: TYPE = SegmentDefs.DataSegmentHandle; FP: TYPE = AltoFileDefs.FP; FileHandle: TYPE = SegmentDefs.FileHandle; FileSegmentHandle: TYPE = SegmentDefs.FileSegmentHandle; PageCount: TYPE = AltoDefs.PageCount; PageNumber: TYPE = AltoDefs.PageNumber; vDA: TYPE = AltoFileDefs.vDA; GlobalFrameHandle: TYPE = ControlDefs.GlobalFrameHandle; StreamHandle: TYPE = StreamDefs.StreamHandle; ProcDesc: TYPE = ControlDefs.ProcDesc; SwapTrapDuringMakeImage: PUBLIC SIGNAL = CODE; SwapErrorDuringMakeImage: PUBLIC SIGNAL = CODE; SwapOutDuringMakeImage: PUBLIC SIGNAL = CODE; NoRoomInImageMap: PUBLIC SIGNAL = CODE; SwapTrapError: PROCEDURE = BEGIN dest: ControlDefs.ControlLink; s: ControlDefs.StateVector; ProcessDefs.DisableInterrupts[]; s ← STATE; dest ← TrapOps.ReadOTP[]; ProcessDefs.DisableInterrupts[]; SIGNAL SwapTrapDuringMakeImage; RETURN WITH s; END; SwapOutError: AllocDefs.SwappingProcedure = BEGIN SIGNAL SwapOutDuringMakeImage; RETURN[TRUE]; END; -- File Segment Transfer Routines bufferseg: DataSegmentHandle; buffer: POINTER; BufferPages: PageCount; SwapDR: TYPE = POINTER TO swap DiskRequest; TransferPages: PROCEDURE [ da: vDA, base: PageNumber, pages: PageCount, fp: POINTER TO FP, sdr: SwapDR] RETURNS [next: vDA] = BEGIN OPEN DiskDefs; sdr.da ← @da; sdr.firstPage ← base; sdr.lastPage ← base + pages - 1; sdr.fp ← fp; IF SwapPages[sdr].page # base + pages - 1 THEN SIGNAL SwapErrorDuringMakeImage; next ← sdr.desc.next; RETURN[next]; END; TransferFileSegment: PROCEDURE [ buffer: POINTER, seg: FileSegmentHandle, file: FileHandle, base: PageNumber, fileda: vDA] RETURNS [vDA] = BEGIN dpd: DiskPageDesc; sdr: swap DiskRequest; old: FileHandle ← seg.file; segbase: PageNumber ← seg.base; pages: PageCount ← seg.pages; segda: vDA; WITH s: seg SELECT FROM disk => segda ← s.hint.da; ENDCASE => ERROR SwapErrorDuringMakeImage; seg.base ← base; sdr ← [ca: buffer, da:, firstPage:, lastPage:, fp:, fixedCA: FALSE, action:, lastAction:, signalCheckError: FALSE, option: swap[desc: @dpd]]; IF seg.swappedin THEN BEGIN sdr.ca ← AddressFromPage[seg.VMpage]; sdr.action ← sdr.lastAction ← WriteD; fileda ← TransferPages[fileda, base, pages, @file.fp, @sdr]; old.swapcount ← old.swapcount - 1; file.swapcount ← file.swapcount + 1; END ELSE BEGIN WHILE BufferPages < pages DO pages ← pages - BufferPages; sdr.action ← sdr.lastAction ← ReadD; segda ← TransferPages[segda, segbase, BufferPages, @old.fp, @sdr]; sdr.action ← sdr.lastAction ← WriteD; fileda ← TransferPages[fileda, base, BufferPages, @file.fp, @sdr]; segbase ← segbase + BufferPages; base ← base + BufferPages; ENDLOOP; sdr.action ← sdr.lastAction ← ReadD; segda ← TransferPages[segda, segbase, pages, @old.fp, @sdr]; sdr.action ← sdr.lastAction ← WriteD; fileda ← TransferPages[fileda, base, pages, @file.fp, @sdr]; END; old.segcount ← old.segcount - 1; seg.file ← file; WITH s: seg SELECT FROM disk => s.hint ← FileHint[AltoFileDefs.eofDA, 0]; ENDCASE; file.segcount ← file.segcount + 1; IF old.segcount = 0 THEN ReleaseFile[old]; RETURN[fileda]; END; EnumerateNeededModules: PROCEDURE [proc: PROCEDURE [GlobalFrameHandle]] = BEGIN proc[FrameDefs.GlobalFrame[EnumerateNeededModules]]; proc[FrameDefs.GlobalFrame[MakeImageOps.AddFileRequest]]; proc[FrameDefs.GlobalFrame[BcdOps.ProcessModules]]; proc[LOOPHOLE[NucleusOps.BFS]]; proc[LOOPHOLE[NucleusOps.SegmentsA]]; proc[LOOPHOLE[NucleusOps.SegmentsB]]; proc[LOOPHOLE[NucleusOps.Files]]; proc[LOOPHOLE[NucleusOps.Faults]]; proc[LOOPHOLE[NucleusOps.DiskKD]]; proc[LOOPHOLE[NucleusOps.Miscellaneous]]; proc[LOOPHOLE[NucleusOps.Directory]]; proc[LOOPHOLE[NucleusOps.StreamsA]]; proc[LOOPHOLE[NucleusOps.StreamsB]]; proc[LOOPHOLE[NucleusOps.StreamsC]]; proc[LOOPHOLE[NucleusOps.FSP]]; proc[LOOPHOLE[NucleusOps.StringsA]]; proc[LOOPHOLE[NucleusOps.StringsB]]; proc[LOOPHOLE[NucleusOps.LoadState]]; proc[LOOPHOLE[NucleusOps.MesaInit]]; proc[LOOPHOLE[NucleusOps.NonResident]]; proc[LOOPHOLE[NucleusOps.OurProcess]]; proc[LOOPHOLE[NucleusOps.HyperRegion]]; proc[LOOPHOLE[NucleusOps.Modules]]; END; SwapOutMakeImageCode: PROCEDURE = BEGIN OPEN FrameDefs; SwapOutCode[GlobalFrame[MakeImageOps.AddFileRequest]]; SwapOutCode[GlobalFrame[Table.Allocate]]; SwapOutCode[GlobalFrame[SymbolOps.FindString]]; SwapOutCode[GlobalFrame[BcdOps.ProcessModules]]; SwapOutCode[GlobalFrame[LoadStateOps.ReleaseLoadState]]; SwapOutCode[GlobalFrame[BcdMergeOps.MergeBcd]]; END; InvalidImageName: PUBLIC SIGNAL = CODE; ResidentGFI: CARDINAL = 1; GetImageFile: PROCEDURE [name: STRING] RETURNS [file: FileHandle] = BEGIN OPEN SegmentDefs; file ← NewFile[name, Read + Write + Append, DefaultVersion]; IF file = FrameOps.CodeHandle[GFT[ResidentGFI].frame].file THEN SIGNAL InvalidImageName; RETURN END; GetSegment: PROCEDURE [pages: CARDINAL] RETURNS [DataSegmentHandle] = BEGIN OPEN SegmentDefs; RETURN[MakeDataSegment[base: DefaultMDSBase, pages: pages, info: HardDown]]; END; AssureObjects: PROCEDURE = { OPEN SwapperOps, SegmentDefs; a: FileHandle; b: DataSegmentHandle; c: FileSegmentHandle; a ← LOOPHOLE[SwapperOps.AllocateObject[SIZE[file Object]]]; a↑ ← [,file[,,,,,,,,,,,]]; b ← LOOPHOLE[SwapperOps.AllocateObject[SIZE[data segment Object]]]; b↑ ← [,segment[,data[,]]]; c ← LOOPHOLE[SwapperOps.AllocateObject[SIZE[file segment Object]]]; c↑ ← [,segment[,file[,,,,,,,,]]]; SwapperOps.LiberateObject[a]; SwapperOps.LiberateObject[b]; SwapperOps.LiberateObject[c]}; InstallImage: PROCEDURE [name: STRING, merge: BOOLEAN] = BEGIN OPEN DiskDefs, AltoFileDefs; wdc: CARDINAL; diskrequest: DiskRequest; lpn: PageNumber; numChars: CARDINAL; savealloctrap, saveswaptrap: ControlLink; auxtrapFrame: FrameHandle; saveAllocationVector: AllocationVector; saveXferTrap, saveXferTrapStatus: UNSPECIFIED; nextpage: PageNumber; swappedinfilepages, swappedoutfilepages, datapages: PageCount ← 0; SwapOutErrorStrategy: AllocDefs.SwapStrategy ← AllocDefs.SwapStrategy[ link:, proc: SwapOutError]; mapindex: CARDINAL ← 0; maxFileSegPages: CARDINAL ← 0; endofdatamapindex: CARDINAL; HeaderSeg: DataSegmentHandle; Image: POINTER TO ImageFormat.ImageHeader; imageDA, HeaderDA: vDA; ImageFile: FileHandle; diskKD: FileSegmentHandle; saveDIW: WORD; savePV: ARRAY [0..15] OF UNSPECIFIED; saveReadyList: ProcessOps.Queue; savePriority: ProcessDefs.Priority; saveCurrentPSB: PSBDefs.ProcessHandle; saveCurrentState: ControlDefs.SVPointer; initstateseg: FileSegmentHandle ← LoadStateOps.initstate; stateseg: FileSegmentHandle ← LoadStateOps.state; net: CARDINAL ← MiscDefs.GetNetworkNumber[]; maxbcdsize: CARDINAL; creator: BcdDefs.VersionStamp ← ImageDefs.ImageVersion[]; mdsFreeList: DESCRIPTOR FOR ARRAY OF Region.NodeObject; SaveMDSFreeList: PROCEDURE = BEGIN OPEN SwapperOps; nNodes, i: CARDINAL; node: Region.Node; nNodes ← 0; FOR node ← mdsNodes.fwd, node.fwd UNTIL node = @mdsNodes DO nNodes ← nNodes + 1; ENDLOOP; IF nNodes = 0 THEN BEGIN mdsFreeList ← DESCRIPTOR[NIL, 0]; RETURN END; mdsFreeList ← DESCRIPTOR[auxalloc[nNodes*SIZE[Region.NodeObject]], nNodes]; i ← 0; FOR node ← mdsNodes.fwd, node.fwd UNTIL node = @mdsNodes DO mdsFreeList[i] ← node↑; i ← i + 1; ENDLOOP; END; RestoreMDSFreeList: PROCEDURE = BEGIN OPEN SwapperOps; i: CARDINAL ← 0; node: Region.Node; IF LENGTH[mdsFreeList] = 0 THEN RETURN; FOR i IN [0..LENGTH[mdsFreeList]) DO node ← AddressFromPage[mdsFreeList[i].base]; node↑ ← mdsFreeList[i]; ENDLOOP; END; SaveProcesses: PROCEDURE = BEGIN OPEN ProcessOps; saveDIW ← ProcessDefs.DIW↑; ProcessDefs.DIW↑ ← 0; savePV ← ProcessDefs.CV↑; WakeupsWaiting↑ ← 0; saveReadyList ← ReadyList↑; saveCurrentPSB ← CurrentPSB↑; savePriority ← CurrentPSB.priority; saveCurrentState ← CurrentState↑; END; RestoreProcesses: PROCEDURE = BEGIN OPEN ProcessDefs, ProcessOps; p: PSBDefs.ProcessHandle; ActiveWord↑ ← 77777B; ProcessDefs.DIW↑ ← saveDIW; ProcessDefs.CV↑ ← savePV; ReadyList↑ ← saveReadyList; CurrentPSB↑ ← saveCurrentPSB; CurrentPSB.priority ← LAST[Priority]; CurrentState↑ ← saveCurrentState; FOR p ← FirstProcess↑, p + SIZE[PSBDefs.PSB] UNTIL p = LastProcess↑ DO IF p.state = alive AND p.timeout # 0 AND p.waitingOnCV THEN BEGIN p.waitingOnCV ← FALSE; Requeue[from: NullQueueHandle, to: ReadyList, p: p]; END; ENDLOOP; SetPriority[savePriority]; RETURN END; EnterMapItem: PROCEDURE [vmpage: PageNumber, pages: PageCount] = BEGIN OPEN ImageFormat; map: POINTER TO ARRAY [0..0) OF normal MapItem = LOOPHOLE[@Image.map]; IF pages > 127 THEN SIGNAL SwapErrorDuringMakeImage; IF mapindex >= MapSpace THEN SIGNAL NoRoomInImageMap; map[mapindex] ← MapItem[vmpage, pages, normal[]]; mapindex ← mapindex + SIZE[normal MapItem]; END; CountFileSegments: PROCEDURE [s: FileSegmentHandle] RETURNS [BOOLEAN] = BEGIN IF s # diskKD THEN BEGIN [] ← SwapperOps.PositionSeg[s, FALSE]; IF s.swappedin THEN BEGIN swappedinfilepages ← swappedinfilepages + s.pages; IF s.class = code THEN maxFileSegPages ← MAX[maxFileSegPages, s.pages]; END ELSE BEGIN swappedoutfilepages ← swappedoutfilepages + s.pages; maxFileSegPages ← MAX[maxFileSegPages, s.pages]; END END; RETURN[FALSE]; END; CountDataSegments: PROCEDURE [s: DataSegmentHandle] RETURNS [BOOLEAN] = BEGIN IF s # HeaderSeg AND s # bufferseg THEN datapages ← datapages + s.pages; RETURN[FALSE]; END; MapDataSegments: PROCEDURE [s: DataSegmentHandle] RETURNS [BOOLEAN] = BEGIN IF s # HeaderSeg AND s # bufferseg THEN BEGIN EnterMapItem[s.VMpage, s.pages]; nextpage ← nextpage + s.pages; END; RETURN[FALSE]; END; WriteSwappedIn: PROCEDURE [s: FileSegmentHandle] RETURNS [BOOLEAN] = BEGIN IF s.swappedin THEN BEGIN imageDA ← TransferFileSegment[buffer, s, ImageFile, nextpage, imageDA]; EnterMapItem[s.VMpage, s.pages]; nextpage ← nextpage + s.pages; END; RETURN[FALSE]; END; WriteSwappedOutCode: PROCEDURE [s: FileSegmentHandle] RETURNS [BOOLEAN] = BEGIN IF ~s.swappedin AND s.class = code THEN BEGIN imageDA ← TransferFileSegment[buffer, s, ImageFile, nextpage, imageDA]; nextpage ← nextpage + s.pages; END; RETURN[FALSE]; END; WriteSwappedOutNonCode: PROCEDURE [s: FileSegmentHandle] RETURNS [BOOLEAN] = BEGIN IF ~s.swappedin AND s.class # code AND s # diskKD THEN BEGIN imageDA ← TransferFileSegment[buffer, s, ImageFile, nextpage, imageDA]; nextpage ← nextpage + s.pages; END; RETURN[FALSE]; END; SDDefs.SD[SDDefs.sAddFileRequest] ← AddFileRequest; ImageFile ← GetImageFile[name]; diskKD ← KDSegment[]; ProcessDefs.DisableInterrupts[]; wdc ← ProcessOps.ReadWDC[]; CoreSwapDefs.level ← -1; SaveProcesses[]; ImageDefs.UserCleanupProc[Save]; maxbcdsize ← ProcessBcds[initstateseg, merge]; [] ← Storage.Prune[]; SwapperOps.MoveCode[direction: intoMDS]; SwapperOps.DisableHyperspace[]; SetupAuxStorage[]; EnumerateNeededModules[LockCodeSegment]; HeaderDA ← DAofPage[ImageFile, 1]; -- [] ← FrameDefs.EnumerateGlobalFrames[SwapOutUnlockedCode]; -- [] ← EnumerateFileSegments[SwapOutUnlocked]; -- set up private frame allocation trap FrameOps.FlushLargeFrames[]; savealloctrap ← SDDefs.SD[SDDefs.sAllocTrap]; SDDefs.SD[SDDefs.sAllocTrap] ← auxtrapFrame ← auxtrap[]; saveAllocationVector ← AV↑; AV↑ ← LOOPHOLE[DataSegmentAddress[AuxSeg], POINTER TO AllocationVector]↑; BufferPages ← maxbcdsize + initstateseg.pages; bufferseg ← GetSegment[BufferPages]; HeaderSeg ← GetSegment[1]; datapages ← 0; AssureObjects[]; [] ← EnumerateDataSegments[CountDataSegments]; swappedinfilepages ← swappedoutfilepages ← 0; [] ← EnumerateFileSegments[CountFileSegments]; SetEndOfFile[ ImageFile, datapages + swappedinfilepages + swappedoutfilepages + ImageFormat.FirstImageDataPage - 1, AltoDefs.BytesPerPage]; [] ← DiskKDDefs.CloseDiskKD[]; Image ← DataSegmentAddress[HeaderSeg]; MiscDefs.Zero[Image, ImageFormat.HeaderPages*AltoDefs.PageSize]; Image.prefix.versionident ← ImageFormat.VersionID; --Image.prefix.options ← 0; --Image.prefix.state.stk[0] ← Image.prefix.state.stk[1] ← 0; Image.prefix.state.stkptr ← 2; Image.prefix.state.dest ← FrameOps.MyLocalFrame[]; Image.prefix.type ← makeimage; Image.prefix.diskAddresses ← Image; Image.prefix.leaderDA ← ImageFile.fp.leaderDA; Image.prefix.version ← BcdDefs.VersionStamp[ time: MiscDefs.CurrentTime[], net: net, host: OsStaticDefs.OsStatics.SerialNumber]; Image.prefix.creator ← creator; -- now disable swapping saveswaptrap ← SDDefs.SD[SDDefs.sSwapTrap]; SDDefs.SD[SDDefs.sSwapTrap] ← SwapTrapError; AllocDefs.AddSwapStrategy[@SwapOutErrorStrategy]; datapages ← 0; [] ← EnumerateDataSegments[CountDataSegments]; swappedinfilepages ← swappedoutfilepages ← 0; [] ← EnumerateFileSegments[CountFileSegments]; nextpage ← ImageFormat.FirstImageDataPage; [] ← SegmentDefs.EnumerateDataSegments[MapDataSegments]; IF nextpage # ImageFormat.FirstImageDataPage + datapages THEN ERROR; endofdatamapindex ← mapindex; imageDA ← DAofPage[ImageFile, nextpage]; buffer ← SegmentDefs.DataSegmentAddress[bufferseg]; [] ← SegmentDefs.EnumerateFileSegments[WriteSwappedIn]; IF nextpage # ImageFormat.FirstImageDataPage + datapages + swappedinfilepages THEN ERROR; [] ← SegmentDefs.EnumerateFileSegments[WriteSwappedOutCode]; [] ← SegmentDefs.EnumerateFileSegments[WriteSwappedOutNonCode]; SegmentDefs.DeleteDataSegment[bufferseg]; SegmentDefs.CloseFile[ImageFile ! SegmentDefs.FileError => RESUME ]; ImageFile.write ← ImageFile.append ← FALSE; InitLoadStates[stateseg]; Image.prefix.loadStateBase ← stateseg.base; Image.prefix.initialLoadStateBase ← initstateseg.base; Image.prefix.loadStatePages ← initstateseg.pages; diskrequest ← DiskRequest[ ca: auxalloc[datapages + 3], da: auxalloc[datapages + 3], fixedCA: FALSE, fp: auxalloc[SIZE[FP]], firstPage: ImageFormat.FirstImageDataPage - 1, lastPage: ImageFormat.FirstImageDataPage + datapages - 1, action: WriteD, lastAction: WriteD, signalCheckError: FALSE, option: update[BFSDefs.GetNextDA]]; diskrequest.fp↑ ← ImageFile.fp; [] ← SegmentDefs.EnumerateFileSegments[BashHint]; [] ← SegmentDefs.EnumerateFiles[BashFile]; (diskrequest.ca + 1)↑ ← Image; FillInCAs[Image, endofdatamapindex, diskrequest.ca + 2]; MiscDefs.SetBlock[diskrequest.da, fillinDA, datapages + 3]; (diskrequest.da + 1)↑ ← HeaderDA; SaveMDSFreeList[]; saveXferTrap ← SDDefs.SD[SDDefs.sXferTrap]; SDDefs.SD[SDDefs.sXferTrap] ← FrameOps.MyLocalFrame[]; saveXferTrapStatus ← TrapOps.ReadXTS[]; [lpn, numChars] ← BFSDefs.ActOnPages[LOOPHOLE[@diskrequest]]; IF lpn # 0 OR numChars # 0 THEN BEGIN AltoDisplay.DCBchainHead↑ ← SDDefs.SD[SDDefs.sGoingAway] ← NIL; ImageDefs.StopMesa[]; END; ProcessOps.WriteWDC[wdc]; AV↑ ← saveAllocationVector; SDDefs.SD[SDDefs.sAllocTrap] ← savealloctrap; SDDefs.SD[SDDefs.sXferTrap] ← saveXferTrap; TrapOps.WriteXTS[saveXferTrapStatus]; SDDefs.SD[SDDefs.sAddFileRequest] ← 0; FrameOps.Free[auxtrapFrame]; RestoreMDSFreeList[]; SwapperOps.InitMemoryConfig[]; BootImageFile[ImageFile, LOOPHOLE[Image]]; DiskDefs.sysDisk ← DiskDefs.StandardDisk; DiskKDDefs.InitializeDiskKD[]; BootPageTable[ImageFile, LOOPHOLE[Image]]; SegmentDefs.DeleteDataSegment[HeaderSeg]; -- turn swapping back on AllocDefs.RemoveSwapStrategy[@SwapOutErrorStrategy]; SDDefs.SD[SDDefs.sSwapTrap] ← saveswaptrap; SwapperOps.EnableHyperspace[]; CollectDiskAddresses[ImageFile]; RestoreProcesses[]; ProcessDefs.EnableInterrupts[]; ProcessFileRequests[]; InlineDefs.COPY[ from: SegmentDefs.FileSegmentAddress[initstateseg], to: SegmentDefs.FileSegmentAddress[stateseg], nwords: stateseg.pages*AltoDefs.PageSize]; LoadStateOps.ForceDirty[]; LoadStateOps.ReleaseLoadState[]; SegmentDefs.Unlock[initstateseg]; SegmentDefs.SwapOut[initstateseg]; SegmentDefs.DeleteDataSegment[AuxSeg]; FreeAllSpace[]; EnumerateNeededModules[UnlockCodeSegment]; SwapperOps.MoveCode[direction: outofMDS]; SwapOutMakeImageCode[]; ImageDefs.UserCleanupProc[Restore]; RETURN END; -- auxillary storage for frames and non-saved items AuxSeg: DataSegmentHandle; freepointer: POINTER; wordsleft: CARDINAL; StoragePages: CARDINAL = 10; SetupAuxStorage: PROCEDURE = BEGIN av: POINTER; i: CARDINAL; AuxSeg ← GetSegment[StoragePages]; av ← freepointer ← DataSegmentAddress[AuxSeg]; wordsleft ← StoragePages*AltoDefs.PageSize; [] ← auxalloc[AllocationVectorSize]; freepointer ← freepointer + 3; wordsleft ← wordsleft - 3; FOR i IN [0..LastAVSlot] DO (av + i)↑ ← (i + 1)*4 + 2; ENDLOOP; (av + 6)↑ ← (av + LargeReturnSlot)↑ ← (av + SpecialReturnSlot + 1)↑ ← 1; END; auxalloc: PROCEDURE [n: CARDINAL] RETURNS [p: POINTER] = BEGIN -- allocate in multiples of 4 words p ← freepointer; n ← InlineDefs.BITAND[n + 3, 177774B]; freepointer ← freepointer + n; IF wordsleft < n THEN ImageDefs.PuntMesa[]; wordsleft ← wordsleft - n; RETURN END; auxtrap: PROCEDURE RETURNS [myframe: FrameHandle] = BEGIN state: StateVector; newframe: FrameHandle; eventry: POINTER TO EntryVectorItem; fsize, findex: CARDINAL; newG: GlobalFrameHandle; dest, tempdest: ControlLink; alloc: BOOLEAN; gfi: GFTIndex; ep: CARDINAL; myframe ← LOOPHOLE[FrameOps.MyLocalFrame[]]; state.dest ← myframe.returnlink; state.source ← 0; state.instbyte ← 0; state.stk[0] ← myframe; state.stkptr ← 1; ProcessDefs.DisableInterrupts[]; DO ProcessDefs.EnableInterrupts[]; TRANSFER WITH state; ProcessDefs.DisableInterrupts[]; state ← STATE; dest ← TrapOps.ReadATP[]; myframe.returnlink ← state.source; tempdest ← dest; DO SELECT tempdest.tag FROM frame => BEGIN alloc ← TRUE; findex ← LOOPHOLE[tempdest, CARDINAL]/4; EXIT END; procedure => BEGIN OPEN proc: LOOPHOLE[tempdest, ControlDefs.ProcDesc]; gfi ← proc.gfi; ep ← proc.ep; [frame: newG, epbase: findex] ← GFT[gfi]; eventry ← @LOOPHOLE[newG.code.shortbase, PrefixHandle].entry[ findex + ep]; findex ← eventry.info.framesize; alloc ← FALSE; EXIT END; indirect => tempdest ← tempdest.link↑; ENDCASE => ImageDefs.PuntMesa[]; ENDLOOP; IF findex > LastAVSlot THEN ImageDefs.PuntMesa[]; fsize ← FrameVec[findex]; IF fsize MOD 4 # 0 THEN fsize ← fsize + 1; newframe ← LOOPHOLE[freepointer + 1]; freepointer↑ ← findex; freepointer ← freepointer + fsize; IF wordsleft < fsize THEN ImageDefs.PuntMesa[] ELSE wordsleft ← wordsleft - fsize; IF alloc THEN BEGIN state.dest ← myframe.returnlink; state.stk[state.stkptr] ← newframe; state.stkptr ← state.stkptr + 1; END ELSE BEGIN state.dest ← dest; newframe.accesslink ← LOOPHOLE[AV[findex].frame]; AV[findex].frame ← newframe; state.source ← myframe.returnlink; END; ENDLOOP; END; PageTable: TYPE = MACHINE DEPENDENT RECORD [ fp: AltoFileDefs.CFP, firstpage: CARDINAL, table: ARRAY [0..1) OF DiskDefs.DA]; BootImageFile: PROCEDURE [file: FileHandle, pt: POINTER TO PageTable] = BEGIN OPEN AltoFileDefs; DropFileRequest[file]; file.open ← TRUE; file.fp ← FP[serial: pt.fp.serial, leaderDA: pt.fp.leaderDA]; RETURN END; BootPageTable: PROCEDURE [file: FileHandle, pt: POINTER TO PageTable] = BEGIN OPEN AltoFileDefs; lastpage: PageNumber; pageInc: PageNumber = pt.firstpage - ImageFormat.FirstImageDataPage; PlugHint: PROCEDURE [seg: FileSegmentHandle] RETURNS [BOOLEAN] = BEGIN IF seg.file = file THEN BEGIN seg.base ← seg.base + pageInc; IF seg.base IN [pt.firstpage..lastpage] THEN WITH s: seg SELECT FROM disk => s.hint ← FileHint[ page: s.base, da: DiskDefs.VirtualDA[pt.table[s.base - pt.firstpage]]]; ENDCASE; END; RETURN[FALSE] END; FOR lastpage ← 0, lastpage + 1 UNTIL pt.table[lastpage] = DiskDefs.DA[ 0, 0, 0, 0, 0] DO NULL ENDLOOP; IF lastpage = 0 THEN RETURN; lastpage ← lastpage + pt.firstpage - 1; [] ← EnumerateFileSegments[PlugHint]; RETURN END; CollectDiskAddresses: PROCEDURE [imageFile: FileHandle] = BEGIN OPEN Storage, SegmentDefs, AltoFileDefs; DAs: DESCRIPTOR FOR ARRAY OF vDA; maxunknown, maxknown: CARDINAL ← FIRST[CARDINAL]; minunknown: CARDINAL ← LAST[CARDINAL]; maxknownDA: vDA; DisplayHead: POINTER TO WORD = LOOPHOLE[420B]; saveDisplay: WORD; diskrequest: DiskDefs.DiskRequest; bufseg, DAseg: DataSegmentHandle; FindEnds: PROCEDURE [seg: FileSegmentHandle] RETURNS [BOOLEAN] = BEGIN WITH s: seg SELECT FROM disk => IF s.file = imageFile AND s.hint.da = eofDA THEN BEGIN maxunknown ← MAX[maxunknown, s.base]; minunknown ← MIN[minunknown, s.base]; END; ENDCASE; RETURN[FALSE]; END; -- of FindEnds -- FindKnown: PROCEDURE [seg: FileSegmentHandle] RETURNS [BOOLEAN] = BEGIN WITH s: seg SELECT FROM disk => IF s.file = imageFile AND s.hint.da # eofDA AND s.base < minunknown AND s.base > maxknown THEN BEGIN maxknown ← s.base; maxknownDA ← s.hint.da END; ENDCASE; RETURN[FALSE]; END; -- of FindKnown -- PlugDA: PROCEDURE [seg: FileSegmentHandle] RETURNS [BOOLEAN] = BEGIN WITH s: seg SELECT FROM disk => IF s.file = imageFile AND s.hint.da = eofDA AND s.base IN (maxknown..maxunknown] THEN SegmentDefs.SetFileSegmentDA[@s, DAs[s.base]]; ENDCASE; RETURN[FALSE]; END; -- of PlugDA -- saveDisplay ← DisplayHead↑; DisplayHead↑ ← 0; [] ← EnumerateFileSegments[FindEnds]; [] ← EnumerateFileSegments[FindKnown]; bufseg ← MakeDataSegment[DefaultMDSBase, 1, EasyDown]; DAseg ← MakeDataSegment[ DefaultMDSBase, PagesForWords[maxunknown - maxknown + 3], EasyDown]; DAs ← DESCRIPTOR[DataSegmentAddress[DAseg] - (maxknown - 1), maxunknown + 2]; diskrequest ← DiskDefs.DiskRequest[ ca: DataSegmentAddress[bufseg], fixedCA: TRUE, da: @DAs[0], fp: @imageFile.fp, firstPage: maxknown, lastPage: maxunknown, action: ReadD, lastAction: ReadD, signalCheckError: FALSE, option: update[cleanup: BFSDefs.GetNextDA]]; MiscDefs.SetBlock[@DAs[maxknown - 1], fillinDA, maxunknown - maxknown + 3]; DAs[maxknown] ← maxknownDA; [] ← BFSDefs.ActOnPages[LOOPHOLE[@diskrequest]]; -- we know it is an Update diskrequest [] ← EnumerateFileSegments[PlugDA]; DeleteDataSegment[DAseg]; DeleteDataSegment[bufseg]; DisplayHead↑ ← saveDisplay; END; -- of CollectDiskAddresses -- -- The driver MakeImage: PUBLIC PROCEDURE [name: STRING, merge: BOOLEAN ← TRUE] = BEGIN s: StateVector; InitFileRequest[]; InitSpace[]; s.stk[0] ← FrameOps.MyGlobalFrame[]; s.stkptr ← 1; s.instbyte ← 0; s.dest ← FrameDefs.SwapOutCode; s.source ← FrameOps.GetReturnLink[]; InstallImage[name, merge]; RETURN WITH s; END; END..