-- File: Bootmesa.Mesa -- Last edited by Sandman; September 12, 1980 2:37 PM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY AltoDefs USING [Address, PageCount, PageNumber, PageSize], AltoFileDefs USING [eofDA, NullFP], BcdDefs USING [Base, FTSelf, MTIndex, VersionStamp], BcdOps USING [BcdBase, MTHandle, ProcessModules], CacheOps USING [Flush, Init, PageNumber, READ, WRITE], BootmesaOps, CommanderDefs USING [AddCommand, CommandBlockHandle], ControlDefs USING [ AV, ControlLink, FrameCodeBase, FrameVec, GFT, GFTIndex, GFTItem, GlobalFrameHandle, MainBodyIndex, LargeReturnSlot, LastAVSlot, NullFrame, NullGlobalFrame, SpecialReturnSlot, StateVector], InlineDefs USING [COPY], IODefs USING [WriteLine, WriteString], LoadStateFormat USING [LoadState], MiscDefs USING [GetNetworkNumber], OsStaticDefs USING [OsStatics], ProcessDefs USING [Priority], ProcessOps USING [FirstProcess, FirstStateVector, LastProcess], PSBDefs USING [PSB], SDDefs USING [SD, sGFTLength, sXferTrap], SegmentDefs USING [ AddressFromPage, CloseFile, DataSegmentHandle, DeleteFileSegment, EasyUp, FileHandle, FileSegmentAddress, FileSegmentHandle, MapFileSegment, NewFileSegment, OpenFile, PageFromAddress, Read, SwapIn, SwapUp, Unlock, Write], SegOps USING [ CodeClass, DefaultFile, InitSegMachinery, NewSeg, Seg, SwapInSeg, vmFile], String USING [AppendString], Time USING [Current]; Bootmesa: PROGRAM IMPORTS CacheOps, BootmesaOps, CommanderDefs, InlineDefs, IODefs, MiscDefs, SegmentDefs, String, Time, SegOps, BcdOps EXPORTS BootmesaOps SHARES ControlDefs, ProcessDefs = BEGIN OPEN AltoDefs, ControlDefs, BootmesaOps, SegOps; data: POINTER TO BootmesaOps.BootData ← @dataObject; FileHandle: TYPE = SegmentDefs.FileHandle; FileSegmentHandle: TYPE = SegmentDefs.FileSegmentHandle; DataSegmentHandle: TYPE = SegmentDefs.DataSegmentHandle; -- utility procedures BootAbort: PUBLIC SIGNAL = CODE; BootmesaError: PUBLIC PROCEDURE [msg: STRING] = BEGIN OPEN IODefs; WriteString["Bootmesa Error: "L]; WriteLine[msg]; SIGNAL BootAbort; END; -- Frame Allocation paramsperframe: CARDINAL = 1; framesloaded: CARDINAL ← 0; framebase: POINTER; FrameStackFull: ERROR = CODE; extraFramesDesired: BOOLEAN ← FALSE; frameweight: PACKED ARRAY [0..LastAVSlot] OF CARDINAL ← [9, 15, 10, 8, 7, 6, 5, 7, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; extraframes: ARRAY [0..LastAVSlot] OF CARDINAL; AllocGlobalFrame: PUBLIC PROCEDURE [ framesize, nlinks: CARDINAL, framelinks: BOOLEAN] RETURNS [frame: POINTER] = BEGIN framebase ← framebase - framesize; frame ← framebase ← framebase - LOOPHOLE[framebase, CARDINAL] MOD 4; IF framelinks THEN framebase ← framebase - nlinks; IF LOOPHOLE[framebase, CARDINAL] < CARDINAL[FirstVMPage*PageSize] THEN ERROR FrameStackFull; RETURN END; AllocFrame: PROCEDURE [findex: CARDINAL] RETURNS [frame: POINTER] = BEGIN framesloaded ← framesloaded + 1; frame ← framebase ← framebase - (FrameVec[findex] + 1); CacheOps.WRITE[frame - 1, findex]; RETURN END; AddFrame: PROCEDURE [findex: CARDINAL] = BEGIN OPEN CacheOps; p: POINTER = AllocFrame[findex]; WRITE[p, READ[AVbase + findex]]; WRITE[AVbase + findex, p]; END; AllocateExtraFrames: PROCEDURE = BEGIN i, j: CARDINAL; FOR i IN [0..LENGTH[extraframes]) DO FOR j IN [0..extraframes[i]) DO AddFrame[i]; ENDLOOP; ENDLOOP; END; DivideAllocationArea: PROCEDURE [base: Address, size: CARDINAL] = BEGIN OPEN CacheOps; p: Address ← base + 4; -- allow initial dead space i, j, s, c, sum: CARDINAL; fw: ARRAY [0..LENGTH[frameweight]) OF CARDINAL; FOR i IN [0..LENGTH[fw]) DO fw[i] ← frameweight[i] ENDLOOP; size ← size - 4; sum ← 0; FOR i IN [0..LENGTH[fw]) DO sum ← sum + FrameVec[i]*fw[i] ENDLOOP; c ← MAX[size/sum, 1]; WHILE size > FrameVec[0] DO FOR i IN [0..LENGTH[FrameVec]) DO s ← FrameVec[i]; IF s MOD 4 = 3 THEN s ← s + 1; FOR j IN [1..fw[i]*c] DO -- add to alloc vector IF size < s THEN EXIT; WRITE[p - 1, i]; -- hidden link word WRITE[p, READ[AVbase + i]]; WRITE[AVbase + i, p]; p ← p + s; size ← size - s; ENDLOOP; ENDLOOP; FOR i IN [0..LENGTH[fw] - 1) DO fw[i] ← MAX[fw[i]/3, 1] ENDLOOP; c ← 1; ENDLOOP; RETURN END; SetResidentFramePages: PUBLIC PROCEDURE [n: CARDINAL] = BEGIN IF residentFramePages = 0 THEN residentFramePages ← n END; ResidentFramePages: PROCEDURE [n: CARDINAL] = BEGIN residentFramePages ← n END; residentFramePages: CARDINAL ← 0; FramePages: PageCount; -- initialization AVbase, GFTbase, SDbase, SVbase: POINTER ← NIL; DefaultFirstVMPage: PageNumber ← 2; DefaultLastVMPage: PageNumber ← 370B; FirstVMPage: PageNumber ← 0; LastVMPage: PageNumber ← 0; GetMemoryLimits: PUBLIC PROCEDURE RETURNS [fp, lp: PageNumber] = BEGIN RETURN[FirstVMPage, LastVMPage] END; SetMemoryLimits: PROCEDURE [fp, lp: PageNumber] = BEGIN FirstVMPage ← fp; LastVMPage ← lp; END; SetDefaultMemoryLimits: PUBLIC PROCEDURE [fp, lp: PageNumber] = BEGIN DefaultFirstVMPage ← fp; DefaultLastVMPage ← lp; END; StateVectors: CARDINAL = (LAST[ProcessDefs.Priority] + 1)*SIZE[ControlDefs.StateVector]; DefaultNProcesses: PUBLIC CARDINAL ← (AltoDefs.PageSize - StateVectors)/SIZE[PSBDefs.PSB]; nProcesses: CARDINAL ← 0; SetNumberProcesses: PROCEDURE [n: CARDINAL] = BEGIN nProcesses ← n; END; SetDefaultNProcesses: PUBLIC PROCEDURE [n: CARDINAL] = BEGIN DefaultNProcesses ← n; END; DefaultGFTLength: CARDINAL ← 256; GFTLength: CARDINAL ← 0; SetGFTLength: PROCEDURE [l: CARDINAL] = BEGIN GFTLength ← l; END; SetDefaultGFTLength: PUBLIC PROCEDURE [l: CARDINAL] = BEGIN DefaultGFTLength ← l; END; AssignDefaults: PROCEDURE = BEGIN IF FirstVMPage = 0 THEN FirstVMPage ← DefaultFirstVMPage; IF LastVMPage = 0 THEN LastVMPage ← DefaultLastVMPage; IF GFTLength = 0 THEN GFTLength ← DefaultGFTLength; IF nProcesses = 0 THEN nProcesses ← DefaultNProcesses; AVbase ← ControlDefs.AV; SDbase ← SDDefs.SD; GFTbase ← ControlDefs.GFT; RETURN END; InitializeVM: PROCEDURE [framep: PageCount] = BEGIN OPEN SegmentDefs, CacheOps, SegOps; s: Seg; i, GFTpages, SVpages: CARDINAL; fp: PageNumber; AssignDefaults[]; fp ← FirstVMPage; FramePages ← framep; InitSegMachinery[FirstVMPage, LastVMPage]; CacheOps.Init["BootMesa.Scratch", FirstVMPage, LastVMPage]; framebase ← LOOPHOLE[(LastVMPage + 1)*PageSize]; -- av and sd s ← NewSeg[DefaultFile, PageFromAddress[AVbase], 1, TRUE]; SegOps.vmFile ← s.realFile; FOR i IN [0..PageSize) DO WRITE[AVbase + i, 0] ENDLOOP; FOR i IN [0..18) DO WRITE[AVbase + i, 4*(i + 1) + 2] ENDLOOP; WRITE[AVbase + 11, 1]; FOR i IN [18..LastAVSlot] DO WRITE[AVbase + i, 1] ENDLOOP; WRITE[AVbase + LargeReturnSlot, 1]; WRITE[AVbase + SpecialReturnSlot, 1]; --gft GFTpages ← (GFTLength*SIZE[GFTItem] + (PageSize - 1))/PageSize; s ← NewSeg[DefaultFile, PageFromAddress[GFTbase], GFTpages, TRUE]; FOR i IN [0..GFTLength*SIZE[GFTItem]) DO WRITE[GFTbase + i, 0] ENDLOOP; InitializeGFT[GFTbase, GFTLength]; WRITE[SDbase + SDDefs.sGFTLength, GFTLength]; -- process storage initialization SVpages ← (nProcesses*SIZE[PSBDefs.PSB] + StateVectors + (PageSize - 1))/PageSize; s ← NewSeg[DefaultFile, PageFromAddress[GFTbase] + GFTpages, SVpages, TRUE]; SVbase ← SegmentDefs.AddressFromPage[s.vmPage]; WRITE[ProcessOps.FirstStateVector, SVbase]; WRITE[ProcessOps.FirstProcess, SVbase + StateVectors]; WRITE[ ProcessOps.LastProcess, SVbase + StateVectors + (nProcesses - 1)*SIZE[PSBDefs.PSB]]; FOR i IN [0..SVpages*AltoDefs.PageSize) DO WRITE[SVbase + i, 0] ENDLOOP; RETURN END; InitializeHeap: PUBLIC PROCEDURE = BEGIN stackbase: PageNumber; stackpages: PageCount; frameseg: Seg; frames: POINTER; stackbase ← LOOPHOLE[framebase, CARDINAL]/PageSize; stackpages ← LastVMPage - stackbase + 1; frameseg ← NewSeg[ DefaultFile, stackbase - FramePages, FramePages + stackpages, TRUE]; frames ← SegmentDefs.AddressFromPage[frameseg.vmPage]; DivideAllocationArea[LOOPHOLE[frames], framebase - frames]; RETURN END; imageStamp: BcdDefs.VersionStamp; InitializeBootmesa: PUBLIC PROCEDURE [root: STRING] RETURNS [BcdDefs.VersionStamp] = BEGIN SetResidentFramePages[10]; InitializeVM[residentFramePages]; InitializeBootScript[]; data.imageFileRoot.length ← 0; String.AppendString[data.imageFileRoot, root]; BootmesaOps.OpenLoadmap[root]; imageStamp ← [net: MiscDefs.GetNetworkNumber[], host: OsStaticDefs.OsStatics.SerialNumber, time: LOOPHOLE[Time.Current[]]]; RETURN[imageStamp] END; AdjustBcd: PUBLIC PROCEDURE [fs: Seg] = BEGIN OPEN SegmentDefs; sgb: BcdDefs.Base; bcd: BcdOps.BcdBase; bseg: FileSegmentHandle ← fs.link2; AdjustCodeSegment: PROCEDURE [mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS [BOOLEAN] = BEGIN frame: GlobalFrameHandle ← data.moduleTable[mth.gfi].frame; sgb[mth.code.sgi].file ← BcdDefs.FTSelf; sgb[mth.code.sgi].base ← data.moduleTable[mth.gfi].code.imageBase; RETURN[FALSE]; END; bcd ← FileSegmentAddress[bseg]; sgb ← LOOPHOLE[bcd + bcd.sgOffset]; [] ← BcdOps.ProcessModules[bcd, AdjustCodeSegment]; MapFileSegment[bseg, fs.realFile, fs.imageBase]; RETURN END; InitializeLoadState: PUBLIC PROCEDURE = BEGIN OPEN SegmentDefs; gft: POINTER TO ARRAY [0..0) OF GFTItem = GFTbase; ls: Seg = lsseg; initls: Seg = initlsseg; bcdseg: Seg = fakebcdseg; iseg: FileSegmentHandle ← NewFileSegment[ initls.realFile, initls.imageBase, initls.pages, Read + Write]; seg: FileSegmentHandle ← NewFileSegment[ ls.realFile, ls.imageBase, ls.pages, Read + Write]; bseg: FileSegmentHandle ← bcdseg.link2; loadstate: LoadStateFormat.LoadState; SwapIn[seg]; loadstate ← FileSegmentAddress[seg]; loadstate.bcds[0] ← [exports: data.bcd.nExports # 0, typeExported: data.bcd.typeExported, pages: bcdseg.pages, body: alto[ da: AltoFileDefs.eofDA, base: bcdseg.imageBase, fp: AltoFileDefs.NullFP]]; SwapIn[iseg]; InlineDefs.COPY[ to: FileSegmentAddress[iseg], from: loadstate, nwords: AltoDefs.PageSize*seg.pages]; Unlock[iseg]; DeleteFileSegment[iseg]; Unlock[seg]; DeleteFileSegment[seg]; data.image.prefix.loadStateBase ← ls.imageBase; data.image.prefix.initialLoadStateBase ← initls.imageBase; data.image.prefix.loadStatePages ← ls.pages; data.header.loadState ← ls.index; data.header.initLoadState ← initls.index; data.header.bcd ← bcdseg.index; END; MapCode: PROCEDURE [class: SegOps.CodeClass] = BEGIN i: CARDINAL; fs: Seg; frame: GlobalFrameHandle; mt: DESCRIPTOR FOR ARRAY OF ModuleInfo ← data.moduleTable; mth: BcdOps.MTHandle; FOR i IN [1..LENGTH[mt]) DO IF mt[i].class # class OR mt[i].whenLoaded = notLoaded THEN LOOP; [frame: frame, code: fs, mth: mth] ← mt[i]; IF mth.gfi # i THEN LOOP; IF ~fs.in THEN SwapInSeg[fs]; fs.resident ← class = resident; ENDLOOP; RETURN END; MapResidentCode: PUBLIC PROCEDURE = BEGIN MapCode[resident]; RETURN END; MapSwappedInCode: PUBLIC PROCEDURE = BEGIN MapCode[in]; RETURN END; swapInBcd: BOOLEAN ← TRUE; NoSwapBcd: PROCEDURE = BEGIN swapInBcd ← FALSE END; MapLoadStates: PUBLIC PROCEDURE = BEGIN SwapInSeg[initlsseg]; SwapInSeg[lsseg]; IF swapInBcd THEN SwapInSeg[fakebcdseg]; RETURN END; TurnOffStartTrap: PUBLIC PROCEDURE = BEGIN Mesa: PROCEDURE [gfi: ControlDefs.GFTIndex] RETURNS [BOOLEAN] = BEGIN f: ControlDefs.GlobalFrameHandle; fs: Seg; mth: BcdOps.MTHandle; fcb: ControlDefs.FrameCodeBase; [frame: f, code: fs, mth: mth] ← data.moduleTable[gfi]; fcb.shortbase ← SegmentDefs.AddressFromPage[fs.vmPage] + mth.code.offset; fcb.out ← FALSE; CacheOps.WRITE[@f.code.shortbase, fcb.shortbase]; RETURN[FALSE]; END; [] ← EnumerateNoTrapModules[Mesa]; RETURN END; XFER: PUBLIC PROCEDURE [dest: GlobalFrameHandle] = BEGIN data.image.prefix.state.stk[0] ← FinishBootScript[ ControlDefs.NullGlobalFrame]; data.image.prefix.state.stkptr ← 1; data.image.prefix.state.dest ← SetupMainBodyProc[dest]; data.image.prefix.state.source ← ControlDefs.NullFrame; data.image.prefix.version ← LOOPHOLE[imageStamp]; BootmesaOps.CloseLoadmap[]; [] ← CacheOps.Flush[0, SegmentDefs.EasyUp, NIL]; SegmentDefs.SwapUp[data.headerSeg]; CleanupImageFile[]; RETURN END; SetupMainBodyProc: PROCEDURE [dest: GlobalFrameHandle] RETURNS [proc: ControlLink] = BEGIN OPEN CacheOps; fw: FirstFrameWord ← READ[dest]; proc ← [procedure[gfi: fw.gfi, ep: MainBodyIndex, tag: procedure]]; WRITE[SDbase + SDDefs.sXferTrap, proc]; fw.started ← TRUE; WRITE[dest, fw]; RETURN END; CleanupImageFile: PROCEDURE = BEGIN OPEN SegmentDefs; file: FileHandle = data.imageFile; swapCount: CARDINAL = file.swapcount; file.swapcount ← 0; CloseFile[file]; OpenFile[file]; file.swapcount ← swapCount; RETURN END; BEGIN OPEN CommanderDefs; command: CommandBlockHandle; command ← AddCommand["GFTLength", LOOPHOLE[SetGFTLength], 1]; command.params[0] ← [type: numeric, prompt: "GFTLength"]; command ← AddCommand["NumberProcesses", LOOPHOLE[SetNumberProcesses], 1]; command.params[0] ← [type: numeric, prompt: "NumberProcesses"]; command ← AddCommand["ResidentFramePages", LOOPHOLE[ResidentFramePages], 1]; command.params[0] ← [type: numeric, prompt: "ResidentFramePages"]; command ← AddCommand["SetMemoryBounds", LOOPHOLE[SetMemoryLimits], 2]; command.params[0] ← [type: numeric, prompt: "FirstVMPage"]; command.params[1] ← [type: numeric, prompt: "LastVMPage"]; [] ← AddCommand["NoSwapBcd", LOOPHOLE[NoSwapBcd], 0]; END; END..