CedarLoaderImpl.mesa
This module handles all of parts of loading that don't have anything to do with links:
mapping 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 CedarLinkerOps.Export and CedarLinkerOps.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
Edited by Paul Rovner on December 8, 1982 9:44 am
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;
**********************************************************
public procedures
**********************************************************
Error: PUBLIC ERROR[type: Loader.ErrorType,
message: LONG POINTER TO TEXTNIL] = 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,
offset within the file of the first page of the BCD.
Normally 1 (page 0 is the leader page)
codeLinks: BOOLEANTRUE]
RETURNS[cm: PrincOps.ControlModule, unboundImports: BOOLEAN] =
{[cm, unboundImports] ← DoLoad[file, offset, codeLinks]};
Load: PUBLIC PROC[file: File.Capability,
offset: File.PageCount,
codeLinks: BOOLEANFALSE]
RETURNS [handle: SubSys.Handle] =
{RETURN[LOOPHOLE[DoLoad[file, offset, codeLinks].cm]]};
**********************************************************
The central loading procedures. LoadBcd maps the bcd into VM,
and New calls the procedures that do the work.
**********************************************************
DoLoad: PROC[file: File.Capability,
offset: File.PageCount,
codeLinks: BOOLEANFALSE]
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: BOOLTRUE] =
{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[]};
START New HERE
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: allocates and initializes global frames for the modules
in the bcd and constructs the map of relative gfi's to absolute gfi's.
Also constructs the loadstate info for such modules and returns the
list of frames
**********************************************************
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: BOOLEANFALSE] =
{resident ← FALSE;
IF map[mth.gfi] = PrincOps.GFTNull THEN GetFrameSizes[mth]};
OtherFrameInit: PROC [mth: MTHandle, mti: MTIndex]
RETURNS[stop: BOOLEANFALSE] =
{IF map[mth.gfi] = PrincOps.GFTNull THEN FrameInit[mth]};
Start LoadModules HERE
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]};
**********************************************************
Frame allocation/deallocation
**********************************************************
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};
**********************************************************
Free storage management
**********************************************************
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;
**********************************************************
AssignCodeToFrames: Makes up a list of code segments, maps them in,
and associates each code segment with the appropriate global frame.
**********************************************************
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};
called only from AssignCodeToFrames
FindSegments: PROC [bcd: BcdBase, bcdCap: File.Capability, bcdSpaceBase: File.PageNumber]
RETURNS [sgList: SGList, allCodeInSelf: BOOLEANTRUE] =
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: BOOLEANFALSE;
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: BOOLEANTRUE;
name.length ← 0;
AppendName[s: name, ssb: LOOPHOLE[bcd + bcd.ssOffset], name: mth.name];
IF dummy THEN ERROR Loader.Error[invalidBcd, LOOPHOLE[LONG[name]]]};
**********************************************************
AssignControlModules: determines start trap links for each global frame.
**********************************************************
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: BOOLEANFALSE] =
{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
START AssignControlModules HERE
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.