<> <> <> <> DIRECTORY BasicTime USING [FromPupTime, GMT, OutOfRange], ConvertUnsafe USING [ToRope], Disk USING [Channel, Command, defaultTries, DoIO, GetBootChainLink, Label, PageCount, PageNumber, Request, Status], DiskFace USING [DontCare], FormatDisk, PrincOps USING [zEXCH], Rope USING [ROPE], VM USING [AddressForPageNumber, Allocate, Free, Interval, Pin, Unpin]; FormatDiskD0: MONITOR -- only one guy in here at a time! IMPORTS BasicTime, ConvertUnsafe, Disk, VM EXPORTS FormatDisk = { OPEN FormatDisk; <<>> <> BadPage: PUBLIC SIGNAL [page: Disk.PageNumber, correctable: BOOLEAN] = CODE; Error: PUBLIC ERROR [page: Disk.PageNumber, status: Disk.Status] = CODE; Sweep: PUBLIC ENTRY PROC [channel: Disk.Channel, operation: Operation, firstPage: Disk.PageNumber, pageCount: Disk.PageCount, label: LONG POINTER TO Disk.Label, data: LONG POINTER] = { IF operation=format THEN { initialLabel: Disk.Label _ label^; Transfer[channel: channel, firstPage: firstPage, pageCount: pageCount, command: [write, noOp, noOp], label: label, data: data, reportSoftErrors: TRUE]; label^ _ initialLabel; }; Transfer[channel: channel, firstPage: firstPage, pageCount: pageCount, command: commandTable[operation], label: label, data: data, reportSoftErrors: TRUE]; }; commandTable: ARRAY Operation OF Disk.Command = [ format: [verify, write, write], -- see code above; Dolphin can't do [write, write, write] write: [verify, write, write], read: [verify, read, read], verify: [verify, verify, verify]]; <<>> <> MicrocodeInstallFailure: PUBLIC SIGNAL [why: FailureType] = CODE; InstallInitialMicrocode: PUBLIC ENTRY PROC [channel: Disk.Channel, getPage: PROC [ptr: LONG POINTER] RETURNS [ok: BOOLEAN]] = { label: Disk.Label; vmInterval: VM.Interval _ VM.Allocate[count: 1]; pageBuffer: LONG POINTER _ VM.AddressForPageNumber[vmInterval.page]; thisPage: Disk.PageNumber _ hardUCodeStart; prevPage: Disk.PageNumber _ [hardUCodeStart-1]; VM.Pin[vmInterval]; { ENABLE UNWIND => {VM.Unpin[vmInterval]; VM.Free[vmInterval]}; DO ok: BOOLEAN; IF (ok _ getPage[pageBuffer]) THEN { ENABLE BadPage, Error => IF thisPage=hardUCodeStart THEN GOTO firstPageBad ELSE {thisPage _ [thisPage+1]; RETRY}; IF thisPage>=hardUCodeStart+hardUCodeSize THEN ERROR MicrocodeInstallFailure[microcodeTooBig]; label _ initialMicrocodeLabel; label.dontCare _ channel.GetBootChainLink[[thisPage+1]]; Transfer[channel: channel, firstPage: thisPage, pageCount: 1, command: [verify, write, write], label: @label, data: pageBuffer]; label _ initialMicrocodeLabel; Transfer[channel: channel, firstPage: thisPage, pageCount: 1, command: [verify, verify, verify], label: @label, data: pageBuffer]; }; IF thisPage#Disk.PageNumber[prevPage+1] OR ~ok THEN { ENABLE BadPage, Error => GOTO flakeyPageFound; label _ initialMicrocodeLabel; Transfer[channel: channel, firstPage: prevPage, pageCount: 1, command: [verify, verify, read], label: @label, data: pageBuffer]; label _ initialMicrocodeLabel; label.dontCare _ IF ok THEN channel.GetBootChainLink[thisPage] ELSE eofLink; Transfer[channel: channel, firstPage: prevPage, pageCount: 1, command: [verify, write, write], label: @label, data: pageBuffer]; }; IF ~ok THEN EXIT; thisPage _ [(prevPage _ thisPage)+1]; REPEAT firstPageBad => ERROR MicrocodeInstallFailure[firstPageBad]; flakeyPageFound => ERROR MicrocodeInstallFailure[flakeyPageFound]; ENDLOOP; }; VM.Unpin[vmInterval]; VM.Free[vmInterval]; }; IdentifyInitialMicrocode: PUBLIC ENTRY PROC [channel: Disk.Channel] RETURNS [microcodeInstalled: BOOLEAN, time: BasicTime.GMT, name: Rope.ROPE] = { label: Disk.Label _ initialMicrocodeLabel; vmInterval: VM.Interval _ VM.Allocate[count: 1]; uCodeHeader: LONG POINTER TO MicrocodeHeader _ VM.AddressForPageNumber[vmInterval.page]; VM.Pin[vmInterval]; microcodeInstalled _ FALSE; { Transfer[channel: channel, firstPage: hardUCodeStart, pageCount: 1, command: [verify, verify, read], label: @label, data: uCodeHeader ! BadPage, Error => GOTO error]; IF uCodeHeader.name.length IN [1..uCodeHeader.name.maxlength] AND uCodeHeader.name.maxlength<=maxNameLength THEN { time _ BasicTime.FromPupTime[GMTFromBCPLTime[uCodeHeader.createDate] ! BasicTime.OutOfRange => GOTO error]; name _ ConvertUnsafe.ToRope[@uCodeHeader.name]; microcodeInstalled _ TRUE; }; EXITS error => NULL; }; VM.Unpin[vmInterval]; VM.Free[vmInterval]; }; hardUCodeFileID: ARRAY [0..5) OF CARDINAL = [0, 0, 0, 0, 0]; -- boot microcode knows this ID initialMicrocodeLabel: Disk.Label = [fileID: [abs[LOOPHOLE[hardUCodeFileID]]], filePage: 0, attributes: LOOPHOLE[0], dontCare: LOOPHOLE[LONG[0]]]; -- boot microcode knows this label. All pages of the initial microcode have the same label, except for the boot chain link which is filled in for every page. That is, the initial microcode is not a well-formed file. nullLink: DiskFace.DontCare = LOOPHOLE[LONG[0]]; eofLink: DiskFace.DontCare = LOOPHOLE[LONG[-1]]; MicrocodeHeader: TYPE = MACHINE DEPENDENT RECORD [ version (0): CARDINAL, mustBeZero (1): LONG CARDINAL, createDate (3): BCPLTime, name (5): StringBody]; BCPLTime: TYPE = RECORD [LONG CARDINAL]; GMTFromBCPLTime: PROCEDURE [BCPLTime] RETURNS [LONG CARDINAL] = <> MACHINE CODE {PrincOps.zEXCH}; maxNameLength: CARDINAL = 40; <<>> <> hardUCodeStart: PUBLIC Disk.PageNumber _ [28]; hardUCodeSize: PUBLIC Disk.PageCount _ 224-hardUCodeStart; altoRegionJargon: PUBLIC Rope.ROPE _ "model 44s"; altoRegionsMax: PUBLIC INT _ 4; altoRegionsStart: PUBLIC Disk.PageNumber _ [hardUCodeStart+hardUCodeSize]; altoRegionsSize: PUBLIC Disk.PageCount _ 406*28; altoRegionsBottomUp: PUBLIC BOOL _ TRUE; -- prefer first model 44 <<>> <> Start: PUBLIC PROC = {}; <<>> <> Transfer: PROC [channel: Disk.Channel, firstPage: Disk.PageNumber, pageCount: Disk.PageCount, command: Disk.Command, label: LONG POINTER TO Disk.Label, data: LONG POINTER, reportSoftErrors: BOOLEAN _ FALSE] = <> { retrying: BOOLEAN _ FALSE; WHILE pageCount>0 DO <> request: Disk.Request _ [diskPage: firstPage, data: data, incrementDataPtr: FALSE, command: command, tries: IF reportSoftErrors AND ~retrying THEN 1 ELSE Disk.defaultTries, count: IF retrying THEN 1 ELSE pageCount]; countDone: Disk.PageCount; status: Disk.Status; [status: status, countDone: countDone] _ channel.DoIO[label: label, request: @request]; WITH s: status SELECT FROM changed => ERROR Error[firstPage, status]; unchanged => SELECT s.status FROM goodCompletion => IF retrying THEN {retrying _ FALSE; SIGNAL BadPage[firstPage, TRUE]}; notReady, recalibrateError, seekTimeout, memoryError, memoryFault, clientError, operationReset => ERROR Error[firstPage, status]; ENDCASE => { IF ~retrying THEN retrying _ TRUE ELSE { retrying _ FALSE; SIGNAL BadPage[firstPage, FALSE]; countDone _ countDone+1; -- skip over the bad page label.filePage _ label.filePage+1; }; }; ENDCASE => ERROR; pageCount _ pageCount-countDone; firstPage _ [firstPage+countDone]; ENDLOOP; }; }.