DIRECTORY Basics USING [ BITNOT, BYTE, BytePair, DivMod, LongDivMod, LowHalf ], BasicTime USING [ FromPupTime, GetClockPulses, GMT, nullGMT, OutOfRange ], BootFile USING [MemorySizeToFileSize], Booting USING [ Boot, Switches, switches ], DebuggerSwap USING [EnableSwatWatcher], DefaultRemoteNames USING [Get], Disk USING [Channel, DriveAttributes, GetDeviceFromChannel, Label, NextChannel, PageCount, PageNumber], DiskFace USING [DeviceHandle, GetDeviceAttributes, GetTrueDeviceAttributes], File USING [Error, FindVolumeFromName, FP, GetVolumeID, GetVolumeName, Handle, Info, LogicalInfo, NextVolume, nullFP, Open, RC, SetSize, SystemVolume, Volume, VolumeID, VolumeFile, wordsPerPage], FileBackdoor USING [CreateLogicalVolume, CreatePhysicalVolume, EraseVolume, GetRoot, GetVolumePages, IsDebugger, MarkDebugger, PhysicalPageBad, SetRoot], FormatDisk USING [BadPage, IdentifyInitialMicrocode, InstallInitialMicrocode, MicrocodeInstallFailure, Operation, Sweep], FS USING [ Close, ComponentPositions, Copy, Delete, EnumerateForNames, Error, ExpandName, FileInfo, NameProc, Open, OpenFile, SetByteCountAndCreatedTime, StreamOpen ], FSBackdoor USING [ CloseVolume, CreateVMBacking, FNameFromHandle, GetFileHandle ], FSRemoteFile USING [Retrieve], GermSwap USING [ Switch ], IagoCommands, IagoOps --USING everything--, IO USING [ Close, EndOfStream, Error, GetChar, GetLength, PutChar, PutF, PutF1, PutRope, RopeFromROS, RIS, ROS, SetIndex, STREAM ], PhysicalVolume USING [ GetSubVolumes, NextPhysical, Physical, PhysicalInfo, PhysicalRC, SetPhysicalRoot, SubVolumes ], Rope USING [ Cat, Concat, Find, ROPE, Substr ], SystemVersion USING [ machineType, uCodeCedar, uCodeDate, uCodeFloatingPoint, uCodeVersion ], ThisMachine USING [ Name, ProcessorID ], UserCredentials USING [ChangeState], VM USING [AddressForPageNumber, Allocate, Free, Interval, PagesForBytes, PagesForWords, Pin, wordsPerPage], VMSideDoor USING [rmPages]; IagoCommands1Impl: CEDAR PROGRAM IMPORTS Basics, BasicTime, BootFile, Booting, DebuggerSwap, DefaultRemoteNames, Disk, DiskFace, File, FileBackdoor, FormatDisk, FS, FSBackdoor, FSRemoteFile, IagoCommands, IagoOps, IO, PhysicalVolume, Rope, SystemVersion, ThisMachine, UserCredentials, VM, VMSideDoor EXPORTS IagoCommands = { ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; Attach: PUBLIC PROC [in, out: STREAM] = { from: ROPE = IagoOps.GetFile[ in: in, out: out, prompt: "From ", check: TRUE]; to: ROPE = IagoOps.GetFile[ in: in, out: out, prompt: "To "]; IO.PutRope[out, " ... "]; [] _ FS.Copy[from: from, to: to, remoteCheck: FALSE, attach: TRUE]; IO.PutRope[out, "done"]; }; BootLogical: PUBLIC PROC [in, out: STREAM] = { v: File.Volume = IagoOps.GetLogical[in, out]; reject: ROPE = Booting.Boot[[logical[v]], IagoOps.GetSwitches[in, out]]; IO.PutF1[out, " ... couldn't: %g\n", [rope[reject]] ]; }; Copy: PUBLIC PROC [in, out: STREAM] = { from: ROPE = IagoOps.GetFile[ in: in, out: out, prompt: "From ", check: TRUE]; to: ROPE = IagoOps.GetFile[ in: in, out: out, prompt: "To "]; IO.PutRope[out, " ... "]; [] _ FS.Copy[from: from, to: to]; IO.PutRope[out, "done"]; }; CreateLogical: PUBLIC PROC [in, out: STREAM] = { name: ROPE _ IF File.FindVolumeFromName[IagoOps.clientVolName] = NIL THEN IagoOps.clientVolName ELSE NIL; size: INT; p: PhysicalVolume.Physical; free: INT; HelpCreation: PROC = { IO.PutRope[out, "? type a string which is not the same as the name of any existing volume"]; }; DO name _ IagoOps.GetArg[ in: in, out: out, prompt: "\nNew volume name: ", default: name, help: HelpCreation]; IF File.FindVolumeFromName[name] # NIL THEN IO.PutRope[out, " ... already exists"] ELSE EXIT ENDLOOP; p _ IagoOps.GetPhysical[in, out]; IagoOps.ReservePages[in, out, p]; free _ PhysicalVolume.PhysicalInfo[p].free; size _ IagoOps.GetSize[in: in, out: out, default: free, max: free]; IO.PutRope[out, "\nAre you sure? "]; IF IagoOps.Confirm[in, out] THEN { new: File.Volume _ NIL; IO.PutRope[out, " ... "]; new _ FileBackdoor.CreateLogicalVolume[ id: IagoOps.NewID[], where: LIST[p], size: size, name: name]; IO.PutRope[out, " done"]; IagoOps.clientVolName _ name; IO.PutRope[out, "\nDo you want to use this as the debugger volume? "]; IF IagoOps.Confirm[in, out] THEN FileBackdoor.MarkDebugger[new, TRUE]; }; }; CloseFSVolumes: PROC = { FOR v: File.Volume _ File.NextVolume[NIL], File.NextVolume[v] UNTIL v = NIL DO FSBackdoor.CloseVolume[v]; ENDLOOP; }; CreatePhysical: PUBLIC PROC [in, out: STREAM] RETURNS[done: BOOL _ FALSE] = { HelpCreation: PROC = { IO.PutRope[out, "? type a name not the same as that of any existing volume"]; }; d: Disk.Channel = IagoOps.GetDrive[in, out]; alto: BOOL = Disk.DriveAttributes[d].ordinal = 0 AND IagoOps.CheckAltoRegions[in, out]; name: ROPE = IagoOps.GetArg[ in: in, out: out, prompt: "\nNew volume name: ", default: ThisMachine.Name[], help: HelpCreation]; IF IagoOps.ConfirmDestruction[in, out, Rope.Concat[ "the entire disk drive", IF alto THEN " (excluding Alto regions)" ELSE NIL ] ] THEN { new: PhysicalVolume.Physical; CloseFSVolumes[]; new _ FileBackdoor.CreatePhysicalVolume[where: d, name: name, id: IagoOps.NewID[]]; IagoOps.ReservePages[in, out, new]; done _ TRUE; IagoCommands.InstallCredentials[in, out]; DebuggerSwap.EnableSwatWatcher[TRUE]; }; }; CreateUserWorld: PUBLIC PROC [in, out: STREAM] = { Install: PROC [where: File.Volume, which: File.VolumeFile[microcode..bootFile]] = { wDir: ROPE = Rope.Cat["[]<", File.GetVolumeName[where], ">"]; remote: ROPE = IagoOps.RemoteRootFileName[which]; local: ROPE = IagoOps.LocalRootFileName[which]; fsFile: FS.OpenFile; file: File.Handle; createTime: BasicTime.GMT; IO.PutF[out, "\nInstalling %g as %g%g ... ", [rope[remote]], [rope[wDir]], [rope[local]] ]; [] _ FS.Copy[from: remote, to: local, wDir: wDir]; createTime _ FS.FileInfo[name: local, wDir: wDir].created; fsFile _ FS.Open[name: local, lock: write, wDir: wDir]; file _ FSBackdoor.GetFileHandle[fsFile]; FileBackdoor.SetRoot[which, file]; FS.SetByteCountAndCreatedTime[file: fsFile, created: createTime]; FS.Close[fsFile]; IO.PutRope[out, "done"]; }; format, protect: BOOL; altoText: ROPE _ NIL; myName: ROPE = ThisMachine.Name[]; systemHost: ROPE = DefaultRemoteNames.Get[].systemHost; userHost: ROPE = DefaultRemoteNames.Get[].userHost; d: Disk.Channel = Disk.NextChannel[NIL]; newP: PhysicalVolume.Physical; newC: File.Volume; memImagePages: INT; cedarVMPages: INT _ 0; TRUSTED { memImagePages _ BootFile.MemorySizeToFileSize[VMSideDoor.rmPages]+24; }; IO.PutChar[out, '\n]; IagoOps.ReserveAltoRegions[in, out]; IF IagoOps.CheckAltoRegions[in, out] THEN altoText _ " (excluding the Alto disk regions)"; IO.PutRope[out, "\n\nHas your disk already been formatted? (Confirm if the disk has previously been used for Cedar or Pilot, AND you have not reduced the amount of disk reserved for Alto volumes) "]; format _ NOT IagoOps.Confirm[in, out]; IO.PutRope[out, "\n\nDo you want to password-protect this disk? "]; protect _ IagoOps.Confirm[in, out]; WHILE cedarVMPages < 8000 DO cedarVMPages _ IagoOps.GetNumber[ in: in, out: out, default: DefaultVMSize[], max: 64000, prompt: "\n\nSpecify VM size (in pages): ", help: "? give number of VM pages in decimal (max: 64000)" ]; ENDLOOP; IO.PutRope[out, "\n\nI intend to perform the following operations:"]; IF format THEN IO.PutF1[out, "\n - format the entire disk%g;", [rope[altoText]] ]; IO.PutF1[out, "\n - create a new physical volume named \"%g\";", [rope[myName]] ]; IO.PutF1[out, "\n - create a client volume named \"Cedar\" with a %g page VM;\n - install microcode, germ and boot files(s) from the release directory;\n - make the \"Cedar\" volume be the physical boot volume;\n - boot the volume(s) to initialize the software.\n", [integer[cedarVMPages]] ]; IF NOT IagoOps.ConfirmDestruction[ in, out, Rope.Concat["the entire disk on drive RD0", altoText]] THEN RETURN; CloseFSVolumes[]; IO.PutChar[out, '\n]; IF format THEN TRUSTED { DoFormatOrScan[in: in, out: out, d: d, format: TRUE, passes: 1] }; IO.PutRope[out, "\nCreating physical volume ... "]; newP _ FileBackdoor.CreatePhysicalVolume[where: d, name: myName, id: IagoOps.NewID[]]; IagoOps.ReservePages[in, out, newP]; [] _ UserCredentials.ChangeState[IF protect THEN name ELSE nameHint]; IO.PutRope[out, "done"]; IO.PutRope[out, "\nCreating logical volume \"Cedar\" ... "]; newC _ FileBackdoor.CreateLogicalVolume[ id: IagoOps.NewID[], where: LIST[newP], size: PhysicalVolume.PhysicalInfo[newP].free, name: "Cedar"]; IO.PutRope[out, "done. Erasing it ... "]; FileBackdoor.EraseVolume[newC]; IO.PutRope[out, "done"]; CreateVMFile[out, newC, cedarVMPages]; Install[where: newC, which: microcode]; Install[where: newC, which: germ]; Install[where: newC, which: bootFile]; PhysicalVolume.SetPhysicalRoot[newC, microcode]; PhysicalVolume.SetPhysicalRoot[newC, germ]; PhysicalVolume.SetPhysicalRoot[newC, bootFile]; { init: ROPE = IagoOps.InitialMicrocodeFileName[]; IO.PutRope[out, "\nInstalling "]; IO.PutRope[out, init]; IF DoInitialMicrocodeInstallation[out, d, init, "[]Temp>Initial.Microcode"] THEN [] _ Booting.Boot[ [logical[newC]], [d: Booting.switches[d]] ]; }; }; CreateVM: PUBLIC PROC [in, out: STREAM] = { v: File.Volume = IagoOps.GetLogical[in, out, "On "]; size: INT = IagoOps.GetSize[ in: in, out: out, default: DefaultVMSize[], max: FileBackdoor.GetVolumePages[v].size]; oldFP: File.FP = FileBackdoor.GetRoot[v, VM].fp; oldFile: File.Handle _ NIL; IF oldFP # File.nullFP THEN oldFile _ File.Open[v, oldFP ! File.Error => IF why = unknownFile THEN CONTINUE]; IF oldFile # NIL THEN { IO.PutF[out, "\nThat volume already has a VM backing file of size %g. Do you want me to set its size to %g? ", [integer[File.Info[oldFile].size]], [integer[size]] ]; IF IagoOps.Confirm[in, out] THEN { IO.PutRope[out, " ... "]; File.SetSize[oldFile, size]; IO.PutRope[out, "done"] }; } ELSE CreateVMFile[out, v, size]; -- Create the file ourselves }; DefaultVMSize: PROC RETURNS [pages: INT _ 16000] = { SELECT VMSideDoor.rmPages FROM <= 4*1024 => {}; <= 8*1024 => pages _ 20000; <= 12*1024 => pages _ 24000; ENDCASE => pages _ 32000; }; CreateVMFile: PROC [out: STREAM, v: File.Volume, size: INT] = { newFile: FS.OpenFile; volName: ROPE = File.GetVolumeName[v]; vmName: ROPE = Rope.Cat["[]<", volName, ">", IagoOps.LocalRootFileName[VM]]; IO.PutF1[out, "\nCreating %g ... ", [rope[vmName]] ]; newFile _ FSBackdoor.CreateVMBacking[name: vmName, pages: size]; FileBackdoor.SetRoot[VM, FSBackdoor.GetFileHandle[newFile]]; FS.Close[newFile]; IO.PutRope[out, "done"]; [] _ IagoOps.WriteRemoteNames[volName, out]; }; Delete: PUBLIC PROC [in, out: STREAM] = { count: INT _ 0; DoName: FS.NameProc = { count _ count+1; IO.PutF1[out, "\nDeleting %g ... ", [rope[fullFName]]]; { ENABLE FS.Error => { IO.PutRope[out, error.explanation]; CONTINUE }; FS.Delete[fullFName]; IO.PutRope[out, "done"]; }; RETURN[TRUE]; }; pattern: ROPE _ IagoOps.GetFile[in: in, out: out, pattern: TRUE]; IF Rope.Find[pattern, "!"] < 0 THEN pattern _ pattern.Concat["!L"]; IO.PutRope[out, " ... "]; FS.EnumerateForNames[pattern, DoName]; IF count = 0 THEN IO.PutRope[out, "not found"] ELSE IO.PutF1[out, "\n%g files", [integer[count]] ]; }; DescribeDrives: PUBLIC PROC [in, out: STREAM] = { FOR c: Disk.Channel _ Disk.NextChannel[NIL], Disk.NextChannel[c] UNTIL c = NIL DO ordinal: INT; nPages: INT; [ordinal: ordinal, nPages: nPages] _ Disk.DriveAttributes[c]; IO.PutF[out, "\nRD%g, size: %g pages", [integer[ordinal]], [integer[nPages]] ]; ENDLOOP; }; DescribeLV: PUBLIC PROC [in, out: STREAM] = { FOR v: File.Volume _ File.NextVolume[NIL], File.NextVolume[v] UNTIL v = NIL DO { ENABLE File.Error => IO.PutRope[out, "\nUnexpected File.Error"]--and let it propagate--; id: File.VolumeID; rootStatus, vamStatus: File.RC; name: ROPE; size, free, freeboard: INT; [id: id, size: size, rootStatus: rootStatus, name: name, vamStatus: vamStatus, free: free, freeboard: freeboard] _ File.LogicalInfo[v]; IO.PutRope[out, "\n\nID: "]; IagoOps.PutID[out, File.GetVolumeID[v]]; IF v = File.SystemVolume[] THEN IO.PutRope[out, " (the system volume)"]; SELECT rootStatus FROM ok, nonCedarVolume => NULL; wentOffline => { IO.PutRope[out, "\nVolume went offline"]; LOOP; }; inconsistent => { IO.PutRope[out, "\nRoot page is inconsistent (wrong version?)"]; LOOP; }; software => { IO.PutRope[out, "\nCan't find the volume root page (label-check)"]; LOOP; }; hardware => { IO.PutRope[out, "\nHard disk error reading the volume root page"]; LOOP; }; ENDCASE => ERROR File.Error[rootStatus]; IO.PutF1[out, "\nName: %g", [rope[name]] ]; IF FileBackdoor.IsDebugger[v] THEN IO.PutRope[out, "\nThis is a debugger volume"]; IO.PutF1[out, "\nSize: %g", [integer[size]] ]; IF rootStatus = nonCedarVolume THEN { IO.PutRope[out, "\nNot a Cedar volume"]; LOOP }; SELECT vamStatus FROM ok => IO.PutF1[out, ", free pages: %g", [integer[free]] ]; wentOffline => IO.PutRope[out, "\nVolume went offline during VAM operation"]; inconsistent => IO.PutRope[out, "\nDon't understand the VAM"]; software => IO.PutRope[out, "\nCan't find the VAM (label-check)"]; hardware => IO.PutRope[out, "\nHard disk error reading the VAM"]; unknownFile => IO.PutRope[out, "\nCan't find the VAM (unknown-file)"]; unknownPage => IO.PutRope[out, "\nCan't find the VAM (unknown-page)"]; ENDCASE => ERROR File.Error[vamStatus]; FOR vf: File.VolumeFile IN File.VolumeFile DO PutVolumeFile[out, v, vf]; ENDLOOP; }; ENDLOOP; }; PutVolumeFile: PROC [out: STREAM, v: File.Volume, vf: File.VolumeFile] = { fp: File.FP _ FileBackdoor.GetRoot[v, vf].fp; file: File.Handle; name: ROPE; IF fp = File.nullFP THEN RETURN; IO.PutF[out, "\n%g fp: [id:%bB,da:%bB]", [rope[SELECT vf FROM checkpoint => "Checkpoint", microcode => "Microcode", germ => "Germ", bootFile => "BootFile", debugger => "Debugger", debuggee => "Debuggee", VM => "VM", VAM => "VAM", client => "FS-root", alpine => "Alpine-root", ENDCASE => "Other-root"]], [cardinal[LOOPHOLE[fp.id]]], [cardinal[LOOPHOLE[fp.da]]] ]; file _ File.Open[v, fp ! File.Error => { IO.PutRope[out, " ... "]; IO.PutRope[out, IagoOps.FileError[why]]; file _ NIL; CONTINUE } ]; IF file # NIL THEN { ENABLE FS.Error => { IO.PutRope[out, " ... "]; IF error.code = $invalidPropertyPage THEN IO.PutRope[out, "not an FS file"] ELSE IO.PutRope[out, error.explanation]; CONTINUE }; IO.PutF1[out, ", size: %g", [integer[File.Info[file].size]] ]; name _ FSBackdoor.FNameFromHandle[file]; IO.PutRope[out, ", name: "]; IO.PutRope[out, name]; }; }; DescribeMachine: PUBLIC PROC [in, out: STREAM] = { IO.PutF[out, "\nThis processor is a %g, id = %g, %g, %g, available real memory: %g pages", [rope[SELECT SystemVersion.machineType FROM dolphin => "Dolphin", dorado => "Dorado", dandelion => "Dandelion", dicentra => "Dicentra", ENDCASE => "{unknown processor type!}"]], [rope[ThisMachine.ProcessorID[$Octal]]], [rope[ThisMachine.ProcessorID[$ProductSoftware]]], [rope[ThisMachine.ProcessorID[$Hex]]], [integer[VMSideDoor.rmPages]] ]; IO.PutF1[out, "\nThe microcode is version %g of ", [integer[SystemVersion.uCodeVersion]] ]; { ENABLE BasicTime.OutOfRange => { IO.PutRope[out, "unknown date."]; CONTINUE; }; IO.PutF1[out, "%g.", [time[BasicTime.FromPupTime[SystemVersion.uCodeDate]]] ]; }; IF NOT SystemVersion.uCodeCedar THEN IO.PutRope[out, " No Cedar microcode."]; IF NOT SystemVersion.uCodeFloatingPoint THEN IO.PutRope[out, " No floating-point microcode."]; }; DescribePV: PUBLIC PROC [in, out: STREAM] = { FOR p: PhysicalVolume.Physical _ PhysicalVolume.NextPhysical[NIL], PhysicalVolume.NextPhysical[p] UNTIL p = NIL DO IagoOps.ReservePages[in, out, p]; ENDLOOP; FOR p: PhysicalVolume.Physical _ PhysicalVolume.NextPhysical[NIL], PhysicalVolume.NextPhysical[p] UNTIL p = NIL DO channel: Disk.Channel; rootStatus: PhysicalVolume.PhysicalRC; id: File.VolumeID; name: ROPE; size: Disk.PageCount; free: Disk.PageCount; [channel: channel, rootStatus: rootStatus, id: id, name: name, size: size, free: free] _ PhysicalVolume.PhysicalInfo[p]; IO.PutRope[out, "\n\nID: "]; IagoOps.PutID[out, id]; IO.PutF1[out, "\nOn drive RD%g", [integer[Disk.DriveAttributes[channel].ordinal]] ]; SELECT rootStatus FROM ok => NULL--drop through to after ENDCASE--; wentOffline => { IO.PutRope[out, "\nVolume went offline"]; LOOP }; inconsistent => { IO.PutRope[out, "\nRoot page is inconsistent (wrong version?)"]; LOOP }; software => { IO.PutRope[out, "\nCan't find the volume root page (label-check)"]; LOOP }; hardware => { IO.PutRope[out, "\nHard disk error reading the volume root page"]; LOOP }; ENDCASE => ERROR File.Error[rootStatus]; TRUSTED { microcodeInstalled: BOOL; time: BasicTime.GMT; name: ROPE; [microcodeInstalled, time, name] _ FormatDisk.IdentifyInitialMicrocode[channel]; IF microcodeInstalled THEN IO.PutF[out, "\nContains initial microcode %g of %g", [rope[name]], [time[time]] ]; }; IO.PutF[out, "\nName: %g\nSize: %g, free pages: %g\nLogical sub-volumes:", [rope[name]], [integer[size]], [integer[free]] ]; { sv: PhysicalVolume.SubVolumes = PhysicalVolume.GetSubVolumes[p]; FOR i: CARDINAL IN [0..sv.count) DO IO.PutF1[out, "\n At physical page %g, logical id: ", [integer[sv[i].address]] ]; IagoOps.PutID[out, sv[i].id]; IO.PutF[out, ", pages [%g..%g)", [integer[sv[i].start]], [integer[sv[i].start+sv[i].size]] ]; ENDLOOP; }; ENDLOOP; }; EraseLogical: PUBLIC PROC [in, out: STREAM] = { v: File.Volume = IagoOps.GetLogical[in, out]; IF IagoOps.ConfirmDestruction[in, out, "the entire logical volume"] THEN { IO.PutRope[out, "\nErasing ... "]; FileBackdoor.EraseVolume[v]; IO.PutRope[out, "done"]; FSBackdoor.CloseVolume[v]; }; }; FormatOrScan: PUBLIC PROC [in, out: STREAM, format: BOOL] = TRUSTED { d: Disk.Channel = IagoOps.GetDrive[in, out]; alto: BOOL = Disk.DriveAttributes[d].ordinal = 0 AND IagoOps.CheckAltoRegions[in, out]; passes: INT = IagoOps.GetNumber[in, out, 10, 999, "\nHow many check passes should I make? ", "? Type how often I should make transfers over the entire disk trying to find bad spots"]; IF NOT format OR IagoOps.ConfirmDestruction[in, out, Rope.Concat[ "the entire disk drive", IF alto THEN " (excluding Alto regions)" ELSE NIL ] ] THEN DoFormatOrScan[in, out, d, format, passes]; }; DoFormatOrScan: UNSAFE PROC [in, out: STREAM, d: Disk.Channel, format: BOOL, passes: INT] = UNCHECKED { initLabel: Disk.Label; pageSpace: VM.Interval = VM.Allocate[VM.PagesForWords[File.wordsPerPage]]; data: LONG POINTER = VM.AddressForPageNumber[pageSpace.page]; soft, hard: INT _ 0; BadList: TYPE = LIST OF RECORD[ page: Disk.PageNumber, correctable: BOOL, dontReport: BOOL _ FALSE]; badPages: BadList _ NIL; errorsThisPass: BOOL; SweepDisk: UNSAFE PROC [out: STREAM, d: Disk.Channel, operation: FormatDisk.Operation] = UNCHECKED { origin: Disk.PageNumber _ [0]; label: Disk.Label _ initLabel; IO.PutRope[out, SELECT operation FROM format => "\nFormatting ... ", write => "\nWriting ... ", read => "\nReading ... ", verify => "\nVerifying ... " ENDCASE => ERROR]; errorsThisPass _ FALSE; DO firstPage: Disk.PageNumber; pageCount: Disk.PageCount; [firstPage, pageCount] _ IagoOps.NextRun[d, origin]; IF pageCount < 0 THEN EXIT; FormatDisk.Sweep[d, operation, firstPage, pageCount, @label, data]; origin _ [firstPage+pageCount]; ENDLOOP; IF NOT errorsThisPass THEN IO.PutRope[out, "no errors"]; }; IF format THEN CloseFSVolumes[]; { ENABLE { UNWIND => VM.Free[pageSpace]; FormatDisk.BadPage => { b: BadList; FOR b _ badPages, b.rest UNTIL b = NIL DO IF b.first.page = page THEN { IF b.first.correctable THEN { IF NOT correctable THEN { b.first.correctable _ FALSE; soft _ soft-1; hard _ hard+1 }; }; EXIT }; REPEAT FINISHED => { badPages _ b _ CONS[first: [page: page, correctable: correctable], rest: badPages]; IF correctable THEN soft _ soft+1 ELSE hard _ hard+1; } ENDLOOP; IF hard > 100 THEN { IO.PutRope[out, "\nThere are over 100 hard disk errors. Continue? "]; IF NOT IagoOps.Confirm[in, out] THEN CONTINUE; hard _ 0; }; IF NOT b.first.dontReport THEN { logicalDiskCyl: CARDINAL; physicalDiskCyl, physicalDiskTrack, physicalDiskSector: CARDINAL; cylinder, track, sector, temp: CARDINAL; device: DiskFace.DeviceHandle _ Disk.GetDeviceFromChannel[d]; IO.PutRope[out, IF errorsThisPass THEN ", " ELSE "\nDisk error(s): "]; errorsThisPass _ TRUE; [cylinders: physicalDiskCyl, movingHeads: physicalDiskTrack, sectorsPerTrack: physicalDiskSector] _ DiskFace.GetTrueDeviceAttributes[device]; [cylinders: logicalDiskCyl] _ DiskFace.GetDeviceAttributes[device]; IF logicalDiskCyl # physicalDiskCyl THEN { [quotient: temp, remainder: sector] _ Basics.LongDivMod[ num: page, den: physicalDiskSector ]; [quotient: track, remainder: cylinder] _ Basics.DivMod[ num: temp, den: physicalDiskCyl]; } ELSE { [quotient: cylinder, remainder: temp] _ Basics.LongDivMod[ num: page, den: physicalDiskSector * physicalDiskTrack]; [quotient: track, remainder: sector] _ Basics.DivMod[ num: temp, den: physicalDiskSector]; }; IO.PutF[out, "%bB[c:%g, t:%g, s:%g](%g)", [integer[page]], [cardinal[cylinder]], [cardinal[track]], [cardinal[sector]], [rope[IF correctable THEN "soft" ELSE "hard"]] ]; b.first.dontReport _ NOT correctable; -- suppress messages on subsequent passes }; RESUME }; }; VM.Pin[pageSpace]; IF format THEN { init: BOOL _ TRUE; Randomize: UNSAFE PROC = UNCHECKED { RandomizeOne[LOOPHOLE[LONG[@initLabel]], SIZE[Disk.Label]]; RandomizeOne[data, File.wordsPerPage]; init _ NOT init; }; RandomizeOne: UNSAFE PROC [where: LONG POINTER, nwords: CARDINAL] = UNCHECKED { array: LONG POINTER TO ARRAY OF CARDINAL = LOOPHOLE[where]; FOR i: CARDINAL IN [0..nwords) DO array[i] _ IF init THEN Basics.LowHalf[BasicTime.GetClockPulses[]] ELSE Basics.BITNOT[array[i]]; ENDLOOP; }; Randomize[]; SweepDisk[out, d, format]; SweepDisk[out, d, verify]; THROUGH [1..passes] DO Randomize[]; SweepDisk[out, d, write]; SweepDisk[out, d, verify]; ENDLOOP; } ELSE THROUGH [1..passes] DO SweepDisk[out, d, read] ENDLOOP; { p: PhysicalVolume.Physical _ NIL; IF NOT format THEN FOR p _ PhysicalVolume.NextPhysical[NIL], PhysicalVolume.NextPhysical[p] DO IF p = NIL OR PhysicalVolume.PhysicalInfo[p].channel = d THEN EXIT; ENDLOOP; IF p = NIL THEN { IO.PutRope[out, "\nCreating a physical volume to hold the bad page table ..."]; p _ FileBackdoor.CreatePhysicalVolume[ where: d, name: "JustForTheBadPageTable", id: IagoOps.NewID[]]; IO.PutRope[out, "done"]; }; IF badPages # NIL THEN { rc: PhysicalVolume.PhysicalRC _ ok; IO.PutRope[out, "\nRecording bad pages in physical bad page table ... "]; FOR b: BadList _ badPages, b.rest UNTIL b = NIL OR rc # ok DO full: BOOL _ FALSE; IF NOT b.first.correctable THEN { [full, rc] _ FileBackdoor.PhysicalPageBad[p, b.first.page]; IF full THEN { IO.PutRope[out, "\nOops, bad page table full. Aborting."]; GO TO tableFull; }; }; ENDLOOP; IF rc = ok THEN IO.PutRope[out, " done" ] ELSE ERROR File.Error[rc]; EXITS tableFull => {}; }; }; }; VM.Free[pageSpace]; }; InstallInitial: PUBLIC PROC [in, out: STREAM] = { d: Disk.Channel = IagoOps.GetDrive[in, out]; name: ROPE = IagoOps.GetFile[ in: in, out: out, extension: ".eb", default: IagoOps.InitialMicrocodeFileName[], check: TRUE ]; IO.PutRope[out, " ... installing"]; [] _ DoInitialMicrocodeInstallation[out, d, name]; }; DoInitialMicrocodeInstallation: PROC [out: STREAM, d: Disk.Channel, name: ROPE, temp: ROPE _ NIL] RETURNS [done: BOOL _ FALSE] = { cp: FS.ComponentPositions; fullFName: ROPE; pages: INT _ 0; strm: STREAM; ProduceStream: PROC [fullGName: ROPE, bytes: INT, created: BasicTime.GMT] RETURNS [STREAM] = { pages_ VM.PagesForBytes[bytes]; RETURN[strm_ IO.ROS[]]; }; { [fullFName, cp, ]_ FS.ExpandName[name]; IF cp.server.length # 0 THEN { FSRemoteFile.Retrieve[fullFName.Substr[cp.server.start, cp.server.length], fullFName.Substr[cp.dir.start-1], BasicTime.nullGMT, ProduceStream ! FS.Error => { out.PutChar['\n]; out.PutRope[error.explanation]; GO TO finish}]; IF strm = NIL THEN GOTO noFile; strm_ IO.RIS[IO.RopeFromROS[strm], strm]; } ELSE { strm _ FS.StreamOpen[fullFName ! FS.Error => { out.PutChar['\n]; out.PutRope[error.explanation]; GO TO finish}]; pages_ VM.PagesForBytes[strm.GetLength[]]; }; strm.SetIndex[0]; TRUSTED { VMReader: UNSAFE PROC [ ptr: LONG POINTER]RETURNS [ok: BOOL _ TRUE] = { index: INT; { IF pages <= 0 THEN RETURN[FALSE]; FOR i: INT IN [0 .. VM.wordsPerPage) DO ENABLE IO.EndOfStream => {index_ i; GOTO eos}; val: Basics.BytePair; val.high_ LOOPHOLE[strm.GetChar[], Basics.BYTE]; val.low_ LOOPHOLE[strm.GetChar[], Basics.BYTE]; (ptr + i)^_ LOOPHOLE[val, WORD]; ENDLOOP; pages _ pages-1; EXITS eos => { FOR j: INT IN [index .. VM.wordsPerPage) DO (ptr + j)^_ 0; ENDLOOP; pages_ 0; }; }; }; FormatDisk.InstallInitialMicrocode[d, VMReader ! FormatDisk.MicrocodeInstallFailure => { IO.PutRope[out, SELECT why FROM emptyFile => "empty microcode file", firstPageBad => "first page of microcode area of disk is bad", flakeyPageFound => "bad page in microcode area of disk", microcodeTooBig => "microcode too big for fixed area of disk", other => "other error during installation", ENDCASE => "unknown error during installation"]; GO TO finish; } ]; }; done _ TRUE; IO.PutRope[out, " done."]; GO TO finish; EXITS noFile => {}; finish => {IF strm # NIL THEN strm.Close[ ! IO.Error => CONTINUE]}; }; }; }. ˜IagoCommands1Impl.mesa - Iago commands implementation Copyright c 1984, 1985, 1986 by Xerox Corporation. All rights reserved. Willie-Sue, August 13, 1984 3:29:51 pm PDT Russ Atkinson (RRA) May 2, 1986 6:14:14 pm PDT Hal Murray, January 20, 1986 5:49:09 pm PST ******** The command subroutines (alphabetic order) ******** Room for a physical memory image plus possible junk Has to be trusted because BootFile.MemorySizeToFileSize is misdeclared! [page: Disk.PageNumber, correctable: BOOL] Abnormal cyl/track/sect numbering on a Dorado for Alto compatability Normal cyl/track/sect numbering First, set label and data to random values Record any bad pages Κ˜codešœ5™5Kšœ Οmœ=™HK™*K™.K™+K™šΟk ˜ Kšœžœžœžœ*˜EKšœ žœ žœ˜JKšœ žœ˜&Kšœžœ˜+Kšœ žœ˜'Kšœžœ˜Kšœžœ]˜gKšœ žœ>˜LKšœžœžœSžœE˜ΓKšœ žœ‡˜™Kšœ žœi˜yKšžœžœŸ˜§Kšœ žœB˜RKšœ žœ ˜Kšœ žœ ˜K˜ KšœΟcœ˜Kš žœžœ^žœžœ žœ˜ƒKšœžœb˜vKšœžœžœ ˜/KšœžœJ˜]Kšœ žœ˜(Kšœžœ˜$Kšžœžœc˜kKšœ žœ ˜——K˜šΟnœžœž˜ Kšžœyžœ3žœEžœ ˜ŠKšžœ˜K˜Kšžœžœžœ˜Kšžœžœžœžœ˜—˜K˜—šœ>™>K˜š œž œ žœ˜)šœžœ˜K˜K˜ K˜Kšœžœ˜ —šœžœ˜K˜K˜ K˜—Kšžœ˜Kšœžœ'žœ žœ˜CKšžœ˜Kšœ˜—K˜š  œžœžœ žœ˜.K˜-Kšœžœ<˜HKšžœ4˜6Kšœ˜—K˜š œž œ žœ˜'šœžœ˜K˜K˜ K˜Kšœžœ˜ —šœžœ˜K˜K˜ K˜—Kšžœ˜Kšœžœ˜!Kšžœ˜Kšœ˜—K˜š  œž œ žœ˜0šœžœžœ2ž˜DKšžœ˜Kšžœžœ˜ —Kšœžœ˜ K˜Kšœžœ˜ š  œžœ˜šžœ ˜KšœL˜L—Kšœ˜—šž˜šœ˜K˜K˜ K˜Kšœ˜K˜—šžœ!ž˜&Kšžœžœ$˜+Kšžœž˜ —Kšžœ˜—K˜!K˜!K˜+KšœC˜CKšžœ"˜$šžœžœ˜"Kšœžœ˜Kšžœ˜šœ'˜'Kšœžœ˜=—Kšžœ˜Kšœ˜šžœ ˜Kšœ6˜6—Kšžœžœ žœ˜FKšœ˜—Kšœ˜—K˜š œžœ˜šžœ"žœžœž˜NKšœ˜Kšžœ˜—Kšœ˜K˜—š  œž œ žœžœžœžœ˜Mš  œžœ˜KšžœK˜MKšœ˜—Kšœ,˜,Kšœžœ'žœ#˜Wšœžœ˜K˜K˜ K˜Kšœ˜K˜—šžœ1˜3Kš œžœžœžœžœ˜Nšžœ˜K˜K˜K˜SK˜#Kšœžœ˜ Kšœ)˜)Kšœžœ˜%Kšœ˜——Kšœ˜—K˜š œž œ žœ˜2š œžœE˜SKšœžœ3˜=Kšœžœ%˜1Kšœžœ$˜/Kšœžœ ˜K˜Kšœžœ˜KšžœY˜[Kšœžœ+˜2Kšœ žœ+˜:Kšœ žœ,˜7Kšœ(˜(Kšœ"˜"Kšžœ?˜AKšžœ˜Kšžœ˜Kšœ˜—K˜Kšœžœ˜Kšœ žœžœ˜Kšœžœ˜"Kšœ žœ'˜7Kšœ žœ%˜3Kšœ#žœ˜(K˜K˜šœžœ˜Kšœ3™3—Kšœžœ˜šžœ˜ šœE˜EKšœG™G—K˜—Kšžœ˜Kšœ$˜$šžœ"ž˜)Kšœ0˜0—KšžœΕ˜ΗKšœ žœ˜&KšžœA˜CK˜#šžœž˜šœ!˜!Kšœ7˜7Kšœ+˜+K˜9Kšœ˜—Kšžœ˜—KšžœC˜Ešžœž˜KšžœC˜E—KšžœR˜Tšžœ ˜ Kšœƒ˜ƒKšœ˜—šžœžœ˜"Kšœ?˜?Kšžœžœ˜ —K˜Kšžœ˜šžœžœžœ˜Kšœ/žœ˜B—Kšžœ1˜3K˜VK˜$Kšœ!žœ žœžœ ˜EKšžœ˜Kšžœ:˜<šœ(˜(Kšœ˜Kšœžœ˜Kšœ-˜-Kšœ˜—Kšžœ(˜*K˜Kšžœ˜Kšœ&˜&K˜'K˜"K˜&Kšœ0˜0Kšœ+˜+Kšœ/˜/šœ˜Kšœžœ&˜0Kšžœ˜!Kšžœ˜šžœPž˜Wšœ˜Kšœ˜Kšœ˜——Kšœ˜—Kšœ˜—K˜š œžœžœ žœ˜+K˜4šœžœ˜KšœV˜V—Kšœ žœžœ˜0Kšœžœ˜šžœžœ˜8Kšœžœžœžœ˜4—šžœ ž˜šžœ˜šžœ ˜ Kšœ™˜™—šžœžœ˜"Kšžœ5žœ˜Q—Kšœ˜—KšžœŸ˜=—Kšœ˜K˜—š  œžœžœ žœ ˜4šžœž˜Kšœ˜Kšœ˜Kšœ˜Kšžœ˜—K˜—K˜š  œžœžœžœ˜?Kšœ žœ ˜Kšœ žœ˜&Kšœžœ;žœ˜LKšžœ3˜5Kšœ@˜@Kšœžœ%˜˜@Kšžœ˜Kšœ˜—šœ ˜ KšžœA˜CKšžœ˜Kšœ˜—šœ ˜ Kšžœ@˜BKšžœ˜Kšœ˜—Kšžœžœ˜(—Kšžœ)˜+Kšžœžœžœ-˜RKšžœ,˜.Kšžœžœžœ'žœ˜Všžœ ž˜Kšœžœ2˜:Kšœžœ<˜MKšœžœ,˜>Kšœ žœ4˜BKšœ žœ3˜AKšœžœ5˜FKšœžœ5˜FKšžœžœ˜'—šžœžœž˜-Kšœ˜Kšžœ˜—Kšœ˜Kšžœ˜—Kšœ˜—K˜š  œžœžœ*˜JKšœ žœ"˜-K˜Kšœžœ˜ Kšžœžœžœ˜ šžœ&˜(šœžœž˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšžœ ˜ Kšžœ ˜ Kšœ˜Kšœ˜Kšžœ˜—Kšœ žœ ˜Kšœ žœ ˜K˜—šœ&žœ˜(Kšžœ˜Kšžœ&˜(Kšœžœ˜ Kšžœ˜ —šžœžœ˜šžœžœ ˜Kšžœ˜Kšžœ"˜$Kšžœžœ˜&Kšžœžœ!˜(Kšž˜Kšœ˜—Kšžœ<˜>Kšœ(˜(Kšžœžœ˜3Kšœ˜—Kšœ˜—K˜š œž œ žœ˜2šžœ ˜ KšœM˜Mšœžœž˜+K˜K˜K˜K˜Kšžœ"˜)—Kšœ(˜(Kšœ2˜2Kšœ&˜&K˜ —KšžœY˜[šœ˜šžœ˜ Kšžœ˜!Kšžœ˜ Kšœ˜—KšžœL˜NKšœ˜—šžœžœ˜Kšžœžœ'˜.—šžœžœ!˜'Kšžœžœ0˜7—Kšœ˜—K˜š  œž œ žœ˜-š žœ:žœ"žœžœž˜rKšœ!˜!Kšžœ˜—š žœ:žœ"žœžœž˜rKšœ˜Kšœ&˜&Kšœ˜Kšœžœ˜ Kšœ˜Kšœ˜šœX˜XK˜—Kšžœ˜Kšœ˜KšžœR˜Tšžœ ž˜KšœžŸ!œ˜,šœ˜Kšžœ'˜)Kšžœ˜—šœ˜Kšžœ>˜@Kšžœ˜—šœ ˜ KšžœA˜CKšžœ˜—šœ ˜ Kšžœ@˜BKšžœ˜—Kšžœžœ˜(—šžœ˜ Kšœžœ˜Kšœžœ˜Kšœžœ˜ KšœP˜Pšžœž˜šžœ3˜5K˜——Kšœ˜—šžœH˜JKšœ ˜ Kšœ˜Kšœ˜Kšœ˜—šœ˜K˜@šžœžœžœž˜#KšžœR˜TKšœ˜šžœ˜ Kšœ˜Kšœ!˜!Kšœ˜—Kšžœ˜—Kšœ˜——Kšžœ˜Kšœ˜—K˜š  œž œ žœ˜/K˜-šžœAžœ˜JKšžœ ˜"Kšœ˜Kšžœ˜K˜Kšœ˜—Kšœ˜—K˜š   œž œ žœ žœžœ˜EKšœ,˜,Kšœžœ'žœ#˜Wšœžœ&˜1K˜*K˜Z—šžœžœ˜ šžœ1˜3Kšœ˜Kšžœžœžœžœ˜5—Kšžœ,˜0—Kšœ˜K˜—š œžœžœ žœžœ žœž œ˜gK˜Kšœ žœ žœ žœ#˜JKšœžœžœžœ&˜=Kšœ žœ˜š œ žœžœžœžœ˜Kšœ$žœžœžœ˜D—Kšœžœ˜Kšœžœ˜š   œžœžœžœ6ž œ˜dKšœ˜K˜šžœžœ ž˜%Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšžœžœ˜—Kšœžœ˜šžœ7˜9Kšœ4˜4Kšžœžœžœ˜KšœC˜CKšœ˜—Kšžœ˜Kšžœžœžœžœ˜8Kšœ˜—Kšžœžœ˜ šœ˜šžœ˜Kšžœžœ˜šœ˜Kšœ%žœ™*Kšœ ˜ šžœžœž˜)šžœžœ˜šžœ˜šžœ˜Kšžœžœ ˜Kšžœžœ!˜CKšœ˜——Kšž˜Kšœ˜—šžœžœ˜šœ˜Kšžœ@˜D—Kšžœ žœžœ˜5Kšœ˜—Kšžœ˜—šžœ žœ˜KšžœD˜FKšžœžœžœžœ˜.K˜ Kšœ˜—šžœžœžœ˜ Kšœžœ˜Kšœ8žœ˜AKšœžœ˜(Kšœ=˜=Kšžœžœžœžœ˜FKšœžœ˜Kšœ˜KšœC˜Cšžœ!˜#šžœ˜KšœE™EKšœ^˜^KšœY˜YK˜—šžœ˜Kšœ™šœ:˜:Kšœ8˜8—šœ5˜5Kšœ$˜$—Kšœ˜——šžœ'˜)KšœM˜MKšœžœ žœžœ ˜1—KšœžœŸ)˜OKšœ˜—Kšž˜Kšœ˜—Kšœ˜—Kšžœ˜šžœ˜ šžœ˜Kšœžœžœ˜š  œžœžœž œ˜$Kšœ žœžœžœ˜;Kšœ&˜&Kšœžœ˜Kšœ˜—š  œžœžœ žœžœ žœž œ˜OKšœžœžœžœžœžœžœžœ˜;šžœžœžœ ž˜!šœ žœ˜Kšžœ+˜/Kšžœžœ ˜—Kšžœ˜—Kšœ˜—K˜ K˜K˜Kšžœ ˜šž˜Kšœ*™*K˜ Kšœ˜Kšœ˜—Kšžœ˜Kšœ˜—Kšžœžœ žœžœ˜<—Kšœ™šœ˜Kšœžœ˜!šžœžœž˜šžœ!žœ"ž˜KKš žœžœžœ,žœžœ˜CKšžœ˜——šžœžœ˜KšžœM˜O˜&K˜?—Kšžœ˜Kšœ˜—šžœ žœžœ˜K˜#KšžœG˜Iš žœžœžœžœ ž˜=Kšœžœžœ˜šžœžœžœ˜!Kšœ;˜;šžœžœ˜Kšžœ9˜;Kšžœžœ ˜K˜—K˜—Kšžœ˜—Kš žœ žœžœžœžœ˜DKšžœ˜Kšœ˜——Kšœ˜—Kšœ˜Kšžœ˜Kšœ˜—K˜š œž œ žœ˜1K˜,šœžœ˜K˜K˜Kšœ,˜,Kšœž˜ K˜—Kšžœ!˜#Kšœ2˜2Kšœ˜—K˜š œžœžœžœžœžœžœžœžœ˜‚Kšœžœ˜Kšœ žœ˜Kšœžœ˜Kšœžœ˜ š  œžœ žœ žœžœžœžœ˜^Kšœžœ˜Kšžœžœžœ˜Kšœ˜—K˜šœ˜Kšœžœ˜'šžœ˜šžœ˜šœ˜Kšœžœ>žœžœ ˜Q—Kšžœžœžœžœ˜Kšœžœžœžœ˜)Kšœ˜—šžœ˜šœžœ˜Kšœžœ>žœžœ ˜Q—Kšœžœ!˜*Kšœ˜K˜——K˜šžœ˜ š œžœžœžœžœžœžœžœ˜GKšœžœ˜ šœ˜Kšžœ žœžœžœ˜!š žœžœžœžœž˜'Kšžœžœžœ˜.Kšœ˜Kšœ ž œžœ˜0Kšœ ž œžœ˜0Kšœ žœžœ˜ Kšžœ˜ K˜—K˜šž˜šœ˜Kš žœžœžœ žœžœžœ˜DK˜ Kšœ˜——Kšœ˜—Kšœ˜—šœ.˜.šœ)˜)šžœžœž˜Kšœ$˜$Kšœ>˜>Kšœ8˜8Kšœ>˜>Kšœ+˜+Kšžœ)˜0—Kšžœžœ˜ Kšœ˜——Kšœ˜—Kšœžœ˜ Kšžœ˜Kšžœžœ˜ šž˜Kšœ ˜ Kš œ žœžœžœžœ žœ˜C—Kšœ˜—Kšœ˜—K˜—Kšœ˜—…—b3