-- 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.