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 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,
offset within the file of the first page of the BCD.
Normally 1 (page 0 is the leader page)
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]]};
**********************************************************
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: 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[]};
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: 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]};
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: 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;
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;
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]]]};
**********************************************************
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:
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
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.