<> <> <> <> DIRECTORY BcdDefs USING [ Base, Link, CTIndex, CTNull, EVNull, FPIndex, FPRecord, GFTIndex, MTIndex, VarLimit, VersionID], BcdOps USING [ BcdBase, CTHandle, FPHandle, MTHandle, NameString, ProcessConfigs, ProcessFramePacks, ProcessModules], Inline USING [BITAND], LongString USING [AppendString], MB USING [ Abort, AllocateFrames, BHandle, BIndex, EnumerateFramePacks, EnumerateGlobalFrames, Error, Handle, ModuleInfo, MT, Zero], MBLoaderOps USING [ Bind, EnterModule, FileNotFound, FindFiles, FindCode, GetModule, GetNextGFI, GetVirtualLinks, InputLoadState, LinkFragLength, ProcessUnboundImports, SetGFTEntry, UpdateLoadState, VirtualLinks, WriteLoadState, WriteLinks], MBOut USING [Char, CR, Decimal, Line, Number, NumberFormat, Octal, SP, Text], MBStorage USING [Pages, FreePages, FreeWords, Words], MBTTY USING [Handle, PutCR, PutLine, PutString], MBVM USING [AllocFile, Base, CopyWrite, FileSeg, HyperSpace, Read, Write], PilotLoadStateFormat USING [ConfigIndex, ModuleInfo], PrincOps USING [ AV, ControlLink, ControlModule, FrameCodeBase, GFTIndex, GlobalFrame, GlobalFrameHandle, NullControl, NullLink, UnboundLink], RuntimeInternal USING [MakeFsi], Segments USING [ BaseFromSegment, DeleteSegment, FHandle, FileFromSegment, HardUp, MoveSegment, NewFile, NewSegment, PagesFromSegment, Read, SegmentAddress, SHandle, SwapIn, Unlock]; MBLoaderCore: PROGRAM IMPORTS BcdOps, Inline, MB, MBLoaderOps, MBOut, MBStorage, MBTTY, MBVM, RuntimeInternal, Segments, String: LongString EXPORTS MB, MBLoaderOps = BEGIN OPEN MB; data: MB.Handle _ NIL; InitLoaderCore: PUBLIC PROC [h: MB.Handle] = {data _ h}; FinishLoaderCore: PUBLIC PROC = { FOR i: MB.BIndex IN [0..data.inputBCDs.nBcds) DO loadee: MB.BHandle = data.inputBCDs.bcds[i]; ReleaseModuleTable[loadee]; IF loadee.bcdSegment ~= NIL THEN { Segments.Unlock[loadee.bcdSegment]; Segments.DeleteSegment[loadee.bcdSegment]; }; ENDLOOP; data _ NIL; }; Load: PUBLIC PROC = { tty: MBTTY.Handle = data.ttyHandle; data.nModules _ 0; FOR i: MB.BIndex IN [0..data.inputBCDs.nBcds) DO loadee: MB.BHandle = data.inputBCDs.bcds[i]; name: STRING _ [40]; missingCodeFile: BOOL _ FALSE; config: PilotLoadStateFormat.ConfigIndex; String.AppendString[name, loadee.name]; MBTTY.PutString[tty, "Loading "]; MBTTY.PutString[tty, name]; MBTTY.PutString[tty, "..."L]; IF (loadee.bcdSegment _ LoadBcd[Segments.NewFile[name]]) = NIL THEN { MBTTY.PutCR[tty]; MBTTY.PutString[tty, "!Invalid file "L]; MBTTY.PutString[tty, name]; ERROR MB.Abort }; MBOut.Text["Global Frames for Modules in "L]; MBOut.Text[name]; MBOut.Char[':]; MBOut.CR[]; loadee.bcd _ Segments.SegmentAddress[loadee.bcdSegment]; IF ~data.germ THEN { loadee.bcdSeg _ MBVM.AllocFile[ file: Segments.FileFromSegment[loadee.bcdSegment], fileBase: Segments.BaseFromSegment[loadee.bcdSegment], base: MBVM.HyperSpace, pages: Segments.PagesFromSegment[loadee.bcdSegment]]; loadee.bcdSeg.segment _ loadee.bcdSegment; loadee.bcdSeg.bIndex _ i; }; MBLoaderOps.FindFiles[loadee ! MBLoaderOps.FileNotFound => { MBTTY.PutCR[tty]; MBTTY.PutString[tty, "!Can't find file "L]; MBTTY.PutString[tty, name]; missingCodeFile _ TRUE; RESUME } ]; IF missingCodeFile THEN {MBTTY.PutCR[tty]; MB.Error["Missing code files"L]}; config _ LoadModules[loadee]; MBTTY.PutString[tty, "looking up code..."L]; MBLoaderOps.FindCode[loadee]; MBTTY.PutString[tty, "binding modules..."L]; [] _ AssignControlModules[loadee]; IF config = FIRST[PilotLoadStateFormat.ConfigIndex] THEN JustRelocateLinks[loadee] ELSE MBLoaderOps.Bind[loadee, config]; MBOut.CR[]; MBTTY.PutLine[tty, "done"L]; ENDLOOP; MBLoaderOps.WriteLoadState[]; data.nGFIs _ MBLoaderOps.GetNextGFI[reserve: 0]; MBOut.CR[]; MBOut.Text["Total of "L]; MBOut.Decimal[data.nModules]; MBOut.Text[" modules, "L]; MBOut.Decimal[data.nGFIs]; MBOut.Line[" GFIs"L]; MBLoaderOps.ProcessUnboundImports[]; MBTTY.PutLine[tty, "Finished loading."L]; }; LoadBcd: PROC [bcdfile: Segments.FHandle] RETURNS [bcdseg: Segments.SHandle] = { b: BcdOps.BcdBase; pages: CARDINAL; bcdseg _ Segments.NewSegment[file: bcdfile, base: 1, pages: 1, access: Segments.Read]; Segments.SwapIn[seg: bcdseg, info: Segments.HardUp]; b _ Segments.SegmentAddress[bcdseg]; IF b.versionIdent # BcdDefs.VersionID OR b.definitions --OR ~b.spare1-- THEN { Segments.Unlock[bcdseg]; Segments.DeleteSegment[bcdseg]; RETURN[NIL] }; IF (pages _ b.nPages) > 1 THEN { Segments.Unlock[bcdseg]; Segments.MoveSegment[bcdseg, 1, pages]; Segments.SwapIn[seg: bcdseg, info: Segments.HardUp]; }; }; SetupModuleTable: PROC [loadee: MB.BHandle] RETURNS [ngfi: CARDINAL _ 0] = { <> words: CARDINAL = loadee.bcd.firstdummy * SIZE[MB.ModuleInfo]; SetEntriesForOneModule: PROC [ mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS [stop: BOOL] = { ngfi _ ngfi + mth.ngfi; FOR i: CARDINAL IN [mth.gfi..mth.gfi+mth.ngfi) DO loadee.mt[i] _ MB.ModuleInfo[mth: mth, frame: NIL, code: NIL]; ENDLOOP; RETURN[FALSE] }; <> loadee.mt _ DESCRIPTOR[MBStorage.Words[words], loadee.bcd.firstdummy]; MB.Zero[BASE[loadee.mt], words]; loadee.mt[0] _ MB.ModuleInfo[mth: NIL, frame: NIL, code: NIL]; [] _ BcdOps.ProcessModules[loadee.bcd, SetEntriesForOneModule]; loadee.mt _ DESCRIPTOR[BASE[loadee.mt], ngfi+1]; }; ReleaseModuleTable: PUBLIC PROC [loadee: MB.BHandle] = { IF BASE[loadee.mt] # NIL THEN { MBStorage.FreeWords[BASE[loadee.mt]]; loadee.mt _ DESCRIPTOR[NIL,0]; }; }; LoadModules: PROC [loadee: MB.BHandle] RETURNS [config: PilotLoadStateFormat.ConfigIndex] = BEGIN bcd: BcdOps.BcdBase = loadee.bcd; mt: MT; ngfi: CARDINAL; gfiOffset: CARDINAL; framePtr: POINTER; frameSpace: CARDINAL _ 0; useFrameHeap: BOOL = (bcd.nModules = 1); inFrameHeap: BOOL; framesResident: BOOL _ FALSE; ProcessOneFramePack: PROC [fph: BcdOps.FPHandle, fpi: BcdDefs.FPIndex] RETURNS [BOOL] = { mtb: BcdDefs.Base = LOOPHOLE[bcd + bcd.mtOffset]; frameSpace _ 0; framesResident _ FALSE; FOR i: CARDINAL IN [0..fph.length) DO GetFrameSize[@mtb[fph.modules[i]]]; ENDLOOP; [framePtr, inFrameHeap] _ MB.AllocateFrames[ size: NextMultipleOfFour[frameSpace], single: useFrameHeap, resident: framesResident OR ResidentFramePack[fph] -- specified in bootmesa file--]; FOR i: CARDINAL IN [0..fph.length) DO FrameInit[@mtb[fph.modules[i]]]; ENDLOOP; RETURN[FALSE] }; GetFrameSize: PROC [mth: BcdOps.MTHandle] = { IF ~(mth.linkLoc = code AND mth.code.linkspace) THEN -- frame links frameSpace _ frameSpace + MBLoaderOps.LinkFragLength[loadee, mth]; frameSpace _ NextMultipleOfFour[frameSpace] + mth.framesize; framesResident _ framesResident OR mth.residentFrame; }; FrameInit: PROC [mth: BcdOps.MTHandle] = { frame: PrincOps.GlobalFrameHandle; gf: PrincOps.GlobalFrame; gfi: PrincOps.GFTIndex = gfiOffset + mth.gfi; -- module's biased gfi framelinks: BOOL = ~(mth.linkLoc = code AND mth.code.linkspace); nLinks: CARDINAL = MBLoaderOps.LinkFragLength[loadee, mth]; data.nModules _ data.nModules + 1; <> IF framelinks THEN framePtr _ (framePtr + nLinks); frame _ NextMultipleOfFour[framePtr]; framePtr _ (frame + mth.framesize); <> FOR i: CARDINAL IN [0..mth.ngfi) DO mt[mth.gfi + i].frame _ frame; ENDLOOP; <> MBLoaderOps.SetGFTEntry[frame: frame, gfi: gfi, ngfi: mth.ngfi]; FOR i: CARDINAL IN [0..mth.ngfi) DO MBLoaderOps.EnterModule[ rgfi: (gfi + i), module: PilotLoadStateFormat.ModuleInfo[ config: config, gfi: (mth.gfi + i), -- local gfi resolved: (nLinks = 0)] ]; ENDLOOP; <> gf _ PrincOps.GlobalFrame[ gfi: gfi, copied: FALSE, alloced: inFrameHeap, shared: FALSE, started: FALSE, trapxfers: FALSE, codelinks: ~framelinks, global: , code: PrincOps.FrameCodeBase[ offset[offset: mth.code.offset, highHalf: NIL]] ]; gf.code.out _ TRUE; MBVM.CopyWrite[from: @gf, to: frame, nwords: SIZE[PrincOps.GlobalFrame]]; MBVM.Write[@frame.global[0], PrincOps.NullControl]; -- no control module PrintLoadmapEntry[bcd: bcd, mth: mth, frame: frame, gfiOffset: gfiOffset]; }; OtherFrameSizes: PROC [mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS [BOOL] = { IF mt[mth.gfi].frame = NIL THEN GetFrameSize[mth]; RETURN[FALSE] }; OtherFrameInit: PROC [mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS [BOOL] = { IF mt[mth.gfi].frame = NIL THEN FrameInit[mth]; RETURN[FALSE] }; ngfi _ SetupModuleTable[loadee]; mt _ loadee.mt; config _ MBLoaderOps.InputLoadState[]; <> loadee.gfiOffset _ gfiOffset _ MBLoaderOps.GetNextGFI[reserve: ngfi] - 1; [] _ BcdOps.ProcessFramePacks[bcd, ProcessOneFramePack]; frameSpace _ 0; framesResident _ FALSE; [] _ BcdOps.ProcessModules[bcd, OtherFrameSizes]; IF frameSpace # 0 THEN { -- there are frames not in frame packs [framePtr, inFrameHeap] _ MB.AllocateFrames[ size: NextMultipleOfFour[frameSpace], single: useFrameHeap, resident: framesResident OR AnyResidentGlobalFrames[loadee]]; [] _ BcdOps.ProcessModules[bcd, OtherFrameInit]}; END; ResidentFramePack: PROC [f: BcdOps.FPHandle] RETURNS [resident: BOOL] = { CheckOne: PROC [bh: MB.BHandle, fph: BcdOps.FPHandle] RETURNS [BOOL] = { RETURN[resident _ (f = fph)]}; MB.EnumerateFramePacks[resident, CheckOne]; }; AnyResidentGlobalFrames: PROC [loadee: MB.BHandle] RETURNS [resident: BOOL] = { CheckOne: PROC [bh: MB.BHandle, mth: BcdOps.MTHandle] RETURNS [BOOL] = { RETURN[resident _ (bh = loadee)]}; MB.EnumerateGlobalFrames[resident, CheckOne]; }; NextMultipleOfFour: PROC [x: UNSPECIFIED] RETURNS [UNSPECIFIED] = INLINE { RETURN[x + Inline.BITAND[-LOOPHOLE[x, INTEGER], 3B]]}; PrintLoadmapEntry: PROC [ bcd: BcdOps.BcdBase, mth: BcdOps.MTHandle, frame: POINTER, gfiOffset: CARDINAL] = { ssb: BcdOps.NameString _ LOOPHOLE[bcd + bcd.ssOffset]; MBOut.Text[" New: g = "L]; MBOut.Number[frame, MBOut.NumberFormat[8,FALSE,TRUE,6]]; MBOut.SP[]; FOR i: CARDINAL IN [mth.name .. mth.name+ssb.size[mth.name]) DO MBOut.Char[ssb.string.text[i]]; ENDLOOP; MBOut.Text[" ["L]; MBOut.Octal[PrincOps.ControlLink[ procedure[gfi: (gfiOffset + mth.gfi), ep: 0, tag: FALSE]]]; MBOut.Char[']]; MBOut.CR[]; }; <> CMMapItem: TYPE = RECORD [ cti: BcdDefs.CTIndex, cm: PrincOps.ControlModule, depth: CARDINAL ]; AssignControlModules: PROC [loadee: MB.BHandle] RETURNS [cm: PrincOps.ControlModule] = { bcd: BcdOps.BcdBase = loadee.bcd; mt: MB.MT = loadee.mt; ctb: BcdDefs.Base _ LOOPHOLE[bcd + bcd.ctOffset]; mtb: BcdDefs.Base _ LOOPHOLE[bcd + bcd.mtOffset]; cmMap: LONG POINTER TO ARRAY [0..0) --subconfig#-- OF CMMapItem; lastConfig, maxDepth: CARDINAL _ 0; cti: BcdDefs.CTIndex; EnterControlInfoForConfig: PROC [ cth: BcdOps.CTHandle, cti: BcdDefs.CTIndex] RETURNS [stop: BOOL] = { cm: PrincOps.ControlModule; depth: CARDINAL _ 0; -- depth of config in Bcd's config structure IF cth.nControls = 0 THEN cm _ PrincOps.NullControl ELSE { <> cm.list _ Alloc[RuntimeInternal.MakeFsi[words: (cth.nControls + 1) + 1] ! AllocFault => MB.Error["Larger frame heap needed (for control list)"L] ]; MBVM.Write[@cm.list.nModules, (cth.nControls + 1)]; FOR i: CARDINAL IN [0..cth.nControls) DO WITH cItem: cth.controls[i] SELECT FROM module => MBVM.Write[@cm.list.frames[i+1], mt[mtb[cItem.mti].gfi].frame]; config => MB.Error["Configurations in control lists aren't supported yet."L]; ENDCASE; ENDLOOP; cm.multiple _ TRUE; FOR c: BcdDefs.CTIndex _ ctb[cti].config, ctb[c].config UNTIL c = BcdDefs.CTNull DO depth _ depth + 1; ENDLOOP; }; maxDepth _ MAX[maxDepth, depth]; cmMap[lastConfig] _ CMMapItem[cti: cti, cm: cm, depth: depth]; lastConfig _ lastConfig + 1; RETURN[FALSE] }; IF bcd.nModules = 1 THEN { frame: PrincOps.GlobalFrameHandle _ mt[1].frame; MBVM.Write[@frame.global[0], PrincOps.NullControl]; RETURN }; < (subconfig & control module info) map>> cmMap _ MBStorage.Words[bcd.nConfigs * SIZE[CMMapItem]]; lastConfig _ 0; [] _ BcdOps.ProcessConfigs[bcd, EnterControlInfoForConfig]; FOR depth: CARDINAL DECREASING IN [0..maxDepth] DO FOR index: CARDINAL IN [0..lastConfig) DO list, listHead, oldCm: PrincOps.ControlModule; SetModulesControl: PROC [ mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS [stop: BOOL] = { frame: PrincOps.GlobalFrameHandle _ mt[mth.gfi].frame; IF mth.config # cti THEN RETURN[FALSE]; IF MBVM.Read[@frame.global[0]] = PrincOps.NullControl THEN MBVM.Write[@frame.global[0], GetLink[cm]]; RETURN[FALSE] }; IF cmMap[index].depth # depth OR (cm _ cmMap[index].cm) = PrincOps.NullControl THEN LOOP; list _ cm; list.multiple _ FALSE; cti _ cmMap[index].cti; <> listHead _ SetLink[cm: cm, frame: MBVM.Read[@list.list.frames[1]]]; MBVM.Write[@list.list.frames[1], listHead]; -- restore old value FOR i: CARDINAL IN [2..ctb[cti].nControls+1) DO oldCm _ SetLink[cm: GetLink[listHead], frame: MBVM.Read[@list.list.frames[i]]]; MBVM.Write[@list.list.frames[i], oldCm]; ENDLOOP; <> [] _ BcdOps.ProcessModules[bcd, SetModulesControl]; ENDLOOP; ENDLOOP; <> FOR index: CARDINAL IN [0..lastConfig) DO parent: CARDINAL; list: PrincOps.ControlModule _ cmMap[index].cm; IF list = 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..lastConfig) DO IF cmMap[parent].cti = cti THEN EXIT ENDLOOP; cm _ GetLink[cmMap[parent].cm]; }; MBVM.Write[@list.list.frames[0], cm]; ENDLOOP; <> FOR i: CARDINAL IN [0..lastConfig) DO IF ctb[cmMap[i].cti].config = BcdDefs.CTNull THEN { cm _ GetLink[cmMap[i].cm]; EXIT}; ENDLOOP; MBStorage.FreeWords[cmMap]; }; AllocFault: PUBLIC ERROR = CODE; Alloc: PUBLIC PROC [fsi: CARDINAL] RETURNS [p: POINTER] = { DO p _ MBVM.Read[PrincOps.AV + fsi]; SELECT LOOPHOLE[p, CARDINAL] MOD 4 FROM 0 => EXIT; -- a free frame 1, 3 => ERROR AllocFault; 2 => fsi _ LOOPHOLE[p, CARDINAL]/4; -- use an fsi for larger frames ENDCASE; ENDLOOP; MBVM.Write[PrincOps.AV + fsi, MBVM.Read[p]]; RETURN[p] }; GetLink: PROC [ cm: PrincOps.ControlModule] RETURNS [--frame--PrincOps.ControlModule] = { list: PrincOps.ControlModule; DO -- search up backward pointers for the actual frame to start IF ~cm.multiple THEN RETURN[cm]; list _ cm; list.multiple _ FALSE; cm _ MBVM.Read[@list.list.frames[1]]; ENDLOOP; }; SetLink: PROC [cm: PrincOps.ControlModule, frame: PrincOps.GlobalFrameHandle] RETURNS [PrincOps.ControlModule] = { old: PrincOps.ControlModule = MBVM.Read[@frame.global[0]]; MBVM.Write[@frame.global[0], cm]; RETURN[IF old # PrincOps.NullControl THEN old ELSE [frame[frame]]] }; JustRelocateLinks: PROC [loadee: MB.BHandle] = { bcd: BcdOps.BcdBase = loadee.bcd; mt: MB.MT = loadee.mt; realLinks: LONG POINTER TO ARRAY [0..0) OF PrincOps.ControlLink = MBStorage.Pages[1]; RelocateLinksForModule: PROC [mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS [BOOL] = { gfi: BcdDefs.GFTIndex = mth.gfi; frame: PrincOps.GlobalFrameHandle _ mt[gfi].frame; resolved: BOOL _ TRUE; virtualLinks: MBLoaderOps.VirtualLinks _ MBLoaderOps.GetVirtualLinks[loadee, mth]; IF LENGTH[virtualLinks] # 0 THEN { -- relocate external links FOR i: CARDINAL IN [0..LENGTH[virtualLinks]) DO link: BcdDefs.Link _ virtualLinks[i]; SELECT link.vtag FROM proc1, proc0 => IF link.gfi >= bcd.firstdummy THEN {resolved _ FALSE; realLinks[i] _ PrincOps.UnboundLink} ELSE realLinks[i] _ ConvertLink[link]; var => IF link.gfi >= bcd.firstdummy THEN {resolved _ FALSE; realLinks[i] _ PrincOps.NullLink} ELSE realLinks[i] _ ConvertVariableLink[link]; ENDCASE => {resolved _ FALSE; realLinks[i] _ PrincOps.NullLink}; ENDLOOP; MBLoaderOps.WriteLinks[loadee: loadee, mth: mth, links: realLinks]; }; FOR i: CARDINAL IN [gfi..gfi+mth.ngfi) DO info: PilotLoadStateFormat.ModuleInfo _ MBLoaderOps.GetModule[i]; info.resolved _ resolved; MBLoaderOps.EnterModule[i, info]; ENDLOOP; RETURN[FALSE] }; ConvertVariableLink: PROC [link: BcdDefs.Link] RETURNS [PrincOps.ControlLink] = { mth: BcdOps.MTHandle; frame: PrincOps.GlobalFrameHandle; gfi: BcdDefs.GFTIndex = link.gfi; evb: BcdDefs.Base = LOOPHOLE[bcd + bcd.evOffset]; vp: CARDINAL; [mth: mth, frame: frame] _ mt[gfi]; IF gfi >= bcd.firstdummy THEN RETURN[PrincOps.NullLink]; vp _ BcdDefs.VarLimit*(gfi - mth.gfi) + link.var; IF vp = 0 THEN RETURN[LOOPHOLE[frame]]; IF mth.variables = BcdDefs.EVNull THEN RETURN[PrincOps.NullLink] ELSE RETURN[LOOPHOLE[frame + evb[mth.variables].offsets[vp]]] }; MBLoaderOps.UpdateLoadState[FIRST[PilotLoadStateFormat.ConfigIndex], loadee]; [] _ BcdOps.ProcessModules[bcd, RelocateLinksForModule]; MBStorage.FreePages[realLinks]; }; ConvertLink: PROC [bl: BcdDefs.Link] RETURNS [PrincOps.ControlLink] = INLINE { RETURN[LOOPHOLE[bl]]}; END.