-- OthelloOpsImpl.mesa (last edited by: Johnsson on: 1-Feb-83 10:51:57)
DIRECTORY
Boot USING [BootFileType, DiskAddress, Location, LVBootFiles, PVBootFiles],
BootFile USING [
MapEntry, Header, maxEntriesPerHeader, maxEntriesPerTrailer, Trailer],
BufferDefs USING [OisBuffer],
Device USING [Type],
DiskChannel USING [GetDriveAttributes, PVHandle],
Environment,
File,
Inline USING [LongDivMod],
KernelFile,
OISCP USING [OiscpPackageDestroy, OiscpPackageMake],
OISCPConstants USING [timeServerSocket],
OthelloOps,
PhysicalVolume,
ProcessorFace USING [GreenwichMeanTime, SetGreenwichMeanTime],
Runtime USING [IsBound],
Socket USING [
AssignNetworkAddress, BroadcastAddressFromSocket, ChannelHandle,
Create, Delete, GetPacket, GetPacketBytes, GetSendBuffer,
PutPacketToAllConnectedNets, ReturnBuffer, SetDestination,
SetPacketWords, SetWaitTime, TimeOut],
Space USING [Create, Delete, Handle, LongPointer, Map, Unmap, virtualMemory],
SpecialFile,
SpecialVolume,
StartList USING [BootLocation, Header, VersionID],
System USING [
defaultSwitches, gmtEpoch, GetGreenwichMeanTime, GreenwichMeanTime,
LocalTimeParameters, NetworkAddress, Switches, UpDown, WestEast],
TemporaryBooting USING [MakeBootable, MakeUnbootable],
TemporarySetGMT USING [GetNetworkGMT, TimeZoneDirection],
Utilities USING [PageFromLongPointer],
Volume;
OthelloOpsImpl: PROGRAM
IMPORTS
DiskChannel, File, Inline, KernelFile, OISCP, PhysicalVolume,
ProcessorFace, Runtime, Socket, Space, SpecialFile, SpecialVolume,
System, TemporaryBooting, TemporarySetGMT,
Utilities, Volume
EXPORTS OthelloOps, PhysicalVolume
SHARES BufferDefs, File = PUBLIC
BEGIN OPEN OthelloOps;
maxFilePermissions: PRIVATE File.Permissions =
File.read + File.write + File.grow + File.shrink + File.delete;
ImpossibleBootFileType: PRIVATE ERROR = CODE;
ConvertBootFileType: PROC [x: BootFileType] RETURNS [Boot.BootFileType] =
BEGIN
SELECT x FROM
hardMicrocode => RETURN[hardMicrocode];
softMicrocode => RETURN[softMicrocode];
germ => RETURN[germ];
pilot => RETURN[pilot];
ENDCASE => ERROR ImpossibleBootFileType;
END;
BadSwitches: ERROR = CODE;
DecodeSwitches: PROC [switchString: LONG STRING]
RETURNS [switches: System.Switches ← System.defaultSwitches] = {
escapeCount: CARDINAL ← 0;
setUpDown: System.UpDown ← down;
escapeChar: CHARACTER ← 0C;
FOR i: CARDINAL IN [0..switchString.length) DO
c: CHARACTER = switchString[i];
SELECT TRUE FROM
c = '-, c = '~ => {
IF setUpDown = up THEN ERROR BadSwitches
ELSE {setUpDown ← up; LOOP}};
c = '\\ => {
IF escapeCount # 0 THEN ERROR BadSwitches
ELSE {escapeCount ← 1; LOOP}};
escapeCount = 1 => {
SELECT c FROM
'n, 'N, 'r, 'R => {switches['\n] ← setUpDown; escapeCount ← 0};
't, 'T => {switches['\t] ← setUpDown; escapeCount ← 0};
'b, 'B => {switches['\b] ← setUpDown; escapeCount ← 0};
'f, 'F => {switches['\f] ← setUpDown; escapeCount ← 0};
'l, 'L => {switches['\l] ← setUpDown; escapeCount ← 0};
'\\ => {switches['\\] ← setUpDown; escapeCount ← 0};
IN ['0..'7] => {escapeChar ← c - ('0-0C); escapeCount ← escapeCount + 1};
ENDCASE => ERROR BadSwitches;
LOOP};
escapeCount # 0 => {
IF c NOT IN ['0..'7] THEN ERROR BadSwitches;
escapeChar ← (c - '0) + (escapeChar - 0C) * 8 + 0C;
IF escapeChar > 377C THEN ERROR BadSwitches;
IF (escapeCount ← escapeCount + 1) = 4 THEN {
switches[escapeChar] ← setUpDown; escapeCount ← 0};
LOOP};
ENDCASE => switches[c] ← setUpDown;
-- fall through to here if normal set or escape set
-- but not on seeing or while collecting escape
setUpDown ← down;
ENDLOOP;
IF escapeCount # 0 THEN ERROR BadSwitches;
RETURN};
-- do an old style delete temps. Volume should be Open
VolumeNotClosed: ERROR = CODE;
DeleteTempFiles: PROC [lvID: Volume.ID] =
BEGIN
status: Volume.Status;
DeleteTempsInner: PROC =
BEGIN
lastCap: File.Capability ← File.nullCapability;
DO
temp, immutable: BOOLEAN;
thisCap: File.Capability = KernelFile.GetNextFile[lvID, lastCap];
IF thisCap = File.nullCapability THEN EXIT;
[immutable: immutable, temporary: temp] ← File.GetAttributes[thisCap];
IF ~temp THEN lastCap ← thisCap
ELSE
IF immutable THEN File.DeleteImmutable[thisCap, lvID]
ELSE File.Delete[thisCap];
ENDLOOP;
END;
status ← Volume.GetStatus[lvID];
IF status = openRead OR status = openReadWrite THEN ERROR VolumeNotClosed;
Volume.Open[lvID];
DeleteTempsInner[ ! UNWIND => Volume.Close[lvID]];
Volume.Close[lvID];
END;
Handle: PUBLIC TYPE = DiskChannel.PVHandle;
GetDriveSize: PROC [h: Handle] RETURNS [nPages: LONG CARDINAL] = {
RETURN[DiskChannel.GetDriveAttributes[h.drive].nPages]};
MakeBootable: PROC [
file: File.Capability, type: BootFileType, firstPage: File.PageNumber] =
BEGIN
SELECT type FROM
pilot => TemporaryBooting.MakeBootable[file, firstPage];
ENDCASE =>
BEGIN
lvID: Volume.ID = File.GetAttributes[file].volume;
l: SpecialFile.Link = SpecialFile.MakeBootable[
file: file, firstPage: firstPage, count: File.GetSize[file] - firstPage,
lastLink: SpecialFile.eofLink];
END;
END;
MakeUnbootable: PROC [
file: File.Capability, type: BootFileType, firstPage: File.PageNumber] =
BEGIN
SELECT type FROM
pilot => TemporaryBooting.MakeUnbootable[file, firstPage];
ENDCASE =>
SpecialFile.MakeUnbootable[
file: file, firstPage: firstPage,
count: File.GetSize[file] - firstPage];
END;
SetVolumeBootFile: PROC [
file: File.Capability, type: BootFileType, firstPage: File.PageNumber] =
BEGIN
bootFiles: Boot.LVBootFiles;
lvID: Volume.ID = File.GetAttributes[file].volume;
l: SpecialFile.Link = KernelFile.GetBootLocation[file, firstPage].link;
SpecialVolume.GetLogicalVolumeBootFiles[lvID, @bootFiles];
bootFiles[ConvertBootFileType[type]] ← [file.fID, firstPage, LOOPHOLE[l]];
SpecialVolume.SetLogicalVolumeBootFiles[lvID, @bootFiles];
END;
SetPhysicalVolumeBootFile: PROC [
file: File.Capability, type: BootFileType, firstPage: File.PageNumber] =
BEGIN
pvID: PhysicalVolume.ID = PhysicalVolume.GetContainingPhysicalVolume[
File.GetAttributes[file].volume];
l: SpecialFile.Link = KernelFile.GetBootLocation[file, firstPage].link;
pBootFiles: Boot.PVBootFiles;
SpecialVolume.GetPhysicalVolumeBootFiles[pvID, @pBootFiles];
pBootFiles[ConvertBootFileType[type]] ← [file.fID, firstPage, LOOPHOLE[l]];
SpecialVolume.SetPhysicalVolumeBootFiles[pvID, @pBootFiles];
END;
GetVolumeBootFile: PROC [lvID: Volume.ID, type: BootFileType]
RETURNS [cap: File.Capability, firstPage: File.PageNumber] =
BEGIN
bootFiles: Boot.LVBootFiles;
cType: Boot.BootFileType = ConvertBootFileType[type];
SpecialVolume.GetLogicalVolumeBootFiles[lvID, @bootFiles];
IF bootFiles[cType].fID = File.nullID THEN RETURN[File.nullCapability, 0]
ELSE
RETURN[
[bootFiles[cType].fID, maxFilePermissions], bootFiles[cType].firstPage];
END;
GetPhysicalVolumeBootFile: PROC [pvID: PhysicalVolume.ID, type: BootFileType]
RETURNS [cap: File.Capability, firstPage: File.PageNumber] =
BEGIN
cType: Boot.BootFileType = ConvertBootFileType[type];
bootFiles: Boot.PVBootFiles;
SpecialVolume.GetPhysicalVolumeBootFiles[pvID, @bootFiles];
IF bootFiles[cType].fID = File.nullID THEN RETURN[File.nullCapability, 0]
ELSE
RETURN[
[bootFiles[cType].fID, maxFilePermissions], bootFiles[cType].firstPage];
END;
VoidVolumeBootFile: PROC [lvID: Volume.ID, type: BootFileType] =
BEGIN
pBootFiles: Boot.LVBootFiles;
SpecialVolume.GetLogicalVolumeBootFiles[lvID, @pBootFiles];
pBootFiles[ConvertBootFileType[type]].fID ← File.nullID;
SpecialVolume.SetLogicalVolumeBootFiles[lvID, @pBootFiles];
END;
VoidPhysicalVolumeBootFile: PROC [pvID: PhysicalVolume.ID, type: BootFileType] =
BEGIN
pBootFiles: Boot.PVBootFiles;
SpecialVolume.GetPhysicalVolumeBootFiles[pvID, @pBootFiles];
pBootFiles[ConvertBootFileType[type]].fID ← File.nullID;
SpecialVolume.SetPhysicalVolumeBootFiles[pvID, @pBootFiles];
END;
-- Set Debugger/Get&SetSwitches implemenation
StartListHeadPtr: PRIVATE TYPE = LONG POINTER TO StartList.Header;
SetDebugger: PROC [
debuggeeCap: File.Capability, debuggeeFirstPage: File.PageNumber,
debugger: Volume.ID, debuggerType: Device.Type, debuggerOrdinal: CARDINAL]
RETURNS [outcome: SetDebuggerSuccess] =
BEGIN
bootSpace: Space.Handle;
debuggerBootFiles: Boot.LVBootFiles ← ALL[[fID: File.nullID,firstPage: ,da: ]];
pStartListHeader: StartListHeadPtr;
IF debugger#Volume.nullID THEN {
SpecialVolume.GetLogicalVolumeBootFiles[debugger, @debuggerBootFiles];
IF debuggerBootFiles[pilot].fID = File.nullID
OR debuggerBootFiles[debugger].fID = File.nullID
OR debuggerBootFiles[debuggee].fID = File.nullID THEN RETURN[noDebugger]}
ELSE {debuggerOrdinal ← 0; debuggerType ← LOOPHOLE[0]};
bootSpace ← Space.Create[1, Space.virtualMemory];
[outcome, pStartListHeader] ← GetStartListHeader[
bootSpace, debuggeeCap, debuggeeFirstPage ! UNWIND => Space.Delete[bootSpace]];
IF outcome=success THEN {
pStartListHeader.locDebuggerMicrocode ← LOOPHOLE[Boot.Location[
deviceType: debuggerType, deviceOrdinal: debuggerOrdinal,
vp: disk[debuggerBootFiles[softMicrocode]]]];
pStartListHeader.locDebuggerGerm ← LOOPHOLE[Boot.Location[
deviceType: debuggerType, deviceOrdinal: debuggerOrdinal,
vp: disk[debuggerBootFiles[germ]]]];
pStartListHeader.locDebugger ← LOOPHOLE[Boot.Location[
deviceType: debuggerType, deviceOrdinal: debuggerOrdinal,
vp: disk[debuggerBootFiles[debugger]]]];
pStartListHeader.locDebuggee ← LOOPHOLE[Boot.Location[
deviceType: debuggerType, deviceOrdinal: debuggerOrdinal,
vp: disk[debuggerBootFiles[debuggee]]]]};
Space.Delete[bootSpace];
END;
SetExpirationDate: PROC [
cap: File.Capability, firstPage: File.PageNumber,
expirationDate: System.GreenwichMeanTime]
RETURNS [outcome: SetExpirationDateSuccess] =
BEGIN
bootSpace: Space.Handle;
pStartListHeader: StartListHeadPtr;
bootSpace ← Space.Create[1, Space.virtualMemory];
[outcome, pStartListHeader] ← GetStartListHeader[
bootSpace, cap, firstPage ! UNWIND => Space.Delete[bootSpace]];
IF outcome=success THEN pStartListHeader.expirationDate ← expirationDate;
Space.Delete[bootSpace];
END;
SetSwitches: PROC [
cap: File.Capability, firstPage: File.PageNumber, switches: System.Switches]
RETURNS [outcome: SetGetSwitchesSuccess] =
BEGIN
bootSpace: Space.Handle;
pStartListHeader: StartListHeadPtr;
bootSpace ← Space.Create[1, Space.virtualMemory];
[outcome, pStartListHeader] ← GetStartListHeader[
bootSpace, cap, firstPage ! UNWIND => Space.Delete[bootSpace]];
IF outcome=success THEN pStartListHeader.switches ← LOOPHOLE[switches];
Space.Delete[bootSpace];
END;
GetSwitches: PROC [
cap: File.Capability, firstPage: File.PageNumber]
RETURNS [outcome: SetGetSwitchesSuccess, switches: System.Switches] =
BEGIN
bootSpace: Space.Handle;
pStartListHeader: StartListHeadPtr;
bootSpace ← Space.Create[1, Space.virtualMemory];
[outcome, pStartListHeader] ← GetStartListHeader[
bootSpace, cap, firstPage ! UNWIND => Space.Delete[bootSpace]];
IF outcome=success THEN switches ← LOOPHOLE[pStartListHeader.switches];
Space.Delete[bootSpace];
END;
GetStartListHeader: PROC [
space: Space.Handle, cap: File.Capability, firstPage: File.PageNumber]
RETURNS [
outcome: SetGetSwitchesSuccess, pStartListHeader: StartListHeadPtr] = {
memPage: Environment.PageNumber;
offset: CARDINAL;
pagesRemaining: CARDINAL;
curBase: File.PageNumber ← firstPage+1; -- start at first data page
nEntries: CARDINAL ← BootFile.maxEntriesPerHeader;
pBootHeader: LONG POINTER TO BootFile.Header = Space.LongPointer[space];
entries: LONG POINTER TO ARRAY [0..0) OF BootFile.MapEntry
← @pBootHeader.entries;
IF cap = File.nullCapability THEN {
outcome ← nullBootFile; RETURN};
Space.Map[space, [cap, firstPage]];
memPage ← Utilities.PageFromLongPointer[pBootHeader.pStartListHeader];
offset ← Inline.LongDivMod[
num: LOOPHOLE[pBootHeader.pStartListHeader],
den: Environment.wordsPerPage].remainder;
pStartListHeader ← (Space.LongPointer[space] + offset);
pagesRemaining ← pBootHeader.countData;
DO
nEntries ← MIN[nEntries, pagesRemaining];
FOR i: CARDINAL IN [0..nEntries) DO
IF entries[i].virtual = memPage THEN {
Space.Unmap[space]; Space.Map[space, [cap, curBase+i]];
outcome ← IF pStartListHeader.version # StartList.VersionID THEN
startListHeaderHasBadVersion ELSE success;
RETURN};
ENDLOOP;
curBase ← curBase + nEntries;
pagesRemaining ← pagesRemaining - nEntries;
IF pagesRemaining = 0 THEN EXIT;
Space.Unmap[space]; Space.Map[space, [cap, curBase]];
curBase ← curBase + 1;
entries ← @LOOPHOLE[pBootHeader, LONG POINTER TO BootFile.Trailer].entries;
nEntries ← BootFile.maxEntriesPerTrailer;
ENDLOOP;
outcome ← cantFindStartListHeader};
SubVolumeUnknown: ERROR [sv: SubVolume] = CODE;
GetNextSubVolume: PROC [pvID: PhysicalVolume.ID, thisSv: SubVolume]
RETURNS [SubVolume] = {
sv: SpecialVolume.SubVolume = SpecialVolume.GetNextSubVolume[
pvID,
IF thisSv = nullSubVolume THEN SpecialVolume.nullSubVolume
ELSE [
lvID: thisSv.lvID, firstLVPageNumber: thisSv.firstLVPageNumber,
firstPVPageNumber: thisSv.firstPVPageNumber,
subVolumeSize: thisSv.subVolumeSize] !
SpecialVolume.SubVolumeUnknown => GOTO error];
RETURN[
IF sv = SpecialVolume.nullSubVolume THEN nullSubVolume
ELSE [
lvID: sv.lvID, subVolumeSize: sv.subVolumeSize,
firstLVPageNumber: sv.firstLVPageNumber,
firstPVPageNumber: sv.firstPVPageNumber]];
EXITS error => ERROR SubVolumeUnknown[thisSv]};
IsTimeValid: PROC RETURNS [valid: BOOLEAN] = {
RETURN[System.GetGreenwichMeanTime[]#System.gmtEpoch]};
SetProcessorTime: PROC [time: System.GreenwichMeanTime] = {
ProcessorFace.SetGreenwichMeanTime[time]};
TimeServerError: ERROR [error: TimeServerErrorType] = CODE;
GetTimeFromTimeServer: PROC RETURNS[
serverTime: System.GreenwichMeanTime,
serverLTPs: System.LocalTimeParameters] = {
pfGMT: ProcessorFace.GreenwichMeanTime;
isValid: BOOLEAN;
IF Runtime.IsBound[OISCP.OiscpPackageMake] THEN
[isValid, serverTime, serverLTPs] ← GetOISCPTime[]
ELSE {
zoneDirection: TemporarySetGMT.TimeZoneDirection;
[networkTimeFound: isValid, timeFromNetwork: pfGMT,
zoneDirection: zoneDirection, zone: serverLTPs.zone,
zoneMinutes: serverLTPs.zoneMinutes, beginDST: serverLTPs.beginDST,
endDST: serverLTPs.endDST] ← TemporarySetGMT.GetNetworkGMT[];
serverTime ← [pfGMT];
serverLTPs.direction ← IF zoneDirection = east THEN east ELSE west};
IF ~isValid THEN ERROR TimeServerError[noResponse];
RETURN};
GetOISCPTime: PRIVATE PROC RETURNS [
valid: BOOLEAN ← FALSE, time: System.GreenwichMeanTime,
ltp: System.LocalTimeParameters] =
BEGIN
cH: Socket.ChannelHandle;
id1: CARDINAL = 12345;
id2: CARDINAL = 6789;
target: System.NetworkAddress = Socket.BroadcastAddressFromSocket[
OISCPConstants.timeServerSocket];
timeHeader: LONG POINTER TO TimeHeader;
WireTimeFormat: TYPE = MACHINE DEPENDENT RECORD [
timeH(0), timeL(1): CARDINAL,
zoneS(2:0..0): System.WestEast,
zoneH(2:1..7): [0..177B],
zoneM(2:8..15): [0..377B],
beginDST(3): WORD,
endDST(4): WORD,
spare(5): ARRAY [5..8) OF WORD ← ALL[0]];
TimeHeader: TYPE = MACHINE DEPENDENT RECORD [
id1, id2: CARDINAL, type: CARDINAL];
-- These should move to OISCPTypes
timeRequest: CARDINAL = 1;
timeResponse: CARDINAL = 2;
OISCP.OiscpPackageMake[];
cH ← Socket.Create[local: Socket.AssignNetworkAddress[], receive: 1];
Socket.SetWaitTime[cH, 700]; -- milli-seconds
THROUGH [0..3) DO
sendBuf: BufferDefs.OisBuffer ← Socket.GetSendBuffer[cH];
Socket.SetPacketWords[sendBuf, SIZE[TimeHeader]];
sendBuf.ois.transCntlAndPktTp.packetType ← LOOPHOLE[123];
Socket.SetDestination[sendBuf, target];
timeHeader ← LOOPHOLE[@sendBuf.ois.oisWords];
timeHeader↑ ← [id1, id2, timeRequest];
Socket.PutPacketToAllConnectedNets[cH, sendBuf];
DO
recBuf: BufferDefs.OisBuffer;
recBuf ← Socket.GetPacket[cH ! Socket.TimeOut => EXIT];
timeHeader ← LOOPHOLE[@recBuf.ois.oisWords];
SELECT TRUE FROM
Socket.GetPacketBytes[recBuf] < 2*(SIZE[WireTimeFormat] + 1)
OR (timeHeader.id1 # id1) OR (timeHeader.id2 # id2)
OR (timeHeader.type # timeResponse) => LOOP;
ENDCASE =>
BEGIN OPEN t: LOOPHOLE[time, Environment.LongNumber];
wt: LONG POINTER TO WireTimeFormat
= LOOPHOLE[@recBuf.ois.oisWords[SIZE[TimeHeader]]];
valid ← TRUE;
t ← [num[lowbits: wt.timeL, highbits: wt.timeH]];
ltp ← [zone: wt.zoneH, direction: wt.zoneS, zoneMinutes: wt.zoneM,
beginDST: wt.beginDST, endDST: wt.endDST];
Socket.ReturnBuffer[recBuf];
GOTO done;
END;
ENDLOOP;
REPEAT done => NULL;
ENDLOOP;
Socket.Delete[cH];
OISCP.OiscpPackageDestroy[];
END;
END....
LOG
Time: May 31, 1980 9:54 PM By: Forrest Action: Re-created file from combines of old VolumeImplA & B.
Time: July 13, 1980 8:10 PM By: Forrest Action: Another run at the old fence.
Time: 18-Aug-81 14:36:15 By: Forrest Action: new switches.
Time: 16-Nov-81 11:38:25 By: pasqua Action: fold in bootstrap changes made by Knutsen
Time: 17-Nov-81 17:33:25 By: Forrest Action: change GetOISCP time to not reference SocketInternal; implement SetExpirationDate
Time: 26-Jan-83 18:18:31 By: Johnsson Action: only one \ for excapes.