-- LoaderImpl.Mesa, last edit January 6, 1983 2:19 pm -- Mesa 7.0/ Pilot 6.0 -- procedures to load and start modules in a Model -- this modeller loader is separate from the modelloer -- so that it can maintain its own load state tru successive modellers -- interfaceseqs and loadinfoseqs and dummymapseqs are all allocated here -- can't use PilotLoaderOps since it is not exported by CoPilotDorado.Config -- may use PilotLoadStateOps, however -- links: -- IF gfi > firstdummy, then gfi is index into Import table -- and ep is index into the export record pared with that import -- binding is simply to copy control link in the export record -- into this link -- IF gfi < firstdummy, then gfi in this link is an index into the config's -- moduletable. Do not alter the ep DIRECTORY BcdDefs: TYPE USING [Base, CTIndex, CTNull, EVIndex, FTIndex, FTSelf, GFTIndex, Link, MTIndex, NameRecord, NullLink, SGIndex, SpaceID, SPIndex, SPRecord, UnboundLink, VarLimit, VersionID], BcdOps: TYPE USING [BcdBase, CTHandle, EXPHandle, FTHandle, MTHandle, NameString, ProcessConfigs, ProcessModules, ProcessSegs, SGHandle, SPHandle], CWF: TYPE USING [FWF2, FWF4], Directory: TYPE USING [UpdateDates], Environment: TYPE USING [PageCount, PageNumber, wordsPerPage], File: TYPE USING [Capability, LimitPermissions, PageCount, PageNumber, read, write], Frame: TYPE USING [GetReturnLink], Heap: TYPE USING [FreeMDSNode, MakeMDSNode, systemMDSZone], Inline: TYPE USING [BITAND], IO: TYPE USING[Handle, PutChar], LowLoader: TYPE USING [DummyMapSeq, DummyMapSeqRecord, ImpExpSeq, ImpExpSeqRecord, InterfaceSeq, InterfaceSeqRecord, LoadInfoSeq, LoadInfoSeqRecord, ReplaceResult], Mopcodes: TYPE USING [zALLOC], PrincOps: TYPE USING [ControlLink, ControlModule, Frame, GFTIndex, GlobalFrameHandle, NullControl, NullLink, StateVector, UnboundLink], PrincOpsRuntime: TYPE USING [GetFrame, GFT], RTOS: TYPE USING [CheckForModuleReplacement], Runtime: TYPE USING [IsBound, ValidateGlobalFrame], RuntimeInternal: TYPE USING [Codebase, EnterGlobalFrame, MakeFsi], SDDefs: TYPE USING [SD, sStart, sSwapTrap], Space: TYPE USING [Create, defaultBase, Delete, Error, GetHandle, GetWindow, Handle, LongPointer, MakeReadOnly, MakeWritable, Map, nullHandle, PageCount, PageFromLongPointer, virtualMemory, WindowOrigin], SpecialSpace: TYPE USING [CreateForCode, MakeResident], Subr: TYPE USING [CopyString, FindMappedSpace, FreeString, LongZone], TimeStamp: TYPE USING [Stamp], Trap: TYPE USING [ReadOTP]; LoaderImpl: MONITOR IMPORTS BcdOps, CWF, Directory, File, Frame, Heap, Inline, IO, PrincOpsRuntime, RTOS, Runtime, RuntimeInternal, Space, SpecialSpace, Subr, Trap EXPORTS LowLoader SHARES File = { RTCallable: BOOL = TRUE; -- MDS Usage! waitCodeTrapCV: CONDITION; -- link space data links: LONG POINTER TO ARRAY[0 .. 0) OF PrincOps.ControlLink ← NIL; writeable: BOOL ← FALSE; long: BOOL ← FALSE; -- end of MDS usage SGItem: TYPE = RECORD [sgh: BcdOps.SGHandle, space: Space.Handle]; SGList: TYPE = DESCRIPTOR FOR ARRAY CARDINAL [0..0) OF SGItem; LoadBcdAndCount: PUBLIC PROC[cap: File.Capability, bcdsfn: LONG STRING, oldnwords: CARDINAL] RETURNS[loadinfoseq: LowLoader.LoadInfoSeq, newnwords, nbcdheaderpages, ncodepages: CARDINAL] = { bcdbase: BcdOps.BcdBase; ForEachModule: PROC[mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS[stop: BOOL] = { usecodelinks: BOOL ← mth.linkLoc = code; stop ← FALSE; IF usecodelinks THEN ncodepages ← ncodepages + (LinkSegmentLength[mth, bcdbase] /Environment.wordsPerPage)+1 ELSE -- use frame links newnwords ← newnwords + LinkSegmentLength[mth, bcdbase]; newnwords ← NextMultipleOfFour[newnwords]; newnwords ← newnwords + mth.framesize; }; CountSegments: PROC[sgh: BcdOps.SGHandle, sgi: BcdDefs.SGIndex] RETURNS[stop: BOOL] = { stop ← FALSE; IF sgh.class ~= code THEN RETURN; ncodepages ← ncodepages + sgh.pages; }; ncodepages ← 0; newnwords ← oldnwords; [bcdbase, nbcdheaderpages] ← LoadUpBcd[cap, 1]; loadinfoseq ← AllocateLoadInfoSeq[bcdbase]; loadinfoseq.bcdbase ← bcdbase; loadinfoseq.size ← 0; [] ← BcdOps.ProcessModules[bcdbase, ForEachModule]; [] ← BcdOps.ProcessSegs[bcdbase, CountSegments]; }; LoadFrame: PUBLIC PROC[loadinfoseq: LowLoader.LoadInfoSeq, oldframeptr: POINTER, window: IO.Handle, cap: File.Capability, beginning, ending: LONG CARDINAL, oldConfigGfi: PrincOps.GFTIndex] RETURNS[newframeptr: POINTER, newConfigGfi: PrincOps.GFTIndex] = { mod: CARDINAL ← 0; dummymapseq: LowLoader.DummyMapSeq; bcdbase: BcdOps.BcdBase; ncodepages: CARDINAL; WFPut: PROC[ch: CHAR] = { window.PutChar[ch]; }; ForEachModule: PROC[mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS[stop: BOOL] = { optr: POINTER; diff: CARDINAL; usecodelinks: BOOL ← mth.linkLoc = code; mname: STRING ← [100]; frame: PrincOps.GlobalFrameHandle; gfi: CARDINAL; n: CARDINAL; stop ← FALSE; IF LOOPHOLE[LONG[newframeptr], LONG CARDINAL] < beginning THEN ERROR; optr ← newframeptr; IF NOT usecodelinks THEN newframeptr ← newframeptr + LinkSegmentLength[mth, bcdbase]; newframeptr ← NextMultipleOfFour[newframeptr]; frame ← newframeptr; newframeptr ← newframeptr + mth.framesize; IF LOOPHOLE[LONG[newframeptr], LONG CARDINAL] > ending THEN ERROR; -- frame is zeroed when space is created gfi ← RuntimeInternal.EnterGlobalFrame[frame, mth.ngfi]; frame↑ ← [gfi: gfi, copied: FALSE, alloced: FALSE, started: FALSE, shared: FALSE, trapxfers: FALSE, codelinks: usecodelinks, global:, code:]; loadinfoseq[mod] ← [frame, mth.framesize, mth.ngfi]; newConfigGfi ← newConfigGfi + mth.ngfi; -- now store in cgfi to rgfi map FOR i: CARDINAL IN [0 .. mth.ngfi) DO dummymapseq[mth.gfi + i] ← [ind: gfi, whichone: i]; ENDLOOP; dummymapseq.size ← dummymapseq.size + mth.ngfi; mod ← mod + 1; CopyNStoLS[mname, bcdbase, mth.name]; n ← mth.framesize; CWF.FWF4[WFPut, "%s: gfi = %bB, gfh = %bB, framesize = %u, "L, mname, @gfi, @frame, @n]; n ← LinkSegmentLength[mth, bcdbase]; CWF.FWF2[WFPut, "#%slinks = %u\n"L, IF frame.codelinks THEN "code"L ELSE "frame"L, @n]; diff ← newframeptr - optr; -- CWF.FWF3[WFPut, "Old = %bB, new = %bB, diff = %u.\n"L, @optr, @newframeptr, @diff]; }; cap ← Directory.UpdateDates[cap, File.read]; newframeptr ← oldframeptr; newConfigGfi ← oldConfigGfi; loadinfoseq.configGfi ← newConfigGfi; bcdbase ← loadinfoseq.bcdbase; dummymapseq ← loadinfoseq.dummymapseq; dummymapseq[0] ← [0, 0]; dummymapseq.size ← 1; -- dummy module indices start at 1, not 0 [] ← BcdOps.ProcessModules[bcdbase, ForEachModule]; ncodepages ← FindAndMapInCode[bcdbase, 1, cap, loadinfoseq]; -- CWF.FWF1[WFPut, "%u code pages.\n"L, @ncodepages]; SetLinksToNull[bcdbase, loadinfoseq]; loadinfoseq.cm ← AssignControlModules[bcdbase, loadinfoseq]; loadinfoseq.size ← mod; }; WaitForBroadcast: ENTRY PROC[frame: PrincOps.GlobalFrameHandle] = { WHILE frame.code.out DO WAIT waitCodeTrapCV; ENDLOOP; }; -- can only be called for modules (not configs) LoadIncremental: PUBLIC ENTRY PROC[bcdcap: File.Capability, loadinfoseq: LowLoader.LoadInfoSeq, window: IO.Handle] RETURNS[replaceResult: LowLoader.ReplaceResult] = { savemodellercode: PROC ← NIL; codetrapframe: PrincOps.GlobalFrameHandle ← NIL; { ENABLE UNWIND => IF savemodellercode ~= NIL THEN SDDefs.SD[SDDefs.sSwapTrap] ← savemodellercode; WFPut: PROC[ch: CHAR] = { window.PutChar[ch]; }; ModellerCodeTrap: PROC = { start: PROC[PrincOps.ControlModule]; dest: PrincOps.ControlLink; state: PrincOps.StateVector; frame: PrincOps.GlobalFrameHandle; state ← STATE; dest ← Trap.ReadOTP[]; state.dest ← Frame.GetReturnLink[]; DO IF dest.proc THEN { frame ← PrincOpsRuntime.GetFrame[PrincOpsRuntime.GFT[dest.gfi]]; EXIT} ELSE IF dest.indirect THEN dest ← dest.link↑ ELSE {frame ← dest.frame.accesslink; EXIT}; -- frame ENDLOOP; IF frame = codetrapframe THEN { -- this halts outside process until my procedure is finished WaitForBroadcast[frame]; RETURN; }; IF ~frame.started THEN { start ← LOOPHOLE[SDDefs.SD[SDDefs.sStart]]; start[[frame[frame]]]; }; frame.code.out ← FALSE; RETURN WITH state }; n: CARDINAL; mname: STRING ← [100]; gfi: CARDINAL; bcdbase: BcdOps.BcdBase; mth: BcdOps.MTHandle; frame: PrincOps.GlobalFrameHandle ← loadinfoseq[0].frame; replaceResult ← ok; IF loadinfoseq.size ~= 1 THEN RETURN[configNotReplaceable]; [bcdbase] ← LoadUpBcd[bcdcap, 1]; loadinfoseq.bcdbase ← bcdbase; loadinfoseq.cm ← LOOPHOLE[frame]; -- recompute these since bcdbase.firstdummy, bcdbase.nDummies, and bcdbase.nImports -- may have changed ReSizeMaps[loadinfoseq]; mth ← @LOOPHOLE[bcdbase + bcdbase.mtOffset, BcdDefs.Base][FIRST[BcdDefs.MTIndex]]; -- checking IF LOOPHOLE[frame + mth.framesize, CARDINAL] > LOOPHOLE[NextMultipleOfFour[frame + loadinfoseq[0].framesize], CARDINAL] THEN RETURN[frameTooBig]; IF mth.ngfi > loadinfoseq[0].ngfi THEN RETURN[ngfiTooBig]; -- now think of monitor: -- set lock by setting code trap, then call check procedure -- then do replacement, then release lock -- this is to avoid the case where some local frames -- are created after the call on RTOS.CheckForModuleReplacemeent -- but before I swap the code codetrapframe ← frame; savemodellercode ← SDDefs.SD[SDDefs.sSwapTrap]; SDDefs.SD[SDDefs.sSwapTrap] ← ModellerCodeTrap; frame.code.out ← TRUE; -- force code trap IF RTCallable AND Runtime.IsBound[RTOS.CheckForModuleReplacement] AND NOT RTOS.CheckForModuleReplacement[frame] THEN { SDDefs.SD[SDDefs.sSwapTrap] ← savemodellercode; RETURN[checkForMRFailed]; }; [] ← FindAndMapInCode[bcdbase, 1, bcdcap, loadinfoseq]; -- havinge set the code base, we can now release the lock frame.code.out ← FALSE; BROADCAST waitCodeTrapCV; SDDefs.SD[SDDefs.sSwapTrap] ← savemodellercode; savemodellercode ← NIL; SetLinksToNull[bcdbase, loadinfoseq]; CopyNStoLS[mname, bcdbase, mth.name]; n ← mth.framesize; gfi ← frame.gfi; CWF.FWF4[WFPut, "%s: gfi = %bB, gfh = %bB, framesize = %u, "L, mname, @gfi, @frame, @n]; n ← LinkSegmentLength[mth, bcdbase]; CWF.FWF2[WFPut, "#%slinks = %u\n"L, IF frame.codelinks THEN "code"L ELSE "frame"L, @n]; RETURN[ok]; }}; -- old contents are preserved ReSizeMaps: PROC[loadinfoseq: LowLoader.LoadInfoSeq] = { longzone: UNCOUNTED ZONE ← Subr.LongZone[]; olddummymapseq: LowLoader.DummyMapSeq ← loadinfoseq.dummymapseq; oldimpexpseq: LowLoader.ImpExpSeq ← loadinfoseq.impexpseq; minSize: CARDINAL; loadinfoseq.dummymapseq ← longzone.NEW[LowLoader.DummyMapSeqRecord[ loadinfoseq.bcdbase.firstdummy +loadinfoseq.bcdbase.nDummies]]; loadinfoseq.impexpseq ← longzone.NEW[ LowLoader.ImpExpSeqRecord[loadinfoseq.bcdbase.nImports]]; minSize ← MIN[olddummymapseq.size, loadinfoseq.dummymapseq.maxsize]; FOR i: CARDINAL IN [0 .. minSize) DO loadinfoseq.dummymapseq[i] ← olddummymapseq[i]; ENDLOOP; loadinfoseq.dummymapseq.size ← minSize; minSize ← MIN[oldimpexpseq.size, loadinfoseq.impexpseq.maxsize]; FOR i: CARDINAL IN [0 .. minSize) DO loadinfoseq.impexpseq[i] ← oldimpexpseq[i]; ENDLOOP; loadinfoseq.impexpseq.size ← minSize; longzone.FREE[@olddummymapseq]; longzone.FREE[@oldimpexpseq]; }; SetLinksToNull: PROC[bcdbase: BcdOps.BcdBase, loadinfoseq: LowLoader.LoadInfoSeq] = { ForEachModule: PROC[mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS[stop: BOOL] = { -- set all the links to null frame: PrincOps.GlobalFrameHandle; stop ← FALSE; frame ← PrincOpsRuntime.GetFrame[PrincOpsRuntime.GFT[ loadinfoseq.dummymapseq[mth.gfi].ind]]; Runtime.ValidateGlobalFrame[frame]; [] ← OpenLinkSpace[frame, mth, bcdbase]; FOR i: CARDINAL IN [0..LinkSegmentLength[mth, bcdbase]) DO WriteLink[ offset: i, link: SELECT IthLink[mth, i, bcdbase].vtag FROM var, type => PrincOps.NullLink, ENDCASE => PrincOps.UnboundLink]; ENDLOOP; CloseLinkSpace[frame]; }; [] ← BcdOps.ProcessModules[bcdbase, ForEachModule]; loadinfoseq.linksresolved ← FALSE; }; BuildInterface: PUBLIC PROC[loadinfoseq: LowLoader.LoadInfoSeq, eth: BcdOps.EXPHandle] RETURNS[interfaceseq: LowLoader.InterfaceSeq] = { clink: PrincOps.ControlLink; cgfi: PrincOps.GFTIndex; -- dummy bcdbase: BcdOps.BcdBase; intname: STRING ← [100]; fth: BcdOps.FTHandle; IF eth.size = 0 THEN RETURN[NIL]; bcdbase ← loadinfoseq.bcdbase; CopyNStoLS[intname, bcdbase, eth.name]; interfaceseq ← AllocateInterfaceSeq[intname, eth.size]; FOR i: CARDINAL IN [0 .. eth.size) DO IF eth.links[i].vtag = var THEN { [clink] ← FindVariableLink[eth.links[i], loadinfoseq, NIL, NIL]; interfaceseq[i] ← [clink: clink, blink: BcdDefs.NullLink] } ELSE { realgfi: PrincOps.GFTIndex; realgfi ← loadinfoseq.dummymapseq[eth.links[i].gfi].ind; [clink, cgfi] ← ConvertDummyLinkToControlLink[eth.links[i], realgfi, bcdbase, loadinfoseq]; interfaceseq[i] ← [clink: clink, blink: [procedure[gfi: cgfi, ep: eth.links[i].ep, tag: eth.links[i].tag]]]; }; ENDLOOP; interfaceseq.size ← eth.size; fth ← @LOOPHOLE[bcdbase + bcdbase.ftOffset, BcdDefs.Base][eth.file]; interfaceseq.versstamp ← fth.version; }; -- can't be used for configs BuildFramePtrInterface: PUBLIC PROC[bcdbase: BcdOps.BcdBase, frame: PrincOps.GlobalFrameHandle] RETURNS[interfaceseq: LowLoader.InterfaceSeq] = { intname: STRING ← [100]; mth: BcdOps.MTHandle; IF bcdbase.nModules ~= 1 THEN ERROR; mth ← @LOOPHOLE[bcdbase + bcdbase.mtOffset, BcdDefs.Base][FIRST[BcdDefs.MTIndex]]; CopyNStoLS[intname, bcdbase, mth.name]; interfaceseq ← AllocateInterfaceSeq[intname, 1]; IF mth.file = BcdDefs.FTSelf THEN interfaceseq.versstamp ← bcdbase.version ELSE { fth: BcdOps.FTHandle; fth ← @LOOPHOLE[bcdbase + bcdbase.ftOffset, BcdDefs.Base][mth.file]; interfaceseq.versstamp ← fth.version; }; interfaceseq[0] ← [clink: LOOPHOLE[frame], blink: BcdDefs.NullLink]; interfaceseq.size ← 1; }; -- used by both BuildInterface and the loadstate FindVariableLink: PUBLIC PROC[blink: BcdDefs.Link, loadinfoseq: LowLoader.LoadInfoSeq, frame: PrincOps.GlobalFrameHandle, bcdbase: BcdOps.BcdBase] RETURNS[clink: PrincOps.ControlLink] = { trueep: CARDINAL; evi: BcdDefs.EVIndex; evb: BcdDefs.Base; mth: BcdOps.MTHandle; FindModule: PROC [mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS [BOOL] = BEGIN mgfi: PrincOps.GFTIndex ← mth.gfi; IF blink.vgfi IN [mth.gfi..mgfi + mth.ngfi) THEN BEGIN trueep ← BcdDefs.VarLimit*(blink.vgfi - mgfi); RETURN[TRUE] END; RETURN[FALSE] END; IF bcdbase = NIL THEN bcdbase ← loadinfoseq.bcdbase; mth ← BcdOps.ProcessModules[bcdbase, FindModule].mth; IF mth = NIL THEN RETURN[PrincOps.NullLink]; IF frame = NIL THEN frame ← PrincOpsRuntime.GetFrame[PrincOpsRuntime.GFT[ loadinfoseq.dummymapseq[blink.vgfi].ind]]; evb ← LOOPHOLE[bcdbase + bcdbase.evOffset]; trueep ← trueep + blink.var; IF trueep = 0 THEN RETURN[LOOPHOLE[frame]]; evi ← mth.variables; RETURN[LOOPHOLE[frame + evb[evi].offsets[trueep]]]; }; -- only works for exported BcdDefs.Links in the export table ConvertDummyLinkToControlLink: PROC[bl: BcdDefs.Link, realgfi: CARDINAL, bcdbase: BcdOps.BcdBase, loadinfoseq: LowLoader.LoadInfoSeq] RETURNS[cl: PrincOps.ControlLink, newcgfi: PrincOps.GFTIndex] = { cgfi: PrincOps.GFTIndex; ForEachModule: PROC [mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS [BOOL] = BEGIN mgfi: PrincOps.GFTIndex ← mth.gfi; IF cgfi IN [mth.gfi..mgfi + mth.ngfi) THEN { newcgfi ← newcgfi + (cgfi - mgfi); realgfi ← realgfi + (cgfi - mgfi); RETURN[TRUE]; }; RETURN[FALSE] END; newcgfi ← loadinfoseq.configGfi; IF bl = BcdDefs.UnboundLink THEN RETURN[PrincOps.UnboundLink, newcgfi]; SELECT bl.vtag FROM var => { cgfi ← bl.vgfi; IF BcdOps.ProcessModules[bcdbase, ForEachModule].mth = NIL THEN RETURN[PrincOps.NullLink, newcgfi]; cl ← [procedure[gfi: realgfi, ep: bl.var, tag: FALSE]]; }; proc0, proc1 => { cgfi ← bl.gfi; IF BcdOps.ProcessModules[bcdbase, ForEachModule].mth = NIL THEN RETURN[PrincOps.UnboundLink, newcgfi]; cl ← [procedure[gfi: realgfi, ep: bl.ep, tag: TRUE]]; }; type => cl ← LOOPHOLE[bl.typeID]; ENDCASE; }; EqualStringAndName: PUBLIC PROC[sym: LONG STRING, namestring: BcdOps.NameString, name: BcdDefs.NameRecord] RETURNS[equal: BOOL] = { IF sym.length ~= namestring.size[name] THEN RETURN[FALSE]; FOR i: CARDINAL IN [0 .. sym.length) DO IF sym[i] ~= namestring.string.text[name + i] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; }; CopyNStoLS: PUBLIC PROC[resultstr: LONG STRING, bcdbase: BcdOps.BcdBase, name: BcdDefs.NameRecord] = { namestring: BcdOps.NameString; namestring ← LOOPHOLE[bcdbase + bcdbase.ssOffset]; IF namestring.size[name] > resultstr.maxlength THEN ERROR; FOR i: CARDINAL IN [0 .. namestring.size[name]) DO resultstr[i] ← namestring.string.text[name + i]; ENDLOOP; resultstr.length ← namestring.size[name]; }; FindAndMapInCode: PROC[bcdbase: BcdOps.BcdBase, bcdSpaceBase: File.PageNumber, bcdCap: File.Capability, loadinfoseq: LowLoader.LoadInfoSeq] RETURNS[ncodepages: CARDINAL] = { sgList: SGList; GetCode: PROC[mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS [stop: BOOL] = { frame: PrincOps.GlobalFrameHandle; stop ← FALSE; frame ← PrincOpsRuntime.GetFrame[PrincOpsRuntime.GFT[ loadinfoseq.dummymapseq[mth.gfi].ind]]; IF frame = NIL THEN ERROR; Runtime.ValidateGlobalFrame[frame]; IF NOT bcdbase.tableCompiled AND mth.altoCode THEN InvalidModule[bcdbase, mth]; frame.code.longbase ← SgiToLP[bcdbase, mth.code.sgi, sgList] + mth.code.offset; IF frame.code.longbase = NIL THEN ERROR; frame.code.out ← TRUE; }; sgList ← FindSegments[bcdbase]; ncodepages ← AllocateCodeSpaces[bcdbase, sgList, bcdSpaceBase, bcdCap]; [] ← BcdOps.ProcessModules[bcdbase, GetCode ! UNWIND => ReleaseCode[sgList]]; Heap.FreeMDSNode[z: Heap.systemMDSZone, p: BASE[sgList]]; }; Zero: PUBLIC PROC[lp: LONG POINTER, nwords: CARDINAL] = { FOR i: CARDINAL IN [0 .. nwords) DO (lp + i)↑ ← 0; ENDLOOP; }; AllocateLoadInfoSeq: PUBLIC PROC[bcdbase: BcdOps.BcdBase] RETURNS[loadinfoseq: LowLoader.LoadInfoSeq] = { longzone: UNCOUNTED ZONE ← Subr.LongZone[]; loadinfoseq ← longzone.NEW[LowLoader.LoadInfoSeqRecord[bcdbase.nModules]]; loadinfoseq.dummymapseq ← longzone.NEW[ LowLoader.DummyMapSeqRecord[bcdbase.firstdummy +bcdbase.nDummies]]; loadinfoseq.impexpseq ← longzone.NEW[ LowLoader.ImpExpSeqRecord[bcdbase.nImports]]; }; FreeLoadInfoSeq: PUBLIC PROC[loadinfoseq: LowLoader.LoadInfoSeq] = { longzone: UNCOUNTED ZONE; IF loadinfoseq = NIL THEN RETURN; longzone ← Subr.LongZone[]; IF loadinfoseq.bcdbase ~= NIL THEN Space.Delete[Space.GetHandle[Space.PageFromLongPointer[loadinfoseq.bcdbase]] ! Space.Error => CONTINUE]; longzone.FREE[@loadinfoseq.impexpseq]; longzone.FREE[@loadinfoseq.dummymapseq]; longzone.FREE[@loadinfoseq]; }; AllocateInterfaceSeq: PUBLIC PROC[intname: LONG STRING, size: CARDINAL] RETURNS[interfaceseq: LowLoader.InterfaceSeq] = { longzone: UNCOUNTED ZONE ← Subr.LongZone[]; interfaceseq ← longzone.NEW[LowLoader.InterfaceSeqRecord[size]]; interfaceseq.intname ← Subr.CopyString[intname]; }; FreeInterfaceSeq: PUBLIC PROC[interfaceseq: LowLoader.InterfaceSeq] = { longzone: UNCOUNTED ZONE; IF interfaceseq = NIL OR interfaceseq.isfromloadstate THEN RETURN; longzone ← Subr.LongZone[]; Subr.FreeString[interfaceseq.intname]; longzone.FREE[@interfaceseq]; }; -- from [Ivy]<CedarLang>LowLoader>PilotLoaderSupport.Mesa ReleaseCode: PROC [sgList: SGList] = BEGIN i: CARDINAL; space1, space2: Space.Handle; space1 ← Subr.FindMappedSpace[sgList[i ← 0].space]; i ← 1; DO DO IF i = LENGTH[sgList] THEN EXIT; IF (space2 ← Subr.FindMappedSpace[sgList[i].space]) # space1 THEN EXIT; i ← i + 1; ENDLOOP; Space.Delete[space1]; IF i = LENGTH[sgList] THEN EXIT; space1 ← space2; i ← i + 1; ENDLOOP; RETURN; END; FindSegments: PROC [bcd: BcdOps.BcdBase] RETURNS [sgList: SGList] = BEGIN n: CARDINAL; sgItem: SGItem; CountSegs: PROC [sgh: BcdOps.SGHandle, sgi: BcdDefs.SGIndex] RETURNS [BOOL] = { IF sgh.class # code THEN RETURN[FALSE]; IF sgh.file # BcdDefs.FTSelf THEN BadFile[bcd, sgh.file]; n ← n + 1; RETURN[FALSE]}; AddSeg: PROC [sgh: BcdOps.SGHandle, sgi: BcdDefs.SGIndex] RETURNS [BOOL] = { IF sgh.class # code THEN RETURN[FALSE]; sgList[n] ← [sgh: sgh, space: Space.nullHandle]; n ← n + 1; RETURN[FALSE]}; SiftUp: PROC [low, high: CARDINAL] = { k, son: CARDINAL; sgItem: SGItem; k ← low; DO IF k*2 > high THEN EXIT; IF k*2 + 1 > high OR sgList[k*2 + 1 - 1].sgh.base < sgList[ k*2 - 1].sgh.base THEN son ← k*2 ELSE son ← k*2 + 1; IF sgList[son - 1].sgh.base < sgList[k - 1].sgh.base THEN EXIT; sgItem ← sgList[son - 1]; sgList[son - 1] ← sgList[k - 1]; sgList[k - 1] ← sgItem; k ← son; ENDLOOP; RETURN}; n ← 0; [] ← BcdOps.ProcessSegs[bcd, CountSegs]; sgList ← DESCRIPTOR[ Heap.MakeMDSNode[z: Heap.systemMDSZone, n: n*SIZE[SGItem]], n]; n ← 0; [] ← BcdOps.ProcessSegs[bcd, AddSeg]; FOR n DECREASING IN [1..LENGTH[sgList]/2] DO SiftUp[n, LENGTH[sgList]] ENDLOOP; FOR n DECREASING IN [1..LENGTH[sgList]) DO sgItem ← sgList[1 - 1]; sgList[1 - 1] ← sgList[n + 1 - 1]; sgList[n + 1 - 1] ← sgItem; SiftUp[1, n]; ENDLOOP; END; AllocateCodeSpaces: PROC [bcd: BcdOps.BcdBase, sgList: SGList, bcdSpaceBase: File.PageNumber, bcdCap: File.Capability] RETURNS[ncodepages: CARDINAL] = BEGIN start, end, startBase, pages, offset: CARDINAL; space, subSpace: Space.Handle; ncodepages ← 0; IF bcd.nModules = 1 THEN { -- this is a bcd produced by the compiler biaspages: CARDINAL; mth: BcdOps.MTHandle; IF LENGTH[sgList] ~= 1 THEN ERROR; mth ← @LOOPHOLE[bcd + bcd.mtOffset, BcdDefs.Base][FIRST[BcdDefs.MTIndex]]; -- non-0 if code links biaspages ← IF mth.linkLoc = code THEN (LinkSegmentLength[mth, bcd]/ Environment.wordsPerPage) + 1 ELSE 0; pages ← sgList[0].sgh.pages; ncodepages ← pages + biaspages; space ← SpecialSpace.CreateForCode[ size: pages + biaspages, parent: Space.virtualMemory, base: Space.defaultBase]; -- if the bcd is being loaded with code links, -- the cedar compiler will have left room for them Space.Map[space: space, window: Space.WindowOrigin[ file: File.LimitPermissions[bcdCap, File.read], base: bcdSpaceBase + sgList[0].sgh.base - 1]]; sgList[0].space ← space; RETURN; }; start ← end ← 0; DO startBase ← sgList[start].sgh.base; pages ← sgList[start].sgh.pages; DO end ← end + 1; IF end = LENGTH[sgList] OR pages + sgList[end].sgh.pages > 255 THEN EXIT; pages ← pages + sgList[end].sgh.pages; ENDLOOP; space ← SpecialSpace.CreateForCode[ size: pages, parent: Space.virtualMemory, base: Space.defaultBase]; ncodepages ← ncodepages + pages; Space.Map[ space: space, window: Space.WindowOrigin[ file: File.LimitPermissions[bcdCap, File.read], base: bcdSpaceBase + sgList[start].sgh.base - 1]]; offset ← 0; FOR index: CARDINAL IN [start..end) DO sgh: BcdOps.SGHandle ← sgList[index].sgh; sph: BcdOps.SPHandle ← FindSPHandle[bcd, sgh]; IF sph = NIL THEN subSpace ← Space.Create[size: sgh.pages, parent: space, base: offset] ELSE { FOR sp: CARDINAL DECREASING IN [0..sph.length) DO subSpace ← Space.Create[ size: sph.spaces[sp].pages, parent: space, base: offset + sph.spaces[sp].offset]; IF sph.spaces[sp].resident THEN SpecialSpace.MakeResident[subSpace]; ENDLOOP}; sgList[index].space ← subSpace; offset ← offset + sgh.pages; ENDLOOP; IF end = LENGTH[sgList] THEN EXIT ELSE start ← end; ENDLOOP; RETURN; END; FindSPHandle: PROC [bcd: BcdOps.BcdBase, sgh: BcdOps.SGHandle] RETURNS [sph: BcdOps.SPHandle] = BEGIN sgb: BcdDefs.Base = LOOPHOLE[bcd + bcd.sgOffset]; spb: BcdDefs.Base = LOOPHOLE[bcd + bcd.spOffset]; spi: BcdDefs.SPIndex; FOR spi ← FIRST[BcdDefs.SPIndex], spi + SIZE[BcdDefs.SPRecord] + sph.length*SIZE[BcdDefs.SpaceID] UNTIL spi = bcd.spLimit DO sph ← @spb[spi]; IF @sgb[sph.seg] = sgh THEN RETURN[sph]; ENDLOOP; RETURN[NIL] END; SgiToLP: PROC [bcd: BcdOps.BcdBase, sgi: BcdDefs.SGIndex, sgList: SGList] RETURNS [LONG POINTER] = BEGIN sgb: BcdDefs.Base = LOOPHOLE[bcd + bcd.sgOffset]; i: CARDINAL; FOR i IN [0..LENGTH[sgList]) DO IF @sgb[sgi] = sgList[i].sgh THEN RETURN[Space.LongPointer[sgList[i].space]]; ENDLOOP; RETURN[NIL] END; BadCode: SIGNAL [name: STRING] = CODE; MissingCode: SIGNAL [name: STRING] = CODE; AppendName: PROC [s: STRING, ssb: BcdOps.NameString, name: BcdDefs.NameRecord] = BEGIN i: CARDINAL; FOR i IN [s.length..MIN[s.maxlength, ssb.size[name] + s.length]) DO s[i] ← ssb.string.text[name + i]; s.length ← s.length + 1; ENDLOOP; END; InvalidModule: PROC [bcd: BcdOps.BcdBase, mth: BcdOps.MTHandle] = BEGIN name: STRING ← [40]; dummy: BOOL ← TRUE; AppendName[s: name, ssb: LOOPHOLE[bcd + bcd.ssOffset], name: mth.name]; IF dummy THEN ERROR BadCode[name]; END; BadFile: PROC [bcd: BcdOps.BcdBase, fti: BcdDefs.FTIndex] = BEGIN name: STRING ← [40]; fth: BcdOps.FTHandle = @LOOPHOLE[bcd + bcd.ftOffset, BcdDefs.Base][fti]; dummy: BOOL ← TRUE; AppendName[s: name, ssb: LOOPHOLE[bcd + bcd.ssOffset], name: fth.name]; IF dummy THEN ERROR MissingCode[name]; END; Alloc: PROC [CARDINAL] RETURNS [POINTER] = MACHINE CODE BEGIN Mopcodes.zALLOC END; InvalidFile: SIGNAL [File.Capability] = CODE; LoadUpBcd: PROC [file: File.Capability, offset: File.PageCount] RETURNS [bcd: BcdOps.BcdBase, pages: CARDINAL] = BEGIN bcdSpaceBase: File.PageNumber; bcdSpace: Space.Handle; bcdSpaceBase ← offset; bcdSpace ← Space.Create[size: 1, parent: Space.virtualMemory]; Space.Map[space: bcdSpace, window: [file: file, base: bcdSpaceBase]]; bcd ← Space.LongPointer[bcdSpace]; pages ← bcd.nPages; IF bcd.versionIdent # BcdDefs.VersionID OR bcd.definitions OR (NOT bcd.tableCompiled AND ~bcd.spare1) THEN ERROR InvalidFile[file ! UNWIND => Space.Delete[bcdSpace]]; IF pages > 1 THEN BEGIN Space.Delete[bcdSpace]; bcdSpace ← Space.Create[size: pages, parent: Space.virtualMemory]; Space.Map[space: bcdSpace, window: [file: file, base: bcdSpaceBase]]; bcd ← Space.LongPointer[bcdSpace]; END; Space.MakeReadOnly[bcdSpace]; -- make bcd header spaces ReadOnly, as the code is already RETURN END; LinkSegmentLength: PUBLIC PROC[mth: BcdOps.MTHandle, bcd: BcdOps.BcdBase] RETURNS[CARDINAL] = BEGIN WITH mth: mth SELECT FROM direct => RETURN[mth.length]; indirect => RETURN[LOOPHOLE[bcd + bcd.lfOffset, BcdDefs.Base][mth.links].length]; multiple => RETURN[LOOPHOLE[bcd + bcd.lfOffset, BcdDefs.Base][mth.links].length]; ENDCASE => ERROR; END; IthLink: PUBLIC PROC[mth: BcdOps.MTHandle, i: CARDINAL, bcd: BcdOps.BcdBase] RETURNS[BcdDefs.Link] = BEGIN WITH mth: mth SELECT FROM direct => RETURN[mth.frag[i]]; indirect => RETURN[LOOPHOLE[bcd + bcd.lfOffset, BcdDefs.Base][mth.links].frag[i]]; multiple => RETURN[LOOPHOLE[bcd + bcd.lfOffset, BcdDefs.Base][mth.links].frag[i]]; ENDCASE => ERROR; END; -- link space operations OpenLinkSpace: PUBLIC PROC [frame: PrincOps.GlobalFrameHandle, mth: BcdOps.MTHandle, bcd: BcdOps.BcdBase ← NIL] RETURNS[LONG POINTER] = BEGIN IF frame.codelinks THEN { long ← TRUE; links ← RuntimeInternal.Codebase[LOOPHOLE[frame]]; IF links = NIL THEN ERROR; } ELSE { long ← FALSE; links ← LOOPHOLE[LONG[frame]] }; links ← links - LinkSegmentLength[mth, bcd]; writeable ← FALSE; RETURN[links]; END; ReadLink: PUBLIC PROC [offset: CARDINAL] RETURNS [link: PrincOps.ControlLink] = BEGIN RETURN[links[offset]]; END; WriteLink: PUBLIC PROC [offset: CARDINAL, link: PrincOps.ControlLink] = { IF long AND NOT writeable THEN { space: Space.Handle; cap: File.Capability; writeable ← TRUE; space ← Subr.FindMappedSpace[Space.GetHandle[ Space.PageFromLongPointer[links]]]; cap ← Space.GetWindow[space].file; -- questionable???? -- IF Inline.BITAND[cap.permissions, File.write] = 0 THEN cap.permissions ← cap.permissions + File.write; Space.MakeWritable[space, cap] }; links[offset] ← link}; CloseLinkSpace: PUBLIC PROC [frame: PrincOps.GlobalFrameHandle] = { IF long AND writeable THEN Space.MakeReadOnly[Subr.FindMappedSpace[Space.GetHandle[ Space.PageFromLongPointer[links]]]] }; -- from CedarLoaderCore.Mesa NextMultipleOfFour: PROC [n: UNSPECIFIED] RETURNS [UNSPECIFIED] = BEGIN RETURN[n + Inline.BITAND[-LOOPHOLE[n, INTEGER], 3B]]; END; CMMapItem: TYPE = RECORD [cti: BcdDefs.CTIndex, cm: PrincOps.ControlModule, level: CARDINAL]; AssignControlModules: PROC [bcd: BcdOps.BcdBase, loadinfoseq: LowLoader.LoadInfoSeq] RETURNS [cm: PrincOps.ControlModule] = BEGIN OPEN PrincOps; ctb: BcdDefs.Base ← LOOPHOLE[bcd + bcd.ctOffset]; mtb: BcdDefs.Base ← LOOPHOLE[bcd + bcd.mtOffset]; cti: BcdDefs.CTIndex; mapIndex, maxLevel: CARDINAL ← 0; i: CARDINAL; cmMap: POINTER TO ARRAY [0..0) OF CMMapItem; MapControls: PROC [cth: BcdOps.CTHandle, cti: BcdDefs.CTIndex] RETURNS [BOOL] = BEGIN OPEN PrincOps, PrincOpsRuntime; cm: ControlModule; c: BcdDefs.CTIndex; level: CARDINAL ← 0; IF cth.nControls = 0 THEN cm ← NullControl ELSE { mti: BcdDefs.MTIndex; i: CARDINAL; cm.list ← Alloc[ RuntimeInternal.MakeFsi[cth.nControls + SIZE[CARDINAL] + SIZE[ControlModule]]]; cm.list.nModules ← cth.nControls + 1; FOR i IN [0..cth.nControls) DO WITH v: cth.controls[i] SELECT FROM -- new bcddefs module => mti ← v.mti; ENDCASE => ERROR; -- mti ← cth.controls[i]; old bcddefs cm.list.frames[i+1] ← GetFrame[GFT[loadinfoseq.dummymapseq[mtb[mti].gfi].ind]]; ENDLOOP; cm.multiple ← TRUE}; FOR c ← ctb[cti].config, ctb[c].config UNTIL c = BcdDefs.CTNull DO level ← level + 1; ENDLOOP; cmMap[mapIndex] ← [cti: cti, cm: cm, level: level]; mapIndex ← mapIndex + 1; maxLevel ← MAX[maxLevel, level]; RETURN[FALSE]; END; GetControl: PROC [mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS [BOOL] = BEGIN OPEN PrincOps, PrincOpsRuntime; frame: GlobalFrameHandle ← GetFrame[GFT[loadinfoseq.dummymapseq[mth.gfi].ind]]; IF mth.config # cti THEN RETURN[FALSE]; IF frame.global[0] = NullControl THEN frame.global[0] ← GetModule[cm]; RETURN[FALSE]; END; IF bcd.nModules = 1 THEN BEGIN OPEN PrincOpsRuntime; frame: GlobalFrameHandle ← GetFrame[GFT[loadinfoseq.dummymapseq[1].ind]]; frame.global[0] ← NullControl; RETURN[[frame[frame]]]; END; cmMap ← Heap.MakeMDSNode[z: Heap.systemMDSZone, n: bcd.nConfigs*SIZE[CMMapItem]]; [] ← BcdOps.ProcessConfigs[bcd, MapControls]; FOR level: CARDINAL DECREASING IN [0..maxLevel] DO FOR index: CARDINAL IN [0..mapIndex) DO list: ControlModule; IF cmMap[index].level # level OR (cm ← cmMap[index].cm) = NullControl THEN LOOP; list ← cm; list.multiple ← FALSE; list.list.frames[1] ← SetLink[cm, list.list.frames[1]].frame; FOR i: CARDINAL IN [2..list.list.nModules) DO list.list.frames[i] ← SetLink[GetModule[[frame[list.list.frames[1]]]], list.list.frames[i]].frame; ENDLOOP; cti ← cmMap[index].cti; [] ← BcdOps.ProcessModules[bcd, GetControl]; ENDLOOP; ENDLOOP; FOR index: CARDINAL IN [0..mapIndex) DO parent: CARDINAL; list: ControlModule; IF (list ← cmMap[index].cm) = PrincOps.NullControl THEN LOOP; list.multiple ← FALSE; IF (cti ← ctb[cmMap[index].cti].config) = BcdDefs.CTNull THEN cm ← PrincOps.NullControl ELSE { FOR parent IN [0..mapIndex) DO IF cmMap[parent].cti = cti THEN EXIT; ENDLOOP; cm ← GetModule[cmMap[parent].cm]}; list.list.frames[0] ← cm.frame; ENDLOOP; FOR i IN [0..mapIndex) DO IF ctb[cmMap[i].cti].config = BcdDefs.CTNull THEN { cm ← GetModule[cmMap[i].cm]; EXIT}; ENDLOOP; Heap.FreeMDSNode[z: Heap.systemMDSZone, p: cmMap]; END; SetLink: PROC [ cm: PrincOps.ControlModule, frame: PrincOps.GlobalFrameHandle] RETURNS [PrincOps.ControlModule] = { t: PrincOps.ControlModule = frame.global[0]; frame.global[0] ← cm; RETURN[IF t = PrincOps.NullControl THEN [frame[frame]] ELSE t]}; GetModule: PROC [cm: PrincOps.ControlModule] RETURNS [PrincOps.ControlModule] = { list: PrincOps.ControlModule; DO IF ~cm.multiple THEN RETURN[cm]; list ← cm; list.multiple ← FALSE; cm.frame ← list.list.frames[1]; ENDLOOP }; ConvertLink: PUBLIC PROC [bl: BcdDefs.Link] RETURNS [cl: PrincOps.ControlLink] = BEGIN IF bl = BcdDefs.UnboundLink THEN RETURN[PrincOps.UnboundLink]; SELECT bl.vtag FROM var => cl ← [procedure[gfi: bl.vgfi, ep: bl.var, tag: FALSE]]; proc0, proc1 => cl ← [procedure[gfi: bl.gfi, ep: bl.ep, tag: TRUE]]; type => cl ← LOOPHOLE[bl.typeID]; ENDCASE; RETURN END; }.