-- MesaInit.mesa; edited by Sandman, August 27, 1980 10:01 AM
-- Copyright Xerox Corporation 1979, 1980
DIRECTORY
AllocDefs USING [SwappingProcedure, SwapStrategy, TryCodeSwapping],
AltoDefs USING [MaxMDSPage, PageSize, PagesPerMDS],
ControlDefs USING [GlobalFrameHandle],
FrameDefs USING [
EnumerateGlobalFrames, GlobalFrame, MakeCodeResident, RemoveGlobalFrame,
UnlockCode, UnNew, ValidateGlobalFrame],
FrameOps USING [CodeHandle],
InlineDefs USING [BITAND, LongCOPY],
Map USING [Clean, Entry, SETF, VacantFlags],
MiscDefs USING [],
Mopcodes USING [zRBL, zSTARTIO, zWBL],
NucleusOps USING [],
OsStaticDefs USING [OsStatics],
ProcessDefs USING [CV, DisableInterrupts, EnableInterrupts, ParityLevel],
Region USING [Count, Handle, HyperRegion, Index, Node, Page, PageStatus],
SegmentDefs USING [
AddressFromPage, AllocInfo, BankIndex, Banks, DefaultANYBase, DefaultMDSBase,
EasyUp, EnumerateFileSegments, FileSegmentClass, FileSegmentHandle,
LongAddressFromPage, MachineType, MakeSwappedIn, MemoryConfig, PageNumber,
SegLockCount, SegmentHandle, SegmentLocation, SegmentType, SwapIn, Unlock],
SwapperOps USING [
Alloc, AllocVM, Available, BusyPage, Count, Direction, Disable, ff, FreePage,
initMemoryConfig, lf, map, mdsIndex, mdsNodes, mdsRegion, MDSRegion,
memConfig, Page, PageMap, PageStatus, regions, rover, Status, strategyList,
Swapper, systemTable, Table, TableHandle, TrySwapping, Update, UpdateVM];
MesaInit: PROGRAM
IMPORTS
SwapperOps, FrameDefs, FrameOps, InlineDefs, Map, AllocDefs, ProcessDefs,
Region, SegmentDefs
EXPORTS AllocDefs, MiscDefs, NucleusOps, SwapperOps
SHARES SegmentDefs =PUBLIC
BEGIN OPEN ControlDefs, AllocDefs, SegmentDefs, SwapperOps;
LastResort: SwapStrategy ← SwapStrategy[NIL, TryCodeSwapping];
AddSwapStrategy: PUBLIC PROCEDURE [strategy: POINTER TO SwapStrategy] =
BEGIN
sp: POINTER TO SwapStrategy;
ProcessDefs.DisableInterrupts[];
FOR sp ← SwapperOps.strategyList, sp.link UNTIL sp = NIL DO
IF sp = strategy THEN RETURN; ENDLOOP;
strategy.link ← SwapperOps.strategyList;
SwapperOps.strategyList ← strategy;
ProcessDefs.EnableInterrupts[];
RETURN
END;
RemoveSwapStrategy: PUBLIC PROCEDURE [strategy: POINTER TO SwapStrategy] =
BEGIN
sp: POINTER TO SwapStrategy;
prev: POINTER TO SwapStrategy ← NIL;
ProcessDefs.DisableInterrupts[];
FOR sp ← SwapperOps.strategyList, sp.link UNTIL sp = NIL DO
IF sp = strategy THEN
BEGIN
IF prev = NIL THEN SwapperOps.strategyList ← sp.link
ELSE prev.link ← sp.link;
EXIT
END;
prev ← sp;
ENDLOOP;
ProcessDefs.EnableInterrupts[];
strategy.link ← NIL;
RETURN
END;
MoveCode: PROCEDURE [direction: Direction] =
BEGIN OPEN SegmentDefs;
CheckOne: PROCEDURE [seg: FileSegmentHandle] RETURNS [BOOLEAN] =
BEGIN
oldVMpage, newVMpage: PageNumber;
delta: LONG CARDINAL;
UpdateCodebase: PROCEDURE [f: GlobalFrameHandle] RETURNS [BOOLEAN] =
BEGIN
IF FrameOps.CodeHandle[f] = seg AND ~f.code.out THEN
SELECT direction FROM
outofMDS =>
BEGIN
f.code.longbase ← LONG[f.code.shortbase] + delta;
IF f.code.highHalf = 0 THEN f.code.handle ← seg;
END;
intoMDS =>
BEGIN
f.code.longbase ← f.code.longbase + delta;
IF f.code.highHalf # 0 THEN ERROR;
f.code.handle ← seg;
END;
ENDCASE;
RETURN[FALSE]
END;
IF seg.class # code OR seg.lock = 0 THEN RETURN[FALSE];
IF seg.VMpage >= 256 AND direction = outofMDS THEN RETURN[FALSE];
IF seg.VMpage < 256 AND direction = intoMDS THEN RETURN[FALSE];
SwapIn[seg];
oldVMpage ← seg.VMpage;
newVMpage ← AllocVM[
base: IF direction = outofMDS THEN DefaultANYBase ELSE DefaultMDSBase,
pages: seg.pages, info: [hard, bottomup, code], seg: seg];
ProcessDefs.DisableInterrupts[];
InlineDefs.LongCOPY[
from: LongAddressFromPage[oldVMpage], to: LongAddressFromPage[newVMpage],
nwords: AltoDefs.PageSize*seg.pages];
delta ← AltoDefs.PageSize*(LONG[newVMpage] - LONG[oldVMpage]);
[] ← FrameDefs.EnumerateGlobalFrames[UpdateCodebase];
UpdateVM[oldVMpage, seg.pages, FreePage];
seg.VMpage ← newVMpage;
UpdateVM[newVMpage, seg.pages, seg];
ProcessDefs.EnableInterrupts[];
Unlock[seg];
RETURN[FALSE]
END;
IF ~memConfig.useXM OR memConfig.banks = 100000B THEN RETURN;
[] ← EnumerateFileSegments[CheckOne];
END;
EnableHyperspace: PROCEDURE = {
IF memConfig.useXM THEN
FOR i: BankIndex IN (FIRST[BankIndex]..LAST[BankIndex]] DO
IF LOOPHOLE[memConfig.banks, Banks][i] THEN EnableBank[i]; ENDLOOP};
DisableHyperspace: PROCEDURE =
BEGIN
i: BankIndex;
FOR i IN (FIRST[BankIndex]..LAST[BankIndex]] DO DisableBank[i]; ENDLOOP;
RETURN
END;
NullManager: PROGRAM [Region.Index] RETURNS [Region.Handle] = LOOPHOLE[0];
originalManager: PROGRAM [Region.Index] RETURNS [Region.Handle] ← NullManager;
nHyperRegions: CARDINAL ← 0;
EnableBank: PROCEDURE [bank: BankIndex] =
BEGIN
bankManager: PROGRAM [Region.Index] RETURNS [Region.Handle];
IF bank = 0 THEN RETURN;
IF originalManager = NullManager THEN
bankManager ← originalManager ← Region.HyperRegion
ELSE bankManager ← NEW Region.HyperRegion;
IF nHyperRegions = 0 THEN
FrameDefs.MakeCodeResident[FrameDefs.GlobalFrame[bankManager]];
SwapperOps.regions[bank] ← START bankManager[bank];
nHyperRegions ← nHyperRegions + 1;
RETURN
END;
DisableBank: PROCEDURE [bank: BankIndex] =
BEGIN OPEN FrameDefs;
bankManager: PROGRAM [Region.Index] RETURNS [Region.Handle];
region: Region.Handle;
IF bank = 0 THEN RETURN;
IF (region ← SwapperOps.regions[bank]) = NIL THEN RETURN;
bankManager ← LOOPHOLE[GlobalFrame[region.alloc]];
region.disable[FALSE];
SwapperOps.regions[bank] ← NIL;
IF bankManager # originalManager THEN UnNew[LOOPHOLE[bankManager]];
IF (nHyperRegions ← nHyperRegions - 1) = 0 THEN UnlockCode[originalManager];
RETURN
END;
-- D0/Dorado hyperspace stuff
ComputeRealMemory: PUBLIC PROC RETURNS [pages: CARDINAL, banks: Banks] =
BEGIN OPEN AltoDefs, SwapperOps;
banks ← ALL[FALSE];
pages ← 0;
SELECT memConfig.AltoType FROM
AltoIIXM =>
IF memConfig.xmMicroCode THEN {
word: CARDINAL;
parity: POINTER = ProcessDefs.CV[ProcessDefs.ParityLevel];
ProcessDefs.CV[ProcessDefs.ParityLevel] ← NIL;
FOR i: CARDINAL IN [1..3] DO
word ← RBL[LP[0, i]];
WBL[word + 1, LP[0, i]];
IF RBL[LP[0, i]] = word + 1 THEN {
WBL[word, LP[0, i]]; banks[i] ← TRUE; pages ← pages + PagesPerMDS};
ENDLOOP;
ProcessDefs.CV[ProcessDefs.ParityLevel] ← parity}
ELSE {pages ← PagesPerMDS; banks[0] ← TRUE};
D0, Dorado => {
t: Map.Entry;
FOR pages ← PagesPerMDS, pages + 1 DO
t ← Map.SETF[pages, Map.Clean];
[] ← Map.SETF[pages, t];
IF t.flags = Map.VacantFlags THEN EXIT;
ENDLOOP;
FOR i: CARDINAL IN [0..(pages + MaxMDSPage)/PagesPerMDS) DO
banks[i] ← TRUE; ENDLOOP};
ENDCASE => {pages ← PagesPerMDS; banks[0] ← TRUE};
RETURN
END;
RBL: PROCEDURE [LONG POINTER] RETURNS [CARDINAL] = MACHINE CODE
BEGIN Mopcodes.zRBL, 0 END;
WBL: PROCEDURE [CARDINAL, LONG POINTER] = MACHINE CODE
BEGIN Mopcodes.zWBL, 0 END;
LP: PROCEDURE [CARDINAL, CARDINAL] RETURNS [LONG POINTER] = MACHINE CODE
BEGIN END;
InitMemoryConfig: PROCEDURE =
BEGIN
pages: CARDINAL;
banks: Banks;
MDSOnly: CARDINAL = 100000B;
memConfig ← initMemoryConfig↑;
[pages: pages, banks: banks] ← ComputeRealMemory[];
memConfig.banks ← InlineDefs.BITAND[banks, memConfig.banks];
IF memConfig.banks # MDSOnly THEN memConfig.useXM ← memConfig.xmMicroCode;
END;
Disable: PROCEDURE [BOOLEAN] = BEGIN END;
InitMemory: PROCEDURE [ffvmp, lfvmp: CARDINAL] =
BEGIN OPEN SwapperOps;
page: [0..AltoDefs.MaxMDSPage];
pages: CARDINAL ← lfvmp - ffvmp + 1;
node: Region.Node = AddressFromPage[ffvmp];
START Swapper;
START MDSRegion;
mdsRegion ←
[basePage: 0, alloc: Alloc, update: Update, available: Available,
status: Status, disable: Disable, swap: TrySwapping, hole: pages];
ff ← rover ← ffvmp;
lf ← lfvmp;
node↑ ← [base: ffvmp, pages: pages, fwd: @mdsNodes, back: @mdsNodes];
mdsNodes ← [base: 177777B, pages: 0, fwd: node, back: node];
FOR page IN [0..AltoDefs.MaxMDSPage] DO
map[page] ← IF page IN [ffvmp..lfvmp] THEN FreePage ELSE BusyPage; ENDLOOP;
regions ← ALL[NIL];
regions[mdsIndex ← 0] ← @mdsRegion;
strategyList ← @LastResort;
InitMemoryConfig[];
systemTable ←
[mdsMap: map, memConfig: @memConfig, table: NIL, regions: @regions];
END;
-- Fake Modules
DestroyFakeModule: PROCEDURE [f: GlobalFrameHandle]
RETURNS [seg: SegmentDefs.FileSegmentHandle, offset: CARDINAL] =
BEGIN
FrameDefs.ValidateGlobalFrame[f];
seg ← FrameOps.CodeHandle[f];
IF seg = NIL THEN RETURN[NIL, 0];
IF ~f.shared THEN seg.class ← other;
FrameDefs.RemoveGlobalFrame[f];
ProcessDefs.DisableInterrupts[];
IF f.code.out THEN BEGIN f.code.out ← FALSE; offset ← f.code.offset; END
ELSE offset ← f.code.offset - seg.VMpage*AltoDefs.PageSize;
ProcessDefs.EnableInterrupts[];
RETURN
END;
-- Get Network Number
wordsPerPup: INTEGER = 280;
Byte: TYPE = [0..255];
PupHeader: TYPE = MACHINE DEPENDENT RECORD [
eDest, eSource: Byte,
eWord2, pupLength: INTEGER,
transportControl, pupType: Byte,
pupID1, pupID2: INTEGER,
destNet, destHost: Byte,
destSocket1, destSocket2: INTEGER,
sourceNet, sourceHost: Byte,
sourceSocket1, sourceSocket2: INTEGER,
xSum: CARDINAL];
Pup: TYPE = MACHINE DEPENDENT RECORD [
head: PupHeader, junk: ARRAY [0..100] OF WORD];
EthernetDeviceBlock: TYPE = MACHINE DEPENDENT RECORD [
EPLocMicrocodeStatus, EPLocHardwareStatus: Byte,
EBLocInterruptBit: WORD,
EELocInputFinishCount: INTEGER,
ELLocCollisionMagic: WORD,
EILocInputCount: INTEGER,
EILocInputPointer: POINTER,
EOLocOutputCount: INTEGER,
EOLocOutputPointer: POINTER];
timer: POINTER TO INTEGER = LOOPHOLE[430B];
GetNetworkNumber: PROCEDURE RETURNS [CARDINAL] =
BEGIN
myHost: Byte ← OsStaticDefs.OsStatics.SerialNumber;
then: INTEGER;
now: INTEGER;
device: POINTER TO EthernetDeviceBlock ← LOOPHOLE[600B];
xpup: Pup;
pup: POINTER TO Pup = @xpup;
-- StartIO is Mesa bytecode used to control Ethernet interface
StartIO: PROCEDURE [WORD] = MACHINE CODE BEGIN Mopcodes.zSTARTIO END;
outputCommand: WORD = 1;
inputCommand: WORD = 2;
resetCommand: WORD = 3;
gatewayRequest: PupHeader ←
[eDest: 0, eSource: myHost, eWord2: 1000B, pupLength: 22,
transportControl: 0, pupType: 200B, pupID1:, pupID2:, destNet: 0,
destHost: 0, destSocket1: 0, destSocket2: 2, sourceNet: 0,
sourceHost: myHost, sourceSocket1: 0, sourceSocket2: 2, xSum: 177777B];
device.EBLocInterruptBit ← 0;
THROUGH [0..2) DO
StartIO[resetCommand];
device↑ ← EthernetDeviceBlock[
EPLocMicrocodeStatus: 0, EPLocHardwareStatus: 0, EBLocInterruptBit: 0,
EELocInputFinishCount: 0, ELLocCollisionMagic: 0, EILocInputCount: 0,
EILocInputPointer: pup, EOLocOutputCount: 13,
EOLocOutputPointer: @gatewayRequest];
StartIO[outputCommand];
then ← timer↑;
DO
IF device.EPLocHardwareStatus # 0 THEN
BEGIN
IF device.EPLocMicrocodeStatus = 0 AND pup.head.eWord2 = 1000B AND
wordsPerPup + 2 - device.EELocInputFinishCount > 13 AND
pup.head.destSocket1 = 0 AND pup.head.destSocket2 = 2 AND
pup.head.pupType = 201B THEN RETURN[pup.head.sourceNet];
device↑ ← EthernetDeviceBlock[
EPLocMicrocodeStatus: 0, EPLocHardwareStatus: 0, EBLocInterruptBit: 0,
EELocInputFinishCount: 0, ELLocCollisionMagic: 0,
EILocInputCount: wordsPerPup + 2, EILocInputPointer: pup,
EOLocOutputCount: 0, EOLocOutputPointer: NIL];
StartIO[inputCommand];
END;
now ← timer↑;
IF now - then > 14 THEN EXIT;
ENDLOOP;
ENDLOOP;
RETURN[0];
END;
END...