-- OthelloOpsImpl.mesa 13-Jan-84 11:13:05 by Keith
-- Public procs are first, utility procedures in a later separate section.
DIRECTORY
Boot USING [BootFileType, Location, LVBootFiles, PVBootFiles],
BootFile USING [
currentVersion, Header, MapEntry, maxEntriesPerHeader, maxEntriesPerTrailer,
Trailer],
Buffer USING [Buffer, NSBuffer],
Device USING [Type],
DiskChannel USING [
Drive, GetDriveAttributes, GetNextDrive, GetPageNumber, nullDrive],
Environment USING [
LongNumber, PageFromLongPointer, PageCount, PageNumber, wordsPerPage],
File USING [
File, GetSize, ID, MissingPages, nullFile, nullID, PageCount, PageNumber,
Unknown],
Inline USING [LongDivMod],
KernelFile USING [eofLink, GetBootLocation, Link, MakeBootable, MakeUnbootable],
KernelPhysicalVolume USING [PVHandle],
NSConstants USING [timeServerSocket],
NSTypes USING [],
OthelloOps USING [
BootFileType, nullSubVolume, SetDebuggerSuccess, SetExpirationDateSuccess,
SetGetSwitchesSuccess, SubVolume, TimeServerErrorType],
PhysicalVolume USING [
GetAttributes, GetContainingPhysicalVolume, Handle, ID, InterpretHandle,
PageNumber],
PilotDisk USING [Address, FileID, Handle],
ProcessorFace USING [GreenwichMeanTime, SetGreenwichMeanTime],
Runtime USING [IsBound],
Socket USING [
AssignNetworkAddress, BroadcastAddressFromSocket,
BroadcastPacketToAllConnectedNets, ChannelHandle, Create, Delete, GetPacket,
GetPacketBytes, GetSendBuffer, NetworkAddress, ReturnBuffer, SetDestination,
SetPacketWords, SetWaitTime, TimeOut],
Space USING [Access, Interval, Map, PagesFromWords, Unmap],
SpecialVolume USING [
GetLogicalVolumeBootFiles, GetNextSubVolume, GetPhysicalVolumeBootFiles,
nullSubVolume, SetLogicalVolumeBootFiles, SetPhysicalVolumeBootFiles,
SubVolume, SubVolumeUnknown],
StartList USING [BootLocation, Header, Switches, VersionID],
System USING [
defaultSwitches, GetGreenwichMeanTime, gmtEpoch, GreenwichMeanTime,
LocalTimeParameters, NetworkAddress, nullID, Switches, UpDown, WestEast],
TemporaryBooting USING [MakeBootable, MakeUnbootable],
TemporarySetGMT USING [GetNetworkGMT, TimeZoneDirection],
Volume USING [
Close, GetStatus, ID, NotOnline, NotOpen, nullID, Open,
ReadOnly, Status, Unknown];
OthelloOpsImpl: PROGRAM
IMPORTS
DiskChannel, Environment, File, Inline, KernelFile, PhysicalVolume,
ProcessorFace, Runtime, Socket, Space, SpecialVolume, System,
TemporaryBooting, TemporarySetGMT, Volume
EXPORTS OthelloOps, PhysicalVolume --[Handle]--
SHARES Buffer, File =
BEGIN OPEN OthelloOps;
-- Time Server Constants: THESE SHOULD BE IN NSTypes, etc.!
TimeHeader: TYPE = MACHINE DEPENDENT RECORD [
id1, id2: CARDINAL, clientType: CARDINAL, version: CARDINAL, type: CARDINAL];
timeRequest: CARDINAL = 1; -- for TimeHeader.type
timeResponse: CARDINAL = 2; -- for TimeHeader.type
timeProtocolVersion: CARDINAL = 2; -- for TimeHeader.version
packetExchangeClient: CARDINAL = 1; -- for TimeHeader.clientType
WireTimeFormat: TYPE = MACHINE DEPENDENT RECORD [
timeH(0), timeL(1): CARDINAL,
zoneS(2): System.WestEast,
zoneH(3): [0..177B],
zoneM(4): [0..377B],
beginDST(5), endDST(6): WORD,
errorAccurate(7): BOOLEAN,
errorLow(8), errorHigh(9): CARDINAL];
Handle: PUBLIC --PhysicalVolume.-- TYPE = KernelPhysicalVolume.PVHandle;
BadSwitches: PUBLIC ERROR = CODE;
SubVolumeUnknown: PUBLIC ERROR [sv: SubVolume] = CODE;
TimeServerError: PUBLIC ERROR [error: TimeServerErrorType] = CODE;
StartListHeadPtr: TYPE = LONG POINTER TO StartList.Header;
Bug: ERROR [bugType: BugType] = CODE;
BugType: TYPE = {
impossibleBootFileType, startListOffEndOfBootFile, whereDidTheDriveGo,
whereDidTheLogicalVolumeGo};
--========================================
-- Public procedures:
--========================================
DecodeSwitches: PUBLIC 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};
VolumeNotClosed: PUBLIC ERROR = CODE;
DeleteTempFiles: PUBLIC PROC [lvID: Volume.ID] =
BEGIN
status: Volume.Status = Volume.GetStatus[lvID];
IF status = openRead OR status = openReadWrite THEN ERROR VolumeNotClosed;
Volume.Open[lvID]; -- Deletes any temporary files.
Volume.Close[lvID];
END;
GetDriveSize: PUBLIC PROC [h: Handle] RETURNS [nPages: LONG CARDINAL] = {
RETURN[DiskChannel.GetDriveAttributes[h.drive].nPages]};
GetNextSubVolume: PUBLIC PROC [pvID: PhysicalVolume.ID, thisSv: SubVolume]
RETURNS [SubVolume] =
BEGIN
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];
END;
GetTimeFromTimeServer: PUBLIC PROC
RETURNS [
serverTime: System.GreenwichMeanTime,
serverLTPs: System.LocalTimeParameters] =
BEGIN
pfGMT: ProcessorFace.GreenwichMeanTime;
isValid: BOOLEAN;
IF Runtime.IsBound[LOOPHOLE[Socket.Create]] 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];
END;
IsTimeValid: PUBLIC PROC RETURNS [valid: BOOLEAN] = {
RETURN[System.GetGreenwichMeanTime[] # System.gmtEpoch]};
MakeBootable: PUBLIC PROC [
file: File.File, type: BootFileType, firstPage: File.PageNumber] =
BEGIN
SELECT type FROM
pilot => TemporaryBooting.MakeBootable[file, firstPage];
ENDCASE =>
BEGIN
lvID: Volume.ID = file.volumeID;
l: KernelFile.Link = KernelFile.MakeBootable[
file: file, firstPage: firstPage, count: File.GetSize[file] - firstPage,
lastLink: KernelFile.eofLink];
END;
END;
MakeUnbootable: PUBLIC PROC [
file: File.File, type: BootFileType, firstPage: File.PageNumber] =
BEGIN
SELECT type FROM
pilot => TemporaryBooting.MakeUnbootable[file, firstPage];
ENDCASE =>
KernelFile.MakeUnbootable[
file: file, firstPage: firstPage,
count: File.GetSize[file] - firstPage];
END;
SetProcessorTime: PUBLIC PROC [time: System.GreenwichMeanTime] = {
ProcessorFace.SetGreenwichMeanTime[time]};
SetVolumeBootFile: PUBLIC PROC [
file: File.File, type: BootFileType, firstPage: File.PageNumber] =
BEGIN
bootFiles: Boot.LVBootFiles;
lvID: Volume.ID = file.volumeID;
pilotDiskFileID: PilotDisk.FileID ← [volumeRelative[file.fileID]];
addr: PilotDisk.Address = KernelFile.GetBootLocation[
file, firstPage].diskAddress;
SpecialVolume.GetLogicalVolumeBootFiles[lvID, @bootFiles];
bootFiles[ConvertBootFileType[type]] ← [pilotDiskFileID, firstPage, addr];
SpecialVolume.SetLogicalVolumeBootFiles[lvID, @bootFiles];
END;
SetPhysicalVolumeBootFile: PUBLIC PROC [
file: File.File, type: BootFileType, firstPage: File.PageNumber] =
BEGIN
pilotDiskFileID: PilotDisk.FileID ← [volumeRelative[file.fileID]];
pvID: PhysicalVolume.ID = PhysicalVolume.GetContainingPhysicalVolume[
file.volumeID];
addr: PilotDisk.Address = KernelFile.GetBootLocation[
file, firstPage].diskAddress;
pBootFiles: Boot.PVBootFiles;
SpecialVolume.GetPhysicalVolumeBootFiles[pvID, @pBootFiles];
pBootFiles[ConvertBootFileType[type]] ← [pilotDiskFileID, firstPage, addr];
SpecialVolume.SetPhysicalVolumeBootFiles[pvID, @pBootFiles];
END;
GetVolumeBootFile: PUBLIC PROC [lvID: Volume.ID, type: BootFileType]
RETURNS [file: File.File, firstPage: File.PageNumber] =
BEGIN
bootFiles: Boot.LVBootFiles;
cType: Boot.BootFileType = ConvertBootFileType[type];
SpecialVolume.GetLogicalVolumeBootFiles[lvID, @bootFiles];
IF bootFiles[cType].fID.fileID = File.nullID THEN RETURN[File.nullFile, 0]
ELSE {
file ← [bootFiles[cType].fID.fileID, lvID];
RETURN[file, bootFiles[cType].firstPage]};
END;
GetPhysicalVolumeBootFile: PUBLIC PROC [
pvID: PhysicalVolume.ID, type: BootFileType]
RETURNS [file: File.File, firstPage: File.PageNumber] =
BEGIN
cType: Boot.BootFileType = ConvertBootFileType[type];
bootFiles: Boot.PVBootFiles;
lvID: Volume.ID;
-- Begin main text of GetPhysicalVolumeBootFile:
SpecialVolume.GetPhysicalVolumeBootFiles[pvID, @bootFiles];
IF bootFiles[cType].fID.fileID = File.nullID THEN RETURN[File.nullFile, 0]
ELSE
BEGIN
-- determine what logical volume we are on given pvID and bootFiles[cType].da
bootFilePage: PhysicalVolume.PageNumber;
drive: DiskChannel.Drive;
subVolume: SpecialVolume.SubVolume;
instance: PhysicalVolume.Handle = PhysicalVolume.GetAttributes[
pvID].instance;
index: CARDINAL ← PhysicalVolume.InterpretHandle[instance].index;
-- Find drive that the index corresponds to:
FOR drive ← DiskChannel.GetNextDrive[DiskChannel.nullDrive],
DiskChannel.GetNextDrive[drive] WHILE drive # DiskChannel.nullDrive DO
IF DiskChannel.GetDriveAttributes[drive].deviceOrdinal = index THEN EXIT;
REPEAT FINISHED => Bug[whereDidTheDriveGo];
ENDLOOP;
-- Find volume the boot file page lives in:
bootFilePage ← DiskChannel.GetPageNumber[drive, bootFiles[cType].da];
FOR subVolume ← SpecialVolume.GetNextSubVolume[
pvID, SpecialVolume.nullSubVolume], SpecialVolume.GetNextSubVolume[
pvID, subVolume] UNTIL subVolume = SpecialVolume.nullSubVolume DO
IF bootFilePage IN
[subVolume.firstPVPageNumber..subVolume.firstPVPageNumber +
subVolume.subVolumeSize) THEN {
lvID ← subVolume.lvID; EXIT};
REPEAT FINISHED => Bug[whereDidTheLogicalVolumeGo];
ENDLOOP;
file ← [bootFiles[cType].fID.fileID, lvID];
RETURN[file, bootFiles[cType].firstPage];
END;
END; --GetPhysicalVolumeBootFile--
VoidVolumeBootFile: PUBLIC PROC [lvID: Volume.ID, type: BootFileType] =
BEGIN
pBootFiles: Boot.LVBootFiles;
SpecialVolume.GetLogicalVolumeBootFiles[lvID, @pBootFiles];
pBootFiles[ConvertBootFileType[type]].fID.fileID ← File.nullID;
SpecialVolume.SetLogicalVolumeBootFiles[lvID, @pBootFiles];
END;
VoidPhysicalVolumeBootFile: PUBLIC PROC [
pvID: PhysicalVolume.ID, type: BootFileType] =
BEGIN
pBootFiles: Boot.PVBootFiles;
SpecialVolume.GetPhysicalVolumeBootFiles[pvID, @pBootFiles];
pBootFiles[ConvertBootFileType[type]].fID.fileID ← File.nullID;
SpecialVolume.SetPhysicalVolumeBootFiles[pvID, @pBootFiles];
END;
SetDebugger: PUBLIC PROC [
debuggeeFile: File.File, debuggeeFirstPage: File.PageNumber,
debugger: Volume.ID, debuggerType: Device.Type, debuggerOrdinal: CARDINAL]
RETURNS [outcome: SetDebuggerSuccess] =
BEGIN
ENABLE NoStartListHeader --[code]-- => {outcome ← code; CONTINUE};
nullID: PilotDisk.FileID ← [unique[System.nullID]];
debuggerBootFiles: Boot.LVBootFiles;
pStartListHeader: StartListHeadPtr;
debuggerBootFiles ← ALL[[fID: nullID, firstPage:, da:]];
IF debugger # Volume.nullID THEN {
SpecialVolume.GetLogicalVolumeBootFiles[debugger, @debuggerBootFiles];
IF debuggerBootFiles[pilot].fID = nullID
OR debuggerBootFiles[debugger].fID = nullID
OR debuggerBootFiles[debuggee].fID = nullID THEN RETURN[noDebugger]}
ELSE {debuggerOrdinal ← 0; debuggerType ← LOOPHOLE[0]};
[outcome, pStartListHeader] ← MapStartListHeader[
debuggeeFile, debuggeeFirstPage];
IF outcome = success THEN
BEGIN
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]]]];
END;
[] ← Space.Unmap[pStartListHeader];
END; --SetDebugger--
SetExpirationDate: PUBLIC PROC [
file: File.File, firstPage: File.PageNumber,
expirationDate: System.GreenwichMeanTime]
RETURNS [outcome: SetExpirationDateSuccess] =
BEGIN
ENABLE NoStartListHeader --[code]-- => {outcome ← code; CONTINUE};
pStartListHeader: StartListHeadPtr;
[outcome, pStartListHeader] ← MapStartListHeader[file, firstPage];
IF outcome = success THEN pStartListHeader.expirationDate ← expirationDate;
[] ← Space.Unmap[pStartListHeader];
END;
SetSwitches: PUBLIC PROC [
file: File.File, firstPage: File.PageNumber, switches: System.Switches]
RETURNS [outcome: SetGetSwitchesSuccess] =
BEGIN
ENABLE NoStartListHeader --[code]-- => {outcome ← code; CONTINUE};
pStartListHeader: StartListHeadPtr;
[outcome, pStartListHeader] ← MapStartListHeader[file, firstPage];
IF outcome = success THEN
BEGIN
pBootHeader: LONG POINTER TO BootFile.Header;
pStartListHeader.switches ← LOOPHOLE[switches];
-- Note that MapStartListHeader already mapped the header once, so this
-- Map of the bootfile header will succeed again
pBootHeader ← Space.Map[
window: [file, firstPage, 1], swapUnits: [unitary[]]].pointer;
pBootHeader.switches ← LOOPHOLE[switches];
[] ← Space.Unmap[pBootHeader];
END;
[] ← Space.Unmap[pStartListHeader];
END;
GetSwitches: PUBLIC PROC [file: File.File, firstPage: File.PageNumber]
RETURNS [outcome: SetGetSwitchesSuccess, switches: System.Switches] =
BEGIN
ENABLE NoStartListHeader --[code]-- => {outcome ← code; CONTINUE};
pStartListHeader: StartListHeadPtr;
[outcome, pStartListHeader] ← MapStartListHeader[file, firstPage, readOnly];
IF outcome = success THEN switches ← LOOPHOLE[pStartListHeader.switches];
[] ← Space.Unmap[pStartListHeader];
END;
--========================================
-- Private, utility procedures:
--========================================
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 Bug[impossibleBootFileType];
END;
GetOISCPTime: 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[
NSConstants.timeServerSocket];
timeHeader: LONG POINTER TO TimeHeader;
cH ← Socket.Create[local: Socket.AssignNetworkAddress[], receive: 1];
Socket.SetWaitTime[cH, 700]; -- milliseconds
THROUGH [0..3) DO
sendBuf: Buffer.NSBuffer ← Socket.GetSendBuffer[cH];
Socket.SetPacketWords[sendBuf, SIZE[TimeHeader]];
sendBuf.ns.packetType ← packetExchange;
Socket.SetDestination[sendBuf, target];
timeHeader ← LOOPHOLE[@sendBuf.ns.nsWords];
timeHeader↑ ← [
id1, id2, packetExchangeClient, timeProtocolVersion, timeRequest];
Socket.BroadcastPacketToAllConnectedNets[cH, sendBuf];
DO
recBuf: Buffer.NSBuffer;
recBuf ← Socket.GetPacket[cH ! Socket.TimeOut => EXIT];
timeHeader ← LOOPHOLE[@recBuf.ns.nsWords];
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
wt: LONG POINTER TO WireTimeFormat = LOOPHOLE[@recBuf.ns.nsWords[
SIZE[TimeHeader]]];
valid ← TRUE;
time ← LOOPHOLE[Environment.LongNumber[
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];
END; --GetOISCPTime--
NoStartListHeader: PRIVATE ERROR [code: SetGetSwitchesSuccess] = CODE;
MapStartListHeader: PROC [
file: File.File, firstPage: File.PageNumber, access: Space.Access ← readWrite]
RETURNS [outcome: SetGetSwitchesSuccess, pStartListHeader: StartListHeadPtr] =
<< Maps space (readWrite or readOnly) to the page containing the start list header
in the boot file starting at firstPage of file, and returns a pointer to it.
If any trouble, NoStartListHeader is raised (and the space is not mapped).>>
BEGIN
shortBootFile: SetGetSwitchesSuccess = SetGetSwitchesSuccess[other];
pBootHeader: LONG POINTER TO BootFile.Header ← NIL; -- and space.
startListPage: Environment.PageNumber;
offsetStartListInPage: CARDINAL;
remainingBootFilePages: Environment.PageCount;
headerPage: File.PageNumber;
nEntries: CARDINAL;
entries: LONG POINTER TO ARRAY [0..0) OF BootFile.MapEntry;
bootFileSize: File.PageCount;
BEGIN
ENABLE
UNWIND => IF pBootHeader # NIL THEN pBootHeader ← Space.Unmap[pBootHeader];
bootFileSize ← File.GetSize[
file !
File.Unknown, Volume.Unknown, Volume.NotOnline, Volume.NotOpen =>
ERROR NoStartListHeader[nullBootFile]];
-- Map space to boot file header, get location of start list out of it:
IF firstPage > bootFileSize THEN ERROR NoStartListHeader[shortBootFile];
pBootHeader ← Space.Map[ -- map to header page
window: [file, firstPage, 1], swapUnits: [unitary[]], access: access !
Volume.ReadOnly => ERROR NoStartListHeader[cantWriteBootFile];
File.MissingPages => ERROR NoStartListHeader[other]].mapUnit.pointer;
IF pBootHeader.version # BootFile.currentVersion THEN
ERROR NoStartListHeader[other];
startListPage ← Environment.PageFromLongPointer[pBootHeader.pStartListHeader];
offsetStartListInPage ← Inline.LongDivMod[
num: LOOPHOLE[pBootHeader.pStartListHeader],
den: Environment.wordsPerPage].remainder;
-- Set up loop variables:
remainingBootFilePages ← pBootHeader.countData;
entries ← @pBootHeader.entries;
nEntries ← BootFile.maxEntriesPerHeader;
headerPage ← firstPage;
DO --until get to header page which describes page containing start list--
-- At this point we have either a boot file Header or Trailer page,
-- and are looking at the map entries in it,
-- searching for the vm page containing the start list.
nEntries ← CARDINAL[MIN[remainingBootFilePages, nEntries]];
FOR k: CARDINAL IN [0..nEntries) DO
IF entries[k].virtual = startListPage THEN
BEGIN -- found file page containing start list.
startListHeaderPages: Environment.PageCount = Space.PagesFromWords[
StartList.Header.SIZE + Environment.wordsPerPage - 1]; -- can start anywhere in page.
pBootHeader ← Space.Unmap[pBootHeader]; -- unmap the header/trailer page.
-- Map the start list header:
IF headerPage + 1 + k + startListHeaderPages > bootFileSize THEN
ERROR NoStartListHeader[shortBootFile];
pStartListHeader ←
Space.Map[
window: [file, headerPage + 1 + k, startListHeaderPages],
swapUnits: [unitary[]], access: access !
Volume.ReadOnly => ERROR NoStartListHeader[cantWriteBootFile];
File.MissingPages => ERROR NoStartListHeader[other]].mapUnit.pointer
+ offsetStartListInPage;
RETURN[
outcome:
IF pStartListHeader.version # StartList.VersionID THEN
startListHeaderHasBadVersion ELSE success,
pStartListHeader: pStartListHeader];
END;
ENDLOOP;
-- It's not described in this Header or Trailer page; go for the next:
headerPage ← headerPage + 1 + nEntries; -- step past header and data pages.
remainingBootFilePages ← remainingBootFilePages - nEntries;
pBootHeader ← Space.Unmap[pBootHeader];
IF remainingBootFilePages = 0 THEN ERROR Bug[startListOffEndOfBootFile];
IF headerPage > bootFileSize THEN ERROR NoStartListHeader[shortBootFile];
pBootHeader ← Space.Map[ -- map to trailer page
window: [file, headerPage, 1], swapUnits: [unitary[]], access: access !
Volume.ReadOnly => ERROR NoStartListHeader[cantWriteBootFile];
File.MissingPages => ERROR NoStartListHeader[other]].mapUnit.pointer;
entries ← @LOOPHOLE[pBootHeader, LONG POINTER TO BootFile.Trailer].entries;
nEntries ← BootFile.maxEntriesPerTrailer;
ENDLOOP;
END; --ENABLE UNWIND--
END; --GetStartListHeader--
END.
LOG
May 31, 80 9:54 PM Forrest Re-created file from combines of old VolumeImplA & B.
Jul 13, 80 8:10 PM Forrest Another run at the old fence.
18-Aug-81 14:36:15 Forrest new switches.
16-Nov-81 11:38:25 pasqua fold in bootstrap changes made by Knutsen
17-Nov-81 17:33:25 Forrest
change GetOISCP time to not reference SocketInternal; implement SetExpirationDate
26-Jan-83 18:18:31 Johnsson only one \ for excapes.
15-Mar-83 14:11:25 Thiara
Update To Klamath (space stuff). Added to GetPhysicalVolumeBootFile
to find logical volume. Changed DeleteTempFiles.
31-Mar-83 10:51:36 Luniewski Fold in Sierra changes:
13-Apr-83 13:34:43 pasqua
OIS => NS. Some things in SpecialFile moved to KernelFile.
14-Apr-83 11:20:09 pasqua SetDebugger should be PUBLIC.
22-Apr-83 14:29:12 DKnutsen
MapStartListHeader sometimes didn't map space; and clients wrongly always Deallocated it. Reorganized MapStartListHeader. It now checks for short boot file, version mismatches, etc. and handles own error cleanups; now handles case of Header overlapping page boundary. Use Map rather than MapAt. Rearranged to public first, private later.
12-May-83 10:22:10 DKnutsen Allow GetSwitches on readOnly volume
13-May-83 12:49:47 DKnutsen Prev edit didn't fix second Map.
13-Jul-83 13:49:40 Luniewski Convert to 11.0b.
16-Aug-83 16:39:38 pasqua DeleteTempFiles did too much work.
16-Sep-83 12:54:12 marzullo
SetSwitches did not set the switches into the bootfile header.
29-Nov-83 12:13:55 DKnutsen
FindLogicalVolume looped for multiple drives. Uninitialized variable in DeleteTempFiles. Shoot loopholes and uninitialized warnings.
13-Jan-84 10:50:34 marzullo
GetOISCPTime changed to new protocol.