DIRECTORY BasicTime USING [FromPupTime, GMT], BcdDefs USING [ Base, BcdBase, CTHandle, CTIndex, CTNull, FPHandle, FPIndex, FTHandle, FTIndex, FTSelf, MTHandle, MTIndex, NameRecord, NameString, PackedString, SGHandle, SGIndex, SpaceID, SPHandle, SPIndex, VersionID, VersionStamp, ModuleIndex ], BcdOps USING [ProcessConfigs, ProcessSegs, ProcessModules, ProcessFramePacks, ProcessSpaces], FS USING [GetInfo, OpenFile, Open, Read, Error], Loader USING [ErrorType, IRItem], LoaderOps USING [Bind, Export, LinkSegmentLength, FrameList], LoadState USING [ Acquire, ConfigID, ConfigInfo, GlobalFrameToModule, local, ModuleIndex, ModuleInfo, NewConfig, Release, SetGlobalFrame, SetType], IO USING [STREAM, ROS, PutChar, RopeFromROS], PrincOps USING [ ControlModule, CSegPrefix, GlobalFrameHandle, LastAVSlot, MainBodyIndex, NullControl, wordsPerPage], PrincOpsUtils USING [ ZERO, BITAND, Codebase, FrameSize, GetReturnLink, GlobalFrame, MakeFsi, Alloc, LowHalf, Free], Rope USING [ROPE, Find, Concat], SafeStorage USING [Type], SafeStorageOps USING [AcquireTypesAndLiterals], SystemVersion USING [bootFileDate], VM USING [ AddressForPageNumber, Allocate, CantAllocate, Free, Interval, MakeReadOnly, PageNumber, PageNumberForAddress, PagesForWords, Pin, Unpin, WordsForPages]; CedarLoaderImpl: MONITOR IMPORTS BasicTime, BcdOps, FS, IO, LoaderOps, LoadState, PrincOpsUtils, Rope, SafeStorageOps, SystemVersion, VM EXPORTS Loader, LoaderOps = BEGIN OPEN BcdDefs, BcdOps, Rope; FrameList: TYPE = LoaderOps.FrameList; GlobalFrameHandle: TYPE = PrincOps.GlobalFrameHandle; ControlModule: TYPE = PrincOps.ControlModule; SGList: TYPE = REF SGListObj; SGItem: TYPE = RECORD [ sgh: SGHandle, interval: VM.Interval, file: FS.OpenFile, bcdBase: INT ]; SGListObj: TYPE = RECORD[seq: SEQUENCE maxLength: CARDINAL OF SGItem]; CMMap: TYPE = REF CMMapObj; CMMapObj: TYPE = RECORD [seq: SEQUENCE maxLength: NAT OF CMMapItem]; CMMapItem: TYPE = RECORD [cti: CTIndex, cm: PrincOps.ControlModule, level: CARDINAL]; PaintedTime: TYPE = RECORD[BasicTime.GMT]; Error: PUBLIC ERROR[type: Loader.ErrorType, message: ROPE _ NIL] = CODE; Instantiate: PUBLIC PROC[file: FS.OpenFile, pageOffset: INT _ 0, codeLinks: BOOL _ TRUE] RETURNS[cm: PrincOps.ControlModule, unboundImports: LIST OF Loader.IRItem] = { msg: ROPE _ NIL; t: Loader.ErrorType; BEGIN ENABLE { Error => {t _ type; msg _ message; GOTO unwound}; VM.CantAllocate => {t _ insufficientVM; GOTO unwound}; }; [cm, unboundImports] _ LoaderEntry[file, pageOffset, codeLinks]; EXITS unwound => ERROR Error[t, msg]; END; }; Start: PUBLIC PROC [cm: PrincOps.ControlModule] = { IF cm # LOOPHOLE[PrincOps.NullControl] THEN START LOOPHOLE[cm, PROGRAM]; }; MakeProcedureResident: PUBLIC SAFE PROC[proc: PROC ANY RETURNS ANY] = TRUSTED { LoadState.local.Acquire[]; -- acquire the lock on the loadstate BEGIN ENABLE {UNWIND => NULL; ANY => LoadState.local.Release[]}; VM.Pin[IntervalForProc[proc]]; END; LoadState.local.Release[]; }; MakeProcedureSwappable: PUBLIC PROC[proc: PROC ANY RETURNS ANY] = { LoadState.local.Acquire[]; -- acquire the lock on the loadstate BEGIN ENABLE {UNWIND => NULL; ANY => LoadState.local.Release[]}; VM.Unpin[IntervalForProc[proc]]; END; LoadState.local.Release[]; }; MakeGlobalFrameResident: PUBLIC SAFE PROC[proc: PROC ANY RETURNS ANY] = TRUSTED { VM.Pin[IntervalForGlobalFrame[proc]]; }; MakeGlobalFrameSwappable: PUBLIC PROC[proc: PROC ANY RETURNS ANY] = { VM.Unpin[IntervalForGlobalFrame[proc]]; }; IntervalForProc: PROC [proc: PROC ANY RETURNS ANY] RETURNS [VM.Interval] = { gfh: PrincOps.GlobalFrameHandle = LOOPHOLE[PrincOpsUtils.GlobalFrame[proc]]; codeBase: LONG POINTER = PrincOpsUtils.Codebase[gfh]; bcd: BcdDefs.BcdBase; config: LoadState.ConfigID; module: LoadState.ModuleIndex; mtb: BcdDefs.Base; mth: BcdDefs.MTHandle; sgb: BcdDefs.Base; [config, module] _ LoadState.local.GlobalFrameToModule[gfh]; bcd _ LoadState.local.ConfigInfo[config].bcd; sgb _ LOOPHOLE[bcd + bcd.sgOffset]; mtb _ LOOPHOLE[bcd + bcd.mtOffset]; mth _ @mtb[LoadState.local.ModuleInfo[config, module].mti]; IF ~mth.packageable OR mth.code.packed THEN ERROR; -- not yet implemented. RETURN[[VM.PageNumberForAddress[codeBase], sgb[mth.code.sgi].pages]] }; IntervalForGlobalFrame: PROC [proc: PROC ANY RETURNS ANY] RETURNS [VM.Interval] = { gfh: PrincOps.GlobalFrameHandle = LOOPHOLE[PrincOpsUtils.GlobalFrame[proc]]; codeBase: LONG POINTER TO PrincOps.CSegPrefix = PrincOpsUtils.Codebase[gfh]; pGFSize: LONG POINTER TO CARDINAL = LOOPHOLE[codeBase + CARDINAL[codeBase.entry[PrincOps.MainBodyIndex].initialpc] - 1]; nLinks: CARDINAL = codeBase.header.info.nlinks; linkspace: CARDINAL = IF gfh.codelinks THEN 0 ELSE nLinks + PrincOpsUtils.BITAND[-LOOPHOLE[nLinks, INTEGER], 3B]; nWords: CARDINAL = pGFSize^ + linkspace; RETURN[[VM.PageNumberForAddress[gfh-linkspace], VM.PagesForWords[nWords]]] }; BCDBuildTime: PUBLIC SAFE PROC[proc: PROC ANY RETURNS ANY _ NIL] RETURNS[BasicTime.GMT] = TRUSTED { ref: REF ANY; IF proc = NIL THEN proc _ LOOPHOLE[PrincOpsUtils.GetReturnLink[]]; LoadState.local.Acquire[]; BEGIN ENABLE {UNWIND => NULL; ANY => LoadState.local.Release[]}; gfh: PrincOps.GlobalFrameHandle = LOOPHOLE[PrincOpsUtils.GlobalFrame[proc]]; ref _ LoadState.local.ConfigInfo[LoadState.local.GlobalFrameToModule[gfh].config].ref; END; LoadState.local.Release[]; IF ref = NIL THEN RETURN[BasicTime.FromPupTime[SystemVersion.bootFileDate]] ELSE RETURN[NARROW[ref, REF PaintedTime]^] }; LoaderEntry: ENTRY PROC[ file: FS.OpenFile, pageOffset: INT, codeLinks: BOOL] RETURNS [cm: PrincOps.ControlModule, unboundImports: LIST OF Loader.IRItem] = { ENABLE UNWIND => NULL; [cm, unboundImports] _ New[LoadBcd[file, pageOffset], file, pageOffset, ~codeLinks]; }; LoadBcd: INTERNAL PROC[file: FS.OpenFile, pageOffset: INT] RETURNS [bcd: BcdBase] = { bcdSpace: VM.Interval; pages, rtPages: INT; bcdSpace _ VM.Allocate[count: 1]; bcd _ VM.AddressForPageNumber[bcdSpace.page]; FS.Read[file: file, from: pageOffset, nPages: 1, to: bcd]; IF bcd.versionIdent # VersionID OR bcd.definitions OR ~bcd.spare1 THEN {VM.Free[bcdSpace]; ERROR Error[invalidBcd]}; pages _ bcd.nPages; rtPages _ bcd.rtPages.pages; IF pages > 1 THEN { VM.Free[bcdSpace]; bcdSpace _ VM.Allocate[count: pages]; bcd _ VM.AddressForPageNumber[bcdSpace.page]; FS.Read[file: file, from: pageOffset, nPages: pages, to: bcd]; }; VM.MakeReadOnly[bcdSpace]; }; New: INTERNAL PROC[ bcd: BcdBase, file: FS.OpenFile, pageOffset: INT, framelinks: BOOL] RETURNS[cm: PrincOps.ControlModule, unboundImports: LIST OF Loader.IRItem] = { fl: FrameList _ NIL; cid: LoadState.ConfigID; LoadState.local.Acquire[exclusive]; -- acquire the lock on the loadstate cid _ LoadState.local.NewConfig[bcd, NEW[PaintedTime _ [FS.GetInfo[file].created]]]; BEGIN ENABLE { UNWIND => NULL; ANY => { LoadState.local.Release[commit: FALSE]; ReleaseFrames[fl, cid]; }; }; moduleToGFH: PROC[mx: ModuleIndex] RETURNS[PrincOps.GlobalFrameHandle] = {RETURN[LoadState.local.ModuleInfo[cid, mx].gfh]}; setType: PROC[gfh: PrincOps.GlobalFrameHandle, type: SafeStorage.Type] = {LoadState.local.SetType[gfh, type]}; fl _ CreateGlobalFrames[cid, framelinks]; AssignCodeToFrames[cid, file, pageOffset]; cm _ AssignControlModules[cid]; unboundImports _ LoaderOps.Bind[cid]; LoaderOps.Export[cid]; SafeStorageOps.AcquireTypesAndLiterals[bcd, moduleToGFH, setType]; END; -- ENABLE UNWIND LoadState.local.Release[]; --XXX deadlock with TandS }; -- end New CreateGlobalFrames: PUBLIC PROC[cid: LoadState.ConfigID, allframelinks: BOOL] RETURNS[fl: FrameList _ NIL] = { bcd: BcdBase = LoadState.local.ConfigInfo[cid].bcd; f: FrameList; frames: POINTER; space: CARDINAL; single: BOOL _ (bcd.nModules = 1); resident: BOOL; GetFrameSizes: PROC [mth: MTHandle] = { IF allframelinks OR mth.linkLoc = frame OR ~mth.code.linkspace THEN space _ space + LoaderOps.LinkSegmentLength[mth, bcd]; space _ NextMultipleOfFour[space] + mth.framesize; resident _ resident OR mth.residentFrame;}; FrameInit: PROC [mth: MTHandle] = { frame: GlobalFrameHandle; framelinks: BOOL _ allframelinks OR mth.linkLoc = frame OR ~mth.code.linkspace; IF framelinks THEN frames _ frames + LoaderOps.LinkSegmentLength[mth, bcd]; frame _ NextMultipleOfFour[frames]; frames _ frame + mth.framesize; LoadState.local.SetGlobalFrame[cid, mth.gfi, frame]; frame^ _ [gfi: frame.gfi, copied: FALSE, alloced: single, shared: FALSE, started: FALSE, trapxfers: FALSE, codelinks: ~framelinks, global:, code:];}; DoFramePack: PROC [fph: FPHandle, fpi: FPIndex] RETURNS [stop: BOOL _ FALSE] = { mtb: Base = LOOPHOLE[bcd + bcd.mtOffset]; space _ 0; resident _ FALSE; FOR i: CARDINAL IN [0..fph.length) DO GetFrameSizes[@mtb[fph.modules[i]]] ENDLOOP; [f, frames] _ AllocateFrames[size: NextMultipleOfFour[space], single: single, resident: resident]; f.rest _ fl; fl _ f; FOR i: CARDINAL IN [0..fph.length) DO FrameInit[@mtb[fph.modules[i]]] ENDLOOP;}; OtherFrameSizes: PROC [mth: MTHandle, mti: MTIndex] RETURNS[stop: BOOL _ FALSE] = { IF LoadState.local.ModuleInfo[cid, mth.gfi].gfh = NIL THEN GetFrameSizes[mth];}; OtherFrameInit: PROC [mth: MTHandle, mti: MTIndex] RETURNS[stop: BOOL _ FALSE] = { IF LoadState.local.ModuleInfo[cid, mth.gfi].gfh = NIL THEN FrameInit[mth];}; BEGIN ENABLE UNWIND => ReleaseFrames[fl, cid]; [] _ BcdOps.ProcessFramePacks[bcd, DoFramePack]; space _ 0; resident _ FALSE; [] _ BcdOps.ProcessModules[bcd, OtherFrameSizes]; IF space # 0 THEN { [f, frames] _ AllocateFrames[size: NextMultipleOfFour[space], single: single, resident: resident]; f.rest _ fl; fl _ f; [] _ BcdOps.ProcessModules[bcd, OtherFrameInit]; }; END; -- ENABLE UNWIND }; -- end CreateGlobalFrames AllocateFrames: PUBLIC PROC [size: CARDINAL, single, resident: BOOL] RETURNS [fl: FrameList, frames: POINTER] = { IF single THEN { index: CARDINAL; FOR index IN [0..PrincOps.LastAVSlot] DO IF PrincOpsUtils.FrameSize[index] >= size THEN EXIT; ENDLOOP; frames _ PrincOpsUtils.Alloc[index]; [] _ PrincOpsUtils.ZERO[LONG[frames], size]; fl _ CONS[[frame[ptr: frames]], NIL]; } ELSE { pages: INT = VM.PagesForWords[size]; interval: VM.Interval _ VM.Allocate[count: pages, partition: mds]; IF resident THEN VM.Pin[interval]; frames _ LOOPHOLE[PrincOpsUtils.LowHalf[VM.AddressForPageNumber[interval.page]], POINTER]; [] _ PrincOpsUtils.ZERO[LONG[frames], VM.WordsForPages[pages]]; fl _ CONS[[mdsInterval[interval: interval]], NIL]; }; }; NextMultipleOfFour: PROC [n: UNSPECIFIED] RETURNS [UNSPECIFIED] = INLINE {RETURN[n + PrincOpsUtils.BITAND[-LOOPHOLE[n, INTEGER], 3B]]}; ReleaseFrames: PUBLIC PROC [fl: FrameList, cid: LoadState.ConfigID] = { FOR f: FrameList _ fl, f.rest UNTIL f = NIL DO WITH v: f.first SELECT FROM frame => PrincOpsUtils.Free[v.ptr]; mdsInterval => VM.Free[v.interval]; ENDCASE; ENDLOOP; }; AssignCodeToFrames: PUBLIC PROC [ config: LoadState.ConfigID, bcdCap: FS.OpenFile, pageOffset: INT--within file--] = { sgList: SGList; allCodeInSelf: BOOL; bcd: BcdBase = LoadState.local.ConfigInfo[config].bcd; GetCode: PROC [mth: MTHandle, mti: MTIndex] RETURNS [BOOL] = { frame: PrincOps.GlobalFrameHandle = LoadState.local.ModuleInfo[config, mth.gfi].gfh; IF mth.altoCode THEN InvalidModule[bcd, mth]; frame.code.longbase _ SgiToLP[bcd, mth.code.sgi, sgList] + mth.code.offset; frame.code.out _ TRUE; RETURN[FALSE]; }; [sgList, allCodeInSelf] _ FindSegments[bcd, bcdCap, pageOffset]; IF bcd.nModules = 1 THEN AllocateCodeSpace[bcd, sgList, pageOffset, bcdCap] ELSE AllocateCodeSpaces[bcd, sgList, allCodeInSelf]; [] _ BcdOps.ProcessModules[bcd, GetCode ! UNWIND => ReleaseCode[sgList]]; }; -- end AssignCodeToFrames ReleaseCode: PROC [sgList: SGList] = { FOR i: CARDINAL _ 0, i+1 UNTIL i = sgList.maxLength DO VM.Free[sgList[i].interval] ENDLOOP; }; FindSegments: PROC [bcd: BcdBase, bcdCap: FS.OpenFile, pageOffset: INT--page number--] RETURNS [sgList: SGList, allCodeInSelf: BOOL _ TRUE] = BEGIN n: CARDINAL; sgItem: SGItem; GetFileFromSGH: PROC [sgh: SGHandle] RETURNS [file: FS.OpenFile _ [NIL]] = { fth: FTHandle = @LOOPHOLE[bcd + bcd.ftOffset, Base][sgh.file]; name: ROPE _ NameToRope[ssb: LOOPHOLE[bcd + bcd.ssOffset], name: fth.name]; dot: BOOL _ Rope.Find[name, "."] # -1; bcd: BcdBase; interval: VM.Interval; IF ~dot THEN name _ Rope.Concat[name, ".bcd"]; file _ FS.Open[name: name ! FS.Error => CONTINUE]; IF file = FS.OpenFile[NIL] THEN ERROR Error[fileNotFound, name]; interval _ VM.Allocate[count: 1]; bcd _ LOOPHOLE[VM.AddressForPageNumber[interval.page]]; FS.Read[file: file, from: 0, nPages: 1, to: bcd]; IF fth.version # bcd.version THEN { VM.Free[interval]; ERROR Error[versionMismatch, name]; }; VM.Free[interval]; }; CountSegs: PROC [sgh: SGHandle, sgi: SGIndex] RETURNS [BOOL] = { IF sgh.class # code THEN RETURN[FALSE]; IF sgh.file # FTSelf THEN allCodeInSelf _ FALSE; n _ n + 1; RETURN[FALSE]; }; AddSeg: PROC [sgh: SGHandle, sgi: SGIndex] RETURNS [BOOL] = { file: FS.OpenFile; base: INT; IF sgh.class # code THEN RETURN[FALSE]; IF sgh.file = FTSelf THEN {file _ bcdCap; base _ pageOffset} ELSE {file _ GetFileFromSGH[sgh]; base _ 0}; sgList[n] _ [sgh: sgh, interval: [0, 0], file: file, bcdBase: base]; 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 _ NEW[SGListObj[n]]; n _ 0; [] _ BcdOps.ProcessSegs[bcd, AddSeg]; IF allCodeInSelf THEN { FOR n DECREASING IN [1..sgList.maxLength/2] DO SiftUp[n, sgList.maxLength] ENDLOOP; FOR n DECREASING IN [1..sgList.maxLength) DO sgItem _ sgList[1 - 1]; sgList[1 - 1] _ sgList[n + 1 - 1]; sgList[n + 1 - 1] _ sgItem; SiftUp[1, n]; ENDLOOP; }; END; -- end FindSegments NameToRope: PROC [ssb: NameString, name: NameRecord] RETURNS[ans: ROPE] = { s: IO.STREAM = IO.ROS[]; FOR i: NAT IN [0..ssb.size[name]) DO s.PutChar[ssb.string.text[name+i]] ENDLOOP; ans _ s.RopeFromROS[]; }; AllocateCodeSpace: PROC [bcd: BcdBase, sgList: SGList, pageOffset: INT, bcdCap: FS.OpenFile] = { interval: VM.Interval; mth: MTHandle; pages, biaspages: CARDINAL; IF sgList.maxLength ~= 1 THEN ERROR; mth _ @LOOPHOLE[bcd + bcd.mtOffset, Base][FIRST[MTIndex]]; biaspages _ IF mth.linkLoc = code THEN (LoaderOps.LinkSegmentLength[mth, bcd]/PrincOps.wordsPerPage)+1 ELSE 0; pages _ sgList[0].sgh.pages; interval _ VM.Allocate[count: pages + biaspages, in64K: TRUE]; -- won't cross a 64K VM bdry FS.Read[ file: bcdCap, from: pageOffset + sgList[0].sgh.base - 1, nPages: pages + biaspages, to: VM.AddressForPageNumber[interval.page] ]; VM.MakeReadOnly[interval]; sgList[0].interval _ interval; }; AllocateCodeSpaces: PROC [bcd: BcdBase, sgList: SGList, allCodeInSelf: BOOL] = { start, end, startBase, pages: CARDINAL; pageOfInterval: VM.PageNumber; interval: VM.Interval; start _ end _ 0; DO startBase _ sgList[start].sgh.base; pages _ sgList[start].sgh.pages; DO end _ end + 1; IF end = sgList.maxLength OR pages + sgList[end].sgh.pages > 255 OR ~ allCodeInSelf THEN EXIT; pages _ pages + sgList[end].sgh.pages; ENDLOOP; interval _ VM.Allocate[count: pages, in64K: TRUE]; FS.Read[ file: sgList[start].file, from: sgList[start].bcdBase + sgList[start].sgh.base - 1, nPages: pages, to: VM.AddressForPageNumber[interval.page] ]; VM.MakeReadOnly[interval]; pageOfInterval _ interval.page; FOR index: CARDINAL IN [start..end) DO sgh: SGHandle = sgList[index].sgh; sph: SPHandle _ FindSPHandle[bcd, sgh]; subInterval: VM.Interval; IF sph = NIL THEN subInterval _ [page: pageOfInterval, count: sgh.pages] ELSE { FOR sp: CARDINAL DECREASING IN [0..sph.length) DO subInterval _ [page: pageOfInterval + sph.spaces[sp].offset, count: sph.spaces[sp].pages]; IF sph.spaces[sp].resident THEN VM.Pin[subInterval]; ENDLOOP; }; sgList[index].interval _ subInterval; pageOfInterval _ pageOfInterval + sgh.pages; ENDLOOP; IF end = sgList.maxLength THEN EXIT ELSE start _ end; ENDLOOP; }; -- end AllocateCodeSpaces FindSPHandle: PUBLIC PROC [bcd: BcdBase, sgh: SGHandle] RETURNS [sph: SPHandle] = { sgb: Base = LOOPHOLE[bcd + bcd.sgOffset]; proc: PROC [sph: SPHandle, spi: SPIndex] RETURNS [stop: BOOL] = {RETURN[@sgb[sph.seg] = sgh]}; RETURN[BcdOps.ProcessSpaces[bcd: bcd, proc: proc].sph]; }; SgiToLP: PROC[bcd: BcdBase, sgi: SGIndex, sgList: SGList] RETURNS[LONG POINTER] = { sgb: Base = LOOPHOLE[bcd + bcd.sgOffset]; FOR i: CARDINAL IN [0..sgList.maxLength) DO IF @sgb[sgi] = sgList[i].sgh THEN RETURN[VM.AddressForPageNumber[sgList[i].interval.page]]; ENDLOOP; RETURN[NIL]; }; InvalidModule: PROC [bcd: BcdBase, mth: MTHandle] = { name: ROPE = NameToRope[ssb: LOOPHOLE[bcd + bcd.ssOffset], name: mth.name]; ERROR Error[invalidBcd, name]; }; AssignControlModules: PUBLIC PROC[cid: LoadState.ConfigID] RETURNS [cm: PrincOps.ControlModule] = { OPEN PrincOps; bcd: BcdBase _ LoadState.local.ConfigInfo[cid].bcd; ctb: Base _ LOOPHOLE[bcd + bcd.ctOffset]; mtb: Base _ LOOPHOLE[bcd + bcd.mtOffset]; cti: CTIndex; mapIndex, maxLevel: NAT _ 0; i: NAT; cmMap: CMMap; MapControls: PROC[cth: CTHandle, cti: CTIndex] RETURNS[stop: BOOL _ FALSE] = { OPEN PrincOpsUtils; cm: ControlModule; level: CARDINAL _ 0; IF cth.nControls = 0 THEN cm _ NullControl ELSE { cm.list _ PrincOpsUtils.Alloc[ MakeFsi[cth.nControls + SIZE[CARDINAL] + SIZE[ControlModule]]]; cm.list.nModules _ cth.nControls + 1; FOR i: CARDINAL IN [0..cth.nControls) DO WITH ci: cth.controls[i] SELECT FROM module => cm.list.frames[i+1] _ LoadState.local.ModuleInfo[cid, mtb[ci.mti].gfi].gfh; config => ERROR; ENDCASE => ERROR; ENDLOOP; cm.multiple _ TRUE; }; FOR c: CTIndex _ ctb[cti].config, ctb[c].config UNTIL c = CTNull DO level _ level + 1 ENDLOOP; cmMap[mapIndex] _ [cti: cti, cm: cm, level: level]; mapIndex _ mapIndex + 1; maxLevel _ MAX[maxLevel, level]; }; -- end MapControls GetControl: PROC [mth: MTHandle, mti: MTIndex] RETURNS [BOOL] = { OPEN PrincOps, PrincOpsUtils; frame: GlobalFrameHandle _ LoadState.local.ModuleInfo[cid, mth.gfi].gfh; IF mth.config # cti THEN RETURN[FALSE]; IF frame.global[0] = NullControl THEN frame.global[0] _ GetModule[cm]; RETURN[FALSE]; }; -- end GetControl IF bcd.nModules = 1 THEN { frame: GlobalFrameHandle _ LoadState.local.ModuleInfo[cid, 1].gfh; frame.global[0] _ NullControl; RETURN[[frame[frame]]]; }; cmMap _ NEW[CMMapObj[bcd.nConfigs]]; [] _ 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) = NullControl THEN LOOP; list.multiple _ FALSE; IF (cti _ ctb[cmMap[index].cti].config) = CTNull THEN cm _ 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 = CTNull THEN { cm _ GetModule[cmMap[i].cm]; EXIT}; ENDLOOP; }; -- end AssignControlModules SetLink: PROC[cm: ControlModule, frame: GlobalFrameHandle] RETURNS [ControlModule] = { t: ControlModule = frame.global[0]; frame.global[0] _ cm; RETURN[IF t = PrincOps.NullControl THEN [frame[frame]] ELSE t]; }; GetModule: PROC [cm: ControlModule] RETURNS [ControlModule] = { list: ControlModule; DO IF ~cm.multiple THEN RETURN[cm]; list _ cm; list.multiple _ FALSE; cm.frame _ list.list.frames[1]; ENDLOOP; }; END. ŠCedarLoaderImpl.mesa This module handles all of parts of loading that don't have anything to do with links: copying the bcd into VM, creating global frames for each module, associating code with each frame, and initializing the start trap cm's. Linking is handled by LoaderOps.Export and LoaderOps.Bind. Edited by Sandman on October 21, 1980 10:57 AM Edited by Forrest on October 25, 1980 7:45 PM Edited by John Maxwell on February 28, 1983 1:38 pm Last Edited by: Birrell, August 24, 1983 5:13 pm Last Edited by: Schroeder, August 3, 1983 8:56 am Last Edited by: Levin, September 22, 1983 1:52 pm Edited by Paul Rovner on August 17, 1983 4:34 pm Edited by MBrown on September 11, 1983 12:52 pm ********************************************************** public procedures ********************************************************** pageOffset: offset within the file of first page of the BCD, normally 0 ********************************************************** The central loading procedures. LoadBcd copies the bcd into VM, and New calls the procedures that do the work. ********************************************************** START New HERE ********************************************************** CreateGlobalFrames allocates and initializes global frames for the modules in the bcd, constructs the loadstate info for these modules and returns the list of frames. ********************************************************** Start CreateGlobalFrames HERE ********************************************************** Frame allocation/deallocation ********************************************************** ********************************************************** AssignCodeToFrames: Makes up a list of code segments, maps them in, and associates each code segment with the appropriate global frame. ********************************************************** MatchCSeg: PROC [mmth: MTHandle, mmti: MTIndex] RETURNS [BOOL] = { IF mth # mmth AND mth.code.sgi = mmth.code.sgi AND mth.code.offset = mmth.code.offset THEN frame.shared _ LoadState.local.ModuleInfo[config, mmth.gfi].gfh.shared _ TRUE; RETURN[FALSE]; }; Don't do the MatchCSeg stuff; Roy and I (Andrew) think it does no good, and it costs an n-squared enumeration of the modules! [] _ BcdOps.ProcessModules[bcd, MatchCSeg]; START AssignCodeToFrames HERE called only from AssignCodeToFrames START FindSegments HERE this is a bcd produced by the compiler non-0 if code links ncodepages _ pages + biaspages; if the bcd is being loaded with code links, the cedar compiler will have left room for them Hmm. Does this work? who remembers subInterval; apparently only the last one is remembered (below) for this sgList entry. Is it the "first" one? ********************************************************** AssignControlModules: determines start trap links for each global frame. ********************************************************** START AssignControlModules HERE Êg˜Jšœ™JšœV™VJšœA™AJšœH™HJšœ;™;Jšœ/™/Jšœ.™.Jšœ3™3J™0J™1J™1Jšœ0™0Jšœ/™/šÏk ˜ Jšœ œœ˜#šœœ˜J˜äJ˜—JšœœQ˜]Jšœœ(˜0Jšœœ˜!Jšœ œ.˜=šœ œ˜Jšœ˜—Jšœœœœ˜-šœ œ˜Jšœd˜d—šœœ˜JšœœR˜^—Jšœœœ˜ Jšœ œ˜Jšœœ˜/Jšœœ˜#šœœ˜ Jšœ˜˜˜—J˜—J˜Jšœ˜JšœœœL˜oJšœ˜J˜Jšœœ˜!J˜Jšœ œ˜&J˜Jšœœ˜5Jšœœ˜-J˜Jšœœœ ˜šœœœ˜Jšœ˜Jšœ œ ˜Jšœœ ˜Jšœ ˜ Jšœ˜—Jš œ œœœ œœ ˜FJ˜Jšœœœ ˜Jš œ œœœ œœ ˜DJšœ œœ3œ˜UJ˜Jšœ œœ œ˜*J˜Jšœ:™:Jšœ™Jšœ:™:J˜š œœœ"œœœ˜HJ˜—šÏn œœœœœœ œœ˜Xšœ-œœ˜NJšœG™G—Jšœœœ˜Jšœ˜š˜šœ˜Jšœ#œ ˜1Jšœ&œ ˜6J˜—Jšœ@˜@Jšœ œ˜%—Jšœ˜šœ˜J˜—J˜—šžœœœ!˜3Jš œœœœœœ˜HJšœ˜J˜—šžœœœœœœœœœ˜OJšœÏc$˜@š œœœœœ˜@Jšœ˜Jšœ˜—Jšœ˜Jšœ˜—J˜šžœœœœœœœ˜CJšœŸ$˜@š œœœœœ˜@Jšœ˜ Jšœ˜—Jšœ˜Jšœ˜—J˜šžœœœœœœœœœ˜QJšœ#˜%Jšœ˜—J˜šžœœœœœœœ˜EJšœ%˜'Jšœ˜J˜—šžœœœœœœœœ˜LJšœ"œ"˜LJšœ œœ˜5Jšœ˜Jšœ˜Jšœ˜Jšœ˜J˜Jšœ˜Jšœ<˜—Jšœœ˜(Jšœœ&œ˜JJ˜J˜—šž œœœœœœœœœ˜@Jšœ œœ˜"Jšœœœ˜ Jšœœœœ ˜BJ˜š œœœœœ˜@Jšœ"œ"˜LJšœV˜VJšœ˜—J˜Jšœœœœ3˜KJšœœœœ˜*Jšœ˜J˜—Jšœ:™:Jšœ@™@Jšœ.™.Jšœ:™:J˜šž œœœ˜Jšœœ ˜Jšœ œ˜Jšœ œ˜Jšœ.œœ˜OJšœœœ˜JšœT˜T˜J˜——š žœœœœœ˜:Jšœ˜Jšœ œ ˜Jšœœ˜Jšœ œ˜!Jšœœ%˜-Jšœ8˜:šœœœ ˜AJšœœœ˜2—J˜J˜šœ œ˜Jšœ˜Jšœ œ˜%Jšœœ%˜-Jšœ<˜>J˜—Jšœ˜Jšœ˜J˜—šžœœœ˜Jšœœœœ˜CJšœ-œœ˜NJ˜Jšœœ˜Jšœ˜˜Jšœ™—Jšœ%Ÿ$˜IJšœ%œœ˜Tš˜š˜Jšœœ˜šœ˜Jšœ œ˜'Jšœ˜Jšœ˜—J˜—šœ œœ˜HJšœœ+˜2—šœ œ;˜HJšœ%˜%—Jšœ)˜)Jšœ*˜*Jšœ˜Jšœ%˜%Jšœ˜JšœB˜B—JšœŸ˜JšœŸ˜5šœŸ ˜ J˜——J™Jšœ:™:JšœJ™JJšœK™KJšœ™Jšœ:™:J˜šžœ œ)œ˜MJšœœ˜ Jšœ3˜3Jšœ ˜ Jšœœ˜Jšœœ˜Jšœœ˜"Jšœ œ˜šž œœ˜'šœœœ˜>Jšœ7˜;—J˜2Jšœœ˜+—šž œœ˜#J˜Jšœ œœœ˜OJšœ œ9˜KJ˜#J˜Jšœ4˜4šœ˜šœœœ œ˜QJšœ œ,˜=———š ž œœœœœ˜PJšœ œ˜)J˜ Jšœ œ˜Jš œœœœ%œ˜R˜ J˜V—J˜ J˜Jš œœœœ!œ˜P—šžœœ˜3Jšœœœ˜Jšœ0œœ˜P—šžœœ˜2Jšœœœ˜Jšœ0œœ˜L—J™Jšœ™šœœœ˜.J˜0J˜ Jšœ œ˜J˜1šœ œ˜˜ J˜V—J˜ J˜J˜0J˜——JšœŸ˜šœŸ˜J˜——J™Jšœ:™:Jšœ™Jšœ:™:J˜š žœœœœœ˜DJšœœ˜,Jšœ˜ šœ˜Jšœœ˜šœœ˜%Jš œœ(œœœ˜@—Jšœ$˜$Jšœœœ˜,Jšœœœ˜%Jšœ˜—šœ˜Jšœœœ˜$JšœB˜BJšœ œ˜"šœ˜Jšœœœ'œ˜S—Jšœœœ œ˜?Jšœœ$œ˜2Jšœ˜—Jšœ˜J˜—Jš žœœ œœ œ˜AJš œœœœœ ˜EJ˜šž œœœ-˜Gšœœ˜+š˜šœ œ˜Jšœ#˜#Jšœœ˜#Jšœ˜——Jšœ˜—šœ˜J˜——Jšœ:™:JšœE™EJšœC™CJšœ:™:J˜šžœœœ˜!Jšœ$œŸœ˜TJ˜Jšœœ˜Jšœ6˜6J˜šžœœœœ˜>šž œœ!œœ™Bšœ ™ Jšœ™ Jšœœ™&—š™JšœIœ™N—Jšœœ™Jšœ™—JšœT˜TJšœœ˜-J˜KJšœœ˜Jšœ~™~Jšœ+™+Jšœœ˜Jšœ˜—J˜Jšœ™Jšœ@˜@šœ˜Jšœ3˜7Jšœ0˜4—Jšœ*œ˜IšœŸ˜J˜——šž œœ˜&Jš œœ œœœœ˜[Jšœ˜—™Jšœ#™#—š ž œœœŸœ˜WJšœ!œœ˜6Jš˜Jšœœ˜ J˜J˜š žœœœœ œ˜LJšœœ%˜>Jšœœœ&˜KJšœœ˜&J˜ J˜J˜Jšœœ"˜.Jšœ(œ˜2š œœ œœœ˜@J˜—Jšœ!˜!Jšœœœ&˜7Jšœ/˜1šœœ˜#Jšœ˜Jšœ˜#Jšœ˜—Jšœ˜J˜J˜—šž œœœœ˜@Jšœœœœ˜'Jšœœœ˜0J˜ Jšœœ˜Jšœ˜—J˜šžœœœœ˜=Jšœœ ˜Jšœœ˜ Jšœœœœ˜'šœ˜Jšœ#˜'Jšœ(˜,—JšœD˜DJ˜ Jšœœ˜Jšœ˜—J˜šžœœ œ˜&Jšœœ˜J˜J˜š˜Jšœ œœ˜šœœ'˜;Jšœœ ˜ —Jšœ˜Jšœ3œœ˜?J˜J˜ J˜J˜Jšœ˜—Jš˜Jšœ˜—J˜Jšœ™J˜J˜(Jšœ œ˜J˜J˜%šœœ˜Jš œ œœœœ˜Sšœ œœ˜)š˜J˜J˜"J˜J˜ —Jš˜—Jšœ˜—šœŸ˜J˜——šž œœ$˜4Jšœœ˜Jš œœœœœ˜Jš œœœœ$œ˜PJšœ˜šœ˜J˜——šžœœ+œ œ ˜\Jšœ˜Jšœ&™&J˜Jšœ˜Jšœœ˜Jšœœœ˜$Jšœœœ ˜:Jšœ™šœ œ˜"JšœA˜EJšœ˜—Jšœ˜Jšœ™Jšœ œ+œŸ˜\Jšœ[™[šœ˜Jšœ ˜ Jšœ*˜*Jšœ˜Jšœœ$˜*Jšœ˜—Jšœ˜Jšœ˜šœ˜J˜——šžœœ/œ˜PJšœœ˜'Jšœ˜J˜Jšœ˜š˜J˜#J˜ š˜J˜šœœ%œ˜TJšœœ˜ —J˜&Jšœ˜—Jšœ œœ˜2šœ˜Jšœ˜Jšœ9˜9Jšœ˜Jšœœ$˜*Jšœ˜—Jšœ˜Jšœ˜šœœœ˜&J˜"J˜'J˜šœ˜ Jšœ7˜;šœ˜š œœ œœ˜1šœ ˜ JšœL˜LJšœ‘™‘—Jšœœœ˜4—Jš˜Jšœ˜——Jšœ%˜%Jšœ,˜,—Jšœ˜Jšœœœœ ˜5—Jšœ˜šœŸ˜J˜——šž œœœœ˜SJšœ œ˜)šœœ˜(Jšœœœ˜5—Jšœ1˜7šœ˜J˜——šžœœ,˜9Jšœœœ˜Jšœ œ˜)šœœœ˜+šœ˜Jšœœœ0˜>—Jšœ˜—Jšœœ˜ šœ˜J˜——šž œœ"˜5Jšœœœ&˜KJšœ˜šœ˜J˜——J™Jšœ:™:JšœH™HJšœ:™:J˜šžœ œ˜:Jšœ"œ ˜7Jšœ3˜3Jšœ œ˜)Jšœ œ˜)J˜ Jšœœ˜Jšœœ˜Jšœ ˜ J˜š ž œœœœœ˜NJšœ˜J˜Jšœœ˜šœ˜Jšœ˜šœ˜šœ˜Jšœœœœ˜?—J˜%šœœœ˜%š˜šœœ˜$šœ ˜ JšœK˜K—Jšœ œ˜Jšœœ˜——Jšœ˜—Jšœ˜Jšœ˜——šœ-œ ˜@Jšœœ˜—J˜3J˜Jšœ œ˜ šœŸ˜J˜——šž œœœœ˜AJšœ˜JšœH˜HJšœœœœ˜'Jšœœ!˜FJšœœ˜šœŸ˜J˜—Jšœ™—šœœ˜JšœB˜BJ˜Jšœ˜Jšœ˜—Jšœœ˜$J˜-š œœ œœ˜2šœœœ˜'J˜Jšœœ&œœ˜PJ˜ Jšœœ˜J˜=šœœœ˜-˜J˜L—Jšœ˜—J˜J˜,Jšœ˜—Jšœ˜—šœœœ˜'Jšœœ˜J˜Jšœ(œœ˜4Jšœœ˜Jšœ/œ˜Fšœ˜Jšœœœœœœœ˜MJ˜"—J˜Jšœ˜—šœœ˜šœ#œ˜+Jšœœ˜#—Jšœ˜—JšœŸ˜J˜—šžœœ-˜:Jšœ˜J˜#Jšœ˜Jšœœœœ˜?šœ˜J˜——šž œœœ˜?J˜š˜Jšœœœ˜ J˜ Jšœœ˜J˜—Jšœ˜šœ˜J˜——J˜Jšœ˜J˜J˜J˜J˜—…—Nt