<> <> <> <> <> <> <> <> <> DIRECTORY BcdDefs USING [ Base, CTIndex, CTNull, FPIndex, FPNull, FPRecord, FTIndex, FTSelf, MTIndex, NameRecord, PackedString, SGIndex, SpaceID, SPIndex, SPRecord, VersionID, VersionStamp], BcdOps USING [ BcdBase, CTHandle, FPHandle, FTHandle, MTHandle, NameString, ProcessConfigs, ProcessSegs, ProcessModules, SGHandle, SPHandle], CedarLinkerOps USING [Bind, Export, FreeSpace, GetSpace, LinkSegmentLength], DCSFileTypes USING [tLeaderPage], Directory USING [Lookup, Error], Environment USING [wordsPerPage], File USING [ Capability, GetAttributes, LimitPermissions, nullCapability, read, PageCount, PageNumber], Frame USING [Alloc], Heap USING [FreeMDSNode, MakeMDSNode, systemMDSZone], Inline USING [BITAND], Loader USING [Error, ErrorType], LoaderPrivate USING [NextMultipleOfFour], LongString USING [AppendString], MiscAlpha USING [alpha], Mopcodes USING [zALLOC, zFREE, zMISC], PilotLoaderOps USING [FrameItem], PilotLoadStateFormat USING [ConfigIndex, ModuleInfo, NullModule], PilotLoadStateOps USING [ InputLoadState, ConfigIndex, EnterModule, Map, ReleaseLoadState, UpdateLoadState], PrincOps USING [ ControlModule, GFTIndex, GFTNull, GlobalFrameHandle, LastAVSlot, NullControl], PrincOpsRuntime USING [EmptyGFTItem, GetFrame, GFT], RTLoader USING [AcquireTypesAndLiterals], Runtime USING [], RuntimeInternal USING [EnterGlobalFrame, FrameSize, MakeFsi], Space USING [ Create, defaultBase, defaultWindow, Delete, GetAttributes, GetHandle, Handle, LongPointer, Map, mds, nullHandle, PageFromLongPointer, Pointer, virtualMemory, WindowOrigin, wordsPerPage, PageCount, InsufficientSpace], SpecialSpace USING [CreateForCode, MakeResident], SubSys USING [Handle]; CedarLoaderImpl: MONITOR IMPORTS BcdOps, CedarLinkerOps, Directory, File, Frame, Heap, Inline, Loader, LoaderPrivate, PilotLoadStateOps, PrincOpsRuntime, RTLoader, RuntimeInternal, Space, SpecialSpace, String: LongString EXPORTS CedarLinkerOps, PilotLoaderOps, Loader, LoaderPrivate, Runtime, SubSys = BEGIN OPEN BcdDefs, BcdOps, LoaderPrivate; ConfigIndex: TYPE = PilotLoadStateOps.ConfigIndex; Map: TYPE = PilotLoadStateOps.Map; GlobalFrameHandle: TYPE = PrincOps.GlobalFrameHandle; ControlModule: TYPE = PrincOps.ControlModule; FrameList: TYPE = POINTER TO FrameItem; FrameItem: TYPE = PilotLoaderOps.FrameItem; <<**********************************************************>> <> <<**********************************************************>> Error: PUBLIC ERROR[type: Loader.ErrorType, message: LONG POINTER TO TEXT _ NIL] = CODE; LoadConfig: PUBLIC PROC [ file: File.Capability, offset: File.PageCount, codeLinks: BOOLEAN] RETURNS [PROGRAM] = {RETURN[LOOPHOLE[Load[file, offset, codeLinks]]]}; NewConfig: PUBLIC PROC [ file: File.Capability, offset: File.PageCount, codeLinks: BOOLEAN] = { [] _ Load[file, offset, codeLinks]}; RunConfig: PUBLIC PROC [ file: File.Capability, offset: File.PageCount, codeLinks: BOOLEAN] = { Run[Load[file, offset, codeLinks]]}; Run: PUBLIC PROC [handle: SubSys.Handle] = { cm: PROGRAM = LOOPHOLE[handle]; IF cm # LOOPHOLE[PrincOps.NullControl] THEN START cm}; Start: PUBLIC PROC [cm: PrincOps.ControlModule] = { IF cm # LOOPHOLE[PrincOps.NullControl] THEN START LOOPHOLE[cm, PROGRAM]}; Instantiate: PUBLIC PROC[file: File.Capability, offset: File.PageCount, <> <> codeLinks: BOOLEAN _ TRUE] RETURNS[cm: PrincOps.ControlModule, unboundImports: BOOLEAN] = {[cm, unboundImports] _ DoLoad[file, offset, codeLinks]}; Load: PUBLIC PROC[file: File.Capability, offset: File.PageCount, codeLinks: BOOLEAN _ FALSE] RETURNS [handle: SubSys.Handle] = {RETURN[LOOPHOLE[DoLoad[file, offset, codeLinks].cm]]}; <<>> <<**********************************************************>> <> <> <<**********************************************************>> DoLoad: PROC[file: File.Capability, offset: File.PageCount, codeLinks: BOOLEAN _ FALSE] RETURNS [cm: PrincOps.ControlModule, unboundImports: BOOLEAN] = {msg: STRING = [100]; {[cm, unboundImports] _ LoaderEntry[file, offset, codeLinks ! Error => {IF message # NIL THEN String.AppendString[msg, LOOPHOLE[message, LONG STRING]]; SELECT type FROM invalidBcd => GOTO invalidBcd; fileNotFound => GOTO fileNotFound; versionMismatch => GOTO versionMismatch; loadStateFull => GOTO loadStateFull; ENDCASE}; Space.InsufficientSpace => {GOTO insufficientVM}]; EXITS loadStateFull => ERROR Error[loadStateFull]; invalidBcd => ERROR Error[invalidBcd, LOOPHOLE[LONG[msg]]]; versionMismatch => ERROR Error[versionMismatch, LOOPHOLE[LONG[msg]]]; fileNotFound => ERROR Error[fileNotFound, LOOPHOLE[LONG[msg]]]; insufficientVM => ERROR Error[insufficientVM]}}; LoaderEntry: ENTRY PROC[file: File.Capability, offset: File.PageCount, codeLinks: BOOLEAN] RETURNS [cm: PrincOps.ControlModule, unboundImports: BOOLEAN] = {ENABLE UNWIND => NULL; [cm, unboundImports] _ New[LoadBcd[file, offset], file, offset, ~codeLinks]}; LoadBcd: INTERNAL PROC[file: File.Capability, offset: File.PageCount] RETURNS [bcd: BcdBase] = { localFile: File.Capability = File.LimitPermissions[file, File.read]; bcdSpace: Space.Handle; pages, rtPages: CARDINAL; bcdSpace _ Space.Create[size: 1, parent: Space.virtualMemory]; Space.Map[space: bcdSpace, window: [file: localFile, base: offset]]; bcd _ Space.LongPointer[bcdSpace]; IF bcd.versionIdent # BcdDefs.VersionID OR bcd.definitions OR ~bcd.spare1 THEN {Space.Delete[bcdSpace]; ERROR Error[invalidBcd]}; pages _ bcd.nPages; rtPages _ bcd.rtPages.pages; IF pages > 1 THEN {Space.Delete[bcdSpace]; bcdSpace _ Space.Create[size: pages, parent: Space.virtualMemory]; Space.Map[space: bcdSpace, window: [file: localFile, base: offset]]; IF rtPages > 0 THEN [] _ Space.Create[size: pages - rtPages, parent: bcdSpace, base: 0]; bcd _ Space.LongPointer[bcdSpace]}; }; New: INTERNAL PROC[ bcd: BcdBase, file: File.Capability, offset: File.PageNumber, framelinks: BOOLEAN] RETURNS[cm: PrincOps.ControlModule, unboundImports: BOOLEAN] = BEGIN OPEN PilotLoadStateOps; fl: FrameList _ NIL; map: Map _ InitializeMap[bcd]; -- maps bcd-relative gfi's to real gfi's resolved: BOOLEAN _ (bcd.nImports = 0); nbcds: CARDINAL _ InputLoadState[]; -- acquire the lock on the loadstate CleanUpNew: PROC[destroyMap: BOOL _ TRUE] = {frames: FrameList; IF destroyMap AND BASE[map] # NIL THEN {DestroyMap[map]; map _ DESCRIPTOR[NIL, 0]}; UNTIL fl = NIL DO frames _ fl; fl _ fl.next; CedarLinkerOps.FreeSpace[frames] ENDLOOP; ReleaseLoadState[]}; <> IF nbcds >= LAST[PilotLoadStateFormat.ConfigIndex] THEN {CleanUpNew[]; ERROR Loader.Error[loadStateFull]}; BEGIN ENABLE UNWIND => {IF fl # NIL THEN ReleaseFrames[bcd, fl, map]; CleanUpNew[]}; fl _ CreateGlobalFrames[bcd, map, nbcds, framelinks]; AssignCodeToFrames[bcd, file, offset, map]; cm _ AssignControlModules[bcd, map]; resolved _ CedarLinkerOps.Bind[bcd, map]; CedarLinkerOps.Export[bcd, map]; UpdateLoadState[nbcds, bcd]; END; unboundImports _ NOT resolved; CleanUpNew[destroyMap: FALSE]; RTLoader.AcquireTypesAndLiterals[bcd, map ! UNWIND => DestroyMap[map]]; DestroyMap[map]; END; -- New InitializeMap: PUBLIC PROC [bcd: BcdBase] RETURNS [map: PilotLoadStateOps.Map] = {map _ DESCRIPTOR[CedarLinkerOps.GetSpace[bcd.firstdummy--# gfi's in the BCD--], bcd.firstdummy]; FOR i: CARDINAL IN [0..bcd.firstdummy) DO map[i] _ 0; ENDLOOP}; DestroyMap: PUBLIC PROC [map: PilotLoadStateOps.Map] = {IF BASE[map] # NIL THEN CedarLinkerOps.FreeSpace[BASE[map]]}; <<>> <<**********************************************************>> <> <> <> <> <<**********************************************************>> CreateGlobalFrames: PUBLIC PROC[ bcd: BcdBase, map: Map, config: ConfigIndex, allframelinks: BOOLEAN] RETURNS[fl: FrameList _ NIL] = {f: FrameList; frames: POINTER; space: CARDINAL; single: BOOLEAN _ (bcd.nModules = 1); resident: BOOLEAN; GetFrameSizes: PROC [mth: MTHandle] = {IF allframelinks OR mth.linkLoc = frame OR ~mth.code.linkspace THEN space _ space + CedarLinkerOps.LinkSegmentLength[mth, bcd]; space _ NextMultipleOfFour[space] + mth.framesize; resident _ resident OR mth.residentFrame}; FrameInit: PROC [mth: MTHandle] = {frame: GlobalFrameHandle; framelinks: BOOLEAN; gfi: PrincOps.GFTIndex; framelinks _ allframelinks OR mth.linkLoc = frame OR ~mth.code.linkspace; IF framelinks THEN frames _ frames + CedarLinkerOps.LinkSegmentLength[mth, bcd]; frame _ NextMultipleOfFour[frames]; frames _ frame + mth.framesize; gfi _ RuntimeInternal.EnterGlobalFrame[frame, mth.ngfi]; FOR i: PrincOps.GFTIndex IN [0..mth.ngfi) DO map[i + mth.gfi] _ gfi + i; PilotLoadStateOps.EnterModule[ gfi + i, [gfi: mth.gfi + i, config: config, resolved: CedarLinkerOps.LinkSegmentLength[mth, bcd] = 0]]; ENDLOOP; frame^ _ [gfi: gfi, copied: FALSE, alloced: single, shared: FALSE, started: FALSE, trapxfers: FALSE, codelinks: ~framelinks, global:, code:]}; DoFramePack: PROC [fph: FPHandle, fpi: FPIndex] RETURNS [BOOLEAN] = {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 _ AllocateFrames[size: NextMultipleOfFour[space], single: single, resident: resident]; f.next _ fl; fl _ f; frames _ f.frame; FOR i: CARDINAL IN [0..fph.length) DO FrameInit[@mtb[fph.modules[i]]]; ENDLOOP; RETURN[FALSE]}; OtherFrameSizes: PROC [mth: MTHandle, mti: MTIndex] RETURNS[stop: BOOLEAN _ FALSE] = {resident _ FALSE; IF map[mth.gfi] = PrincOps.GFTNull THEN GetFrameSizes[mth]}; OtherFrameInit: PROC [mth: MTHandle, mti: MTIndex] RETURNS[stop: BOOLEAN _ FALSE] = {IF map[mth.gfi] = PrincOps.GFTNull THEN FrameInit[mth]}; <> BEGIN ENABLE UNWIND => ReleaseFrames[bcd, fl, map]; [] _ ProcessFramePacks[bcd, DoFramePack]; space _ 0; [] _ BcdOps.ProcessModules[bcd, OtherFrameSizes]; IF space # 0 THEN {f _ AllocateFrames[size: NextMultipleOfFour[space], single: single, resident: resident]; f.next _ fl; fl _ f; frames _ f.frame; [] _ BcdOps.ProcessModules[bcd, OtherFrameInit]}; END; -- ENABLE UNWIND }; -- end LoadModules ProcessFramePacks: PROC[bcd: BcdBase, proc: PROC[FPHandle, FPIndex] RETURNS[BOOLEAN]] RETURNS[fph: FPHandle, fpi: FPIndex] = {fpb: Base = LOOPHOLE[bcd + bcd.fpOffset]; FOR fpi _ FIRST[FPIndex], fpi + SIZE[FPRecord] + fph.length*SIZE[MTIndex] UNTIL fpi = bcd.fpLimit DO IF proc[fph _ @fpb[fpi], fpi] THEN RETURN; ENDLOOP; RETURN[NIL, FPNull]}; <<>> <<**********************************************************>> <> <<**********************************************************>> AllocateFrames: PUBLIC PROC [size: CARDINAL, single, resident: BOOLEAN] RETURNS [f: FrameList] = BEGIN space: Space.Handle; p: POINTER; IF single THEN { index: CARDINAL; FOR index IN [0..PrincOps.LastAVSlot] DO IF RuntimeInternal.FrameSize[index] >= size THEN EXIT; ENDLOOP; p _ Alloc[index]; [] _ LongZero[LONG[p], size]} ELSE { pages: Space.PageCount = (size + Space.wordsPerPage - 1)/Space.wordsPerPage; space _ Space.Create[ size: pages, parent: Space.mds]; Space.Map[space]; IF resident THEN SpecialSpace.MakeResident[space]; p _ Space.Pointer[space]; [] _ LongZero[LONG[p], pages*Space.wordsPerPage]}; f _ CedarLinkerOps.GetSpace[SIZE[FrameItem]]; f.frame _ p; RETURN END; Alloc: PROC [CARDINAL] RETURNS [POINTER] = MACHINE CODE BEGIN Mopcodes.zALLOC END; ReleaseFrames: PUBLIC PROC [bcd: BcdBase, frames: FrameList, map: PilotLoadStateOps.Map] = {mtb: Base = LOOPHOLE[bcd + bcd.mtOffset]; IF frames = NIL THEN RETURN; IF bcd.nModules = 1 THEN BEGIN Free: PROC [POINTER] = MACHINE CODE BEGIN Mopcodes.zFREE END; Free[frames.frame]; END ELSE UNTIL frames = NIL DO Space.Delete[Space.GetHandle[Space.PageFromLongPointer[frames.frame]]]; frames _ frames.next; ENDLOOP; FOR i: CARDINAL IN [0..LENGTH[map]) DO PilotLoadStateOps.EnterModule[rgfi: map[i], module: PilotLoadStateFormat.NullModule]; PrincOpsRuntime.GFT[map[i]] _ PrincOpsRuntime.EmptyGFTItem; ENDLOOP}; <<>> <<**********************************************************>> <> <<**********************************************************>> heap: MDSZone _ Heap.systemMDSZone; GetSpace: PUBLIC PROC [nwords: CARDINAL] RETURNS [p: POINTER] = { p _ Heap.MakeMDSNode[z: heap, n: nwords]; [] _ LongZero[LONG[p], nwords]; RETURN[p]}; FreeSpace: PUBLIC PROC [p: POINTER] = {Heap.FreeMDSNode[z: heap, p: p]}; aLongBlkZ: MiscAlpha.alpha = 102B; LongZero: PROC [ptr: LONG POINTER, size: CARDINAL] RETURNS[LONG POINTER] = MACHINE CODE BEGIN Mopcodes.zMISC, aLongBlkZ END; <<**********************************************************>> <> <> <<**********************************************************>> SGItem: TYPE = RECORD [sgh: SGHandle, space: Space.Handle, file: File.Capability, bcdBase: File.PageNumber]; SGList: TYPE = DESCRIPTOR FOR ARRAY CARDINAL [0..0) OF SGItem; AssignCodeToFrames: PUBLIC PROC [ bcd: BcdBase, bcdCap: File.Capability, bcdSpaceBase: File.PageNumber, map: Map] = {sgList: SGList; allCodeInSelf: BOOLEAN; GetCode: PROC [mth: MTHandle, mti: MTIndex] RETURNS [BOOLEAN] = BEGIN OPEN RuntimeInternal, PrincOpsRuntime; MatchCSeg: PROC [mmth: MTHandle, mmti: MTIndex] RETURNS [BOOLEAN] = { IF mth # mmth AND mth.code.sgi = mmth.code.sgi AND mth.code.offset = mmth.code.offset THEN frame.shared _ GetFrame[GFT[map[mmth.gfi]]].shared _ TRUE; RETURN[FALSE]}; frame: PrincOps.GlobalFrameHandle = GetFrame[GFT[map[mth.gfi]]]; IF mth.altoCode THEN InvalidModule[bcd, mth]; frame.code.longbase _ SgiToLP[bcd, mth.code.sgi, sgList] + mth.code.offset; frame.code.out _ TRUE; [] _ BcdOps.ProcessModules[bcd, MatchCSeg]; RETURN[FALSE]; END; [sgList, allCodeInSelf] _ FindSegments[bcd, bcdCap, bcdSpaceBase]; IF bcd.nModules = 1 THEN AllocateCodeSpace[bcd, sgList, bcdSpaceBase, bcdCap] ELSE AllocateCodeSpaces[bcd, sgList, allCodeInSelf]; [] _ BcdOps.ProcessModules[bcd, GetCode ! UNWIND => ReleaseCode[sgList]]; CedarLinkerOps.FreeSpace[BASE[sgList]]}; ReleaseCode: PROC [sgList: SGList] = {i: CARDINAL; space1, space2: Space.Handle; space1 _ FindMappedSpace[sgList[i _ 0].space]; i _ 1; DO DO IF i = LENGTH[sgList] THEN EXIT; IF (space2 _ 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}; FindMappedSpace: PUBLIC PROC [space: Space.Handle] RETURNS [Space.Handle] = {mapped: BOOLEAN; parent: Space.Handle; DO [mapped: mapped, parent: parent] _ Space.GetAttributes[space]; IF mapped THEN RETURN[space]; space _ parent; ENDLOOP}; <> FindSegments: PROC [bcd: BcdBase, bcdCap: File.Capability, bcdSpaceBase: File.PageNumber] RETURNS [sgList: SGList, allCodeInSelf: BOOLEAN _ TRUE] = BEGIN n: CARDINAL; sgItem: SGItem; GetFileFromSGH: PROC [sgh: SGHandle] RETURNS [file: File.Capability, base: File.PageNumber] = { fth: FTHandle = @LOOPHOLE[bcd + bcd.ftOffset, Base][sgh.file]; name: STRING = [40]; dot: BOOLEAN _ FALSE; newBCD: BcdBase; space: Space.Handle; AppendName[s: name, ssb: LOOPHOLE[bcd + bcd.ssOffset], name: fth.name]; FOR i: CARDINAL IN [0..name.length) DO IF name[i] = '. THEN {dot _ TRUE; EXIT} ENDLOOP; IF ~dot THEN String.AppendString[name, ".bcd"]; file _ File.nullCapability; file _ Directory.Lookup[fileName: name, permissions: File.read ! Directory.Error => CONTINUE]; IF file = File.nullCapability THEN ERROR Loader.Error[fileNotFound, LOOPHOLE[LONG[name]]]; base _ (IF File.GetAttributes[file].type = DCSFileTypes.tLeaderPage THEN 1 ELSE 0); space _ Space.Create[1, Space.virtualMemory]; Space.Map[space, Space.WindowOrigin[file: file, base: base]]; newBCD _ LOOPHOLE[Space.LongPointer[space]]; IF fth.version # newBCD.version THEN {Space.Delete[space]; ERROR Loader.Error[versionMismatch, LOOPHOLE[LONG[name]]]}; Space.Delete[space]}; CountSegs: PROC [sgh: SGHandle, sgi: SGIndex] RETURNS [BOOLEAN] = { IF sgh.class # code THEN RETURN[FALSE]; IF sgh.file # BcdDefs.FTSelf THEN allCodeInSelf _ FALSE; n _ n + 1; RETURN[FALSE]}; AddSeg: PROC [sgh: SGHandle, sgi: SGIndex] RETURNS [BOOLEAN] = { file: File.Capability; base: File.PageNumber; IF sgh.class # code THEN RETURN[FALSE]; IF sgh.file = BcdDefs.FTSelf THEN {file _ bcdCap; base _ bcdSpaceBase} ELSE {[file, base] _ GetFileFromSGH[sgh]}; sgList[n] _ [sgh: sgh, space: Space.nullHandle, 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 _ DESCRIPTOR[CedarLinkerOps.GetSpace[n*SIZE[SGItem]], n]; n _ 0; [] _ BcdOps.ProcessSegs[bcd, AddSeg]; IF allCodeInSelf THEN {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; AppendName: PUBLIC PROC [s: STRING, ssb: BcdOps.NameString, name: BcdDefs.NameRecord] = {FOR i: CARDINAL 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}; AllocateCodeSpace: PROC [bcd: BcdBase, sgList: SGList, bcdSpaceBase: File.PageNumber, bcdCap: File.Capability] = BEGIN -- this is a bcd produced by the compiler space: Space.Handle; mth: BcdOps.MTHandle; pages, biaspages: CARDINAL; 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 (CedarLinkerOps.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; END; AllocateCodeSpaces: PROC [bcd: BcdBase, sgList: SGList, allCodeInSelf: BOOLEAN] = BEGIN start, end, startBase, pages, offset: CARDINAL; space, subSpace: Space.Handle; 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 OR ~ allCodeInSelf THEN EXIT; pages _ pages + sgList[end].sgh.pages; ENDLOOP; space _ SpecialSpace.CreateForCode[ size: pages, parent: Space.virtualMemory, base: Space.defaultBase]; Space.Map[ space: space, window: Space.WindowOrigin[ file: File.LimitPermissions[sgList[start].file, File.read], base: sgList[start].bcdBase + sgList[start].sgh.base - 1]]; offset _ 0; FOR index: CARDINAL IN [start..end) DO sgh: SGHandle _ sgList[index].sgh; sph: 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; END; FindSPHandle: PUBLIC PROC [bcd: BcdBase, sgh: SGHandle] RETURNS [sph: SPHandle] = {sgb: BcdDefs.Base = LOOPHOLE[bcd + bcd.sgOffset]; spb: BcdDefs.Base = LOOPHOLE[bcd + bcd.spOffset]; FOR spi: SPIndex _ FIRST[SPIndex], spi + SIZE[SPRecord] + sph.length*SIZE[SpaceID] UNTIL spi = bcd.spLimit DO sph _ @spb[spi]; IF @sgb[sph.seg] = sgh THEN RETURN[sph]; ENDLOOP; RETURN[NIL]}; SgiToLP: PROC[bcd: BcdBase, sgi: SGIndex, sgList: SGList] RETURNS[LONG POINTER] = {sgb: BcdDefs.Base = LOOPHOLE[bcd + bcd.sgOffset]; FOR i: CARDINAL IN [0..LENGTH[sgList]) DO IF @sgb[sgi] = sgList[i].sgh THEN RETURN[Space.LongPointer[sgList[i].space]]; ENDLOOP; RETURN[NIL]}; InvalidModule: PROC [bcd: BcdBase, mth: MTHandle] = {name: STRING = [40]; dummy: BOOLEAN _ TRUE; name.length _ 0; AppendName[s: name, ssb: LOOPHOLE[bcd + bcd.ssOffset], name: mth.name]; IF dummy THEN ERROR Loader.Error[invalidBcd, LOOPHOLE[LONG[name]]]}; <<>> <<**********************************************************>> <> <<**********************************************************>> CMMapItem: TYPE = RECORD [cti: CTIndex, cm: PrincOps.ControlModule, level: CARDINAL]; AssignControlModules: PUBLIC PROC[bcd: BcdBase, map: Map] RETURNS [cm: PrincOps.ControlModule] = BEGIN OPEN PrincOps; ctb: Base _ LOOPHOLE[bcd + bcd.ctOffset]; mtb: Base _ LOOPHOLE[bcd + bcd.mtOffset]; cti: CTIndex; mapIndex, maxLevel: CARDINAL _ 0; i: CARDINAL; cmMap: POINTER TO ARRAY [0..0) OF CMMapItem; MapControls: PROC[cth: CTHandle, cti: CTIndex] RETURNS[stop: BOOLEAN _ FALSE] = {OPEN PrincOps, PrincOpsRuntime; cm: ControlModule; level: CARDINAL _ 0; IF cth.nControls = 0 THEN cm _ NullControl ELSE { cm.list _ Frame.Alloc[ RuntimeInternal.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] _ GetFrame[GFT[map[mtb[ci.mti].gfi]]]; 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]}; -- MapControls GetControl: PROC [mth: MTHandle, mti: MTIndex] RETURNS [BOOLEAN] = {OPEN PrincOps, PrincOpsRuntime; frame: GlobalFrameHandle _ GetFrame[GFT[map[mth.gfi]]]; IF mth.config # cti THEN RETURN[FALSE]; IF frame.global[0] = NullControl THEN frame.global[0] _ GetModule[cm]; RETURN[FALSE]}; -- GetControl <> IF bcd.nModules = 1 THEN {OPEN PrincOpsRuntime; frame: GlobalFrameHandle _ GetFrame[GFT[map[1]]]; frame.global[0] _ NullControl; RETURN[[frame[frame]]]}; cmMap _ CedarLinkerOps.GetSpace[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) = 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; CedarLinkerOps.FreeSpace[cmMap]; 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.