-- 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..