--LTCopyVMemImpl.mesa --Created by -- JFung.PASA 19-Dec-83 11:35:03 --last edited by -- JFung.PASA 4-Sep-84 15:44:53 DIRECTORY CmFile, Display, Environment, Event, Exec, File, FileTypes, FileTransfer, FormSW, Heap, Inline, LispToolOps, OthelloDefs, OthelloOps, Process, Put, Runtime, Space, String, TemporaryBooting, Time, Token, Tool, ToolDriver, ToolWindow, UserInput, Version, Volume, Window; LTCopyVMemImpl: PROGRAM IMPORTS Display, File, FormSW, Heap, Inline, LispToolOps, OthelloDefs, OthelloOps, Process, Put, Runtime, Space, String, TemporaryBooting, Time, Tool, ToolDriver, UserInput, Version, Volume, Window EXPORTS LispToolOps = BEGIN OPEN ILT: LispToolOps, OthelloOps; -- TYPEs Indicator: TYPE = {off, left, right}; Graphic: TYPE = ARRAY[0..16) OF WORD; VolHints: TYPE = RECORD [names: SEQUENCE length: CARDINAL OF LONG STRING]; SizeHints: TYPE = RECORD [names: SEQUENCE length: CARDINAL OF CARDINAL]; DataHandle: TYPE = LONG POINTER TO Data; Data: TYPE = MACHINE DEPENDENT RECORD [ -- Message subwindow stuff msgSW(0): Window.Handle ← NIL, -- File subwindow stuff fileSW(2): Window.Handle ← NIL, -- Form subwindow stuff -- Note: enumerateds and booleans must be word boundary -- aligned as addresses for them must be generated --formSW: Window.Handle ← NIL, paramSW(4): Window.Handle ← NIL, commandSW(6): Window.Handle ← NIL, busy(8): BOOLEAN ← FALSE, -- command is running destVolName(9): LONG STRING ← NIL, srcVolName(11): LONG STRING ← NIL, connection(13): FileTransfer.Connection ← NIL, indicator(15): Indicator ← left]; active: BOOLEAN ← FALSE; buffer: LONG POINTER ← NIL; copyWH: Window.Handle ← NIL; debug: BOOLEAN ← FALSE; toolData: DataHandle ← NIL; formDisplay: ToolWindow.DisplayProcType ← NIL; indicatorBox: Window.Box = [[10, 10], [16, 16]]; volume: Volume.ID ← Volume.nullID; -- taken from FloppyFileToo yinLeft: Graphic = [001600B, 006140B, 014020B, 034410B, 074004B, 076004B, 177402B, 177702B, 177742B, 077744B, 077744B, 037350B, 017760B, 007740B, 001600B, 000000B]; yangRight: Graphic = [001600B, 007740B, 017760B, 027370B, 047774B, 047774B, 103776B, 100776B, 100176B, 040074B, 040074B, 020470B, 010060B, 006140B, 001600B, 000000B]; BootStuff: PUBLIC PROCEDURE = BEGIN IF toolData = NIL THEN toolData ← Heap.systemZone.NEW[Data ← []]; IF debug THEN { Put.Line[ILT.toolData.fileSW, "MakeTool...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; copyWH ← MakeTool[]; END; ClearCommandSubwindow: PROCEDURE = BEGIN item: FormSW.ItemHandle; FOR i: CARDINAL ← 0, i + 1 UNTIL (item ← FormSW.FindItem[toolData.commandSW, i]) = NIL DO item.flags.invisible ← TRUE ENDLOOP; FormSW.Display[toolData.commandSW]; toolData.indicator ← left; formDisplay ← Window.GetDisplayProc[toolData.commandSW]; [] ← Window.SetDisplayProc[toolData.commandSW, DisplayEmpty]; END; --ClearCommandSubwindow ClearFileSubwindow: PROCEDURE = BEGIN item: FormSW.ItemHandle; FOR i: CARDINAL ← 0, i + 1 UNTIL (item ← FormSW.FindItem[toolData.fileSW, i]) = NIL DO item.flags.invisible ← TRUE ENDLOOP; FormSW.Display[toolData.fileSW]; --formDisplay ← Window.GetDisplayProc[toolData.fileSW]; END; --ClearFileSubwindow ClearMsgSubwindow: PROCEDURE = BEGIN item: FormSW.ItemHandle; FOR i: CARDINAL ← 0, i + 1 UNTIL (item ← FormSW.FindItem[toolData.msgSW, i]) = NIL DO item.flags.invisible ← TRUE ENDLOOP; FormSW.Display[toolData.msgSW]; --formDisplay ← Window.GetDisplayProc[toolData.msgSW]; END; --ClearMsgSubwindow ClearSubWindows: PROCEDURE = BEGIN --ClearFileSubwindow; ClearMsgSubwindow; END; --ClearSubWindows CloseVolume: PUBLIC PROC [vID: Volume.ID] RETURNS [vOpen: BOOLEAN] = BEGIN IF vOpen THEN {Volume.Close[vID]; vOpen ← FALSE; } END; << ClientTransition: ToolWindow.TransitionProcType = -- This procedure is called whenever the system determines that this -- Tool's state is undergoing a user invoked transition. -- In this Example we demonstrate a technique that minimizes the memory -- requirements for a Tool that is inactive. BEGIN SELECT TRUE FROM old = inactive => BEGIN IF toolData = NIL THEN toolData ← Heap.systemZone.NEW[Data ← []]; active ← TRUE; END; new = inactive => BEGIN IF toolData # NIL THEN BEGIN FormSW.Destroy[toolData.paramSW]; FormSW.Destroy[toolData.commandSW]; Heap.systemZone.FREE[@toolData]; END; --ToolDriver.RemoveSWs[tool: "LispTool"L]; active ← FALSE; END; ENDCASE END; --ClientTransition >> DisplayCommandSubwindow: PROCEDURE = BEGIN item: FormSW.ItemHandle; toolData.indicator ← off; [] ← Window.SetDisplayProc[toolData.commandSW, formDisplay]; FormSW.Display[toolData.commandSW]; FOR i: CARDINAL ← 0, i + 1 UNTIL (item ← FormSW.FindItem[toolData.commandSW, i]) = NIL DO item.flags.invisible ← FALSE ENDLOOP; FormSW.Display[toolData.commandSW]; END; --DisplayCommandSubwindow DisplayEmpty: ToolWindow.DisplayProcType = BEGIN ENABLE UNWIND => NULL; IF ~toolData.busy THEN RETURN; DisplayIndicator[window]; END; DisplayIndicator: ToolWindow.DisplayProcType = { --pattern: ARRAY [0..1] OF ARRAY [0..8) OF WORD; pattern: Graphic; SELECT toolData.indicator FROM left => { pattern ← yinLeft; Display.Bitmap[ window, indicatorBox, [@pattern, , 0], 16, Display.replaceFlags]}; right => { pattern ← yangRight; Display.Bitmap[ window, indicatorBox, [@pattern, , 0], 16, Display.replaceFlags]}; ENDCASE}; --DisplayIndicator DoInstall: UserInput.PeriodicProcType = BEGIN IF debug THEN { Put.Line[toolData.fileSW, "Start Install ....."L]; Process.Pause[Process.SecondsToTicks[5]]; }; ClearMsgSubwindow; ClearCommandSubwindow; DisplayIndicator[toolData.commandSW]; toolData.busy ← TRUE; IF Retrieve[] THEN BEGIN Put.Line[toolData.fileSW, "\n Boot destination volume?"L]; IF ILT.Confirm[] THEN TemporaryBooting.BootButton[]; END; DisplayCommandSubwindow; toolData.busy ← FALSE; END; --DoInstall FormCopyVMem: FormSW.ProcType = BEGIN IF debug THEN { Put.Line[toolData.fileSW, "FormCopyVMem...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; [] ← UserInput.CreatePeriodicNotify[ proc: DoInstall, window: sw, rate: 0]; END; FormSWQuit: FormSW.ProcType = BEGIN IF toolData # NIL THEN BEGIN Tool.Destroy[copyWH]; Heap.systemZone.FREE[@toolData]; END; END; FormSWVolHintsProc: FormSW.MenuProcType = BEGIN RETURN[ hints: DESCRIPTOR[ @ILT.toolData.volHints[0], ILT.toolData.volHints.length], freeHintsProc: HintsNoLongerBusy, replace: TRUE]; END; HintsNoLongerBusy: FormSW.FreeHintsProcType = BEGIN END; InvertIndicator: PROC [] = BEGIN ENABLE UNWIND => NULL; pattern: Graphic ← yinLeft; IF ~toolData.busy THEN RETURN; SELECT toolData.indicator FROM left => { toolData.indicator ← right; pattern ← yangRight; }; off, right => { toolData.indicator ← left; pattern ← yinLeft; }; ENDCASE; Display.Bitmap[ toolData.commandSW, indicatorBox, [@pattern, , 0], 16, Display.replaceFlags]; <<Display.Bitmap[ window: data.commandSW, box: indicatorBox, address: [word: @pattern, bit: 0], bitmapBitWidth: 16, flags: Display.replaceFlags];>> END; MakeCommands: FormSW.ClientItemsProcType = BEGIN OPEN FormSW; tabs: ARRAY [0..2) OF CARDINAL ← [0, 60]; nItems: CARDINAL = 2; items ← AllocateItemDescriptor[nItems]; items[0] ← CommandItem[tag: "Start"L, place: newLine, proc: FormCopyVMem]; items[1] ← CommandItem[tag: "Quit"L, place: newLine, proc: FormSWQuit]; SetTagPlaces[items, DESCRIPTOR[tabs], FALSE]; RETURN[items, TRUE]; END; --MakeCommands MakeParams: FormSW.ClientItemsProcType = BEGIN OPEN FormSW; i, nVols: CARDINAL; tabs: ARRAY [0..4) OF CARDINAL ← [0, 30, 60, 75]; nItems: CARDINAL = 2; items ← AllocateItemDescriptor[nItems]; nVols ← ILT.ListLogicalVolumes[]; << String.Copy[toolData.destVolName, ILT.toolData.volHints[0]]; FOR i IN [0..nVols) DO IF String.Equivalent[ILT.toolData.volHints[i], "Lisp"L] THEN BEGIN String.Replace[ @toolData.destVolName, ILT.toolData.volHints[i], Heap.systemZone]; EXIT; END; ENDLOOP; >> String.Copy[toolData.srcVolName, ILT.toolData.volHints[0]]; FOR i IN [0..nVols) DO IF String.Equivalent[ILT.toolData.volHints[i], "Lisp"L] THEN BEGIN String.Replace[ @toolData.srcVolName, ILT.toolData.volHints[i], Heap.systemZone]; EXIT; END; ENDLOOP; items[0] ← StringItem[ tag: "Source Volume"L, place: newLine, string: @toolData.srcVolName, inHeap: TRUE, menuProc: FormSWVolHintsProc]; items[1] ← StringItem[ tag: "Dest. Volume"L, string: @toolData.destVolName, inHeap: TRUE, menuProc: FormSWVolHintsProc]; SetTagPlaces[items, DESCRIPTOR[tabs], FALSE]; RETURN[items, TRUE] END; --MakeParams MakeSWs: Tool.MakeSWsProc = BEGIN addresses: ARRAY [0..4) OF ToolDriver.Address; logName: STRING ← [20]; Tool.UnusedLogName[unused: logName, root: "CopyOption.log"L]; toolData.msgSW ← Tool.MakeMsgSW[window: window, lines: 1]; toolData.paramSW ← Tool.MakeFormSW[window: window, formProc: MakeParams]; toolData.commandSW ← Tool.MakeFormSW[ window: window, formProc: MakeCommands]; --note: logName is compulsory, else it bombs toolData.fileSW ← Tool.MakeFileSW[window: window, name: logName]; --Supervisor.AddDependency[client: agent, implementor: Event.toolWindow]; -- do the ToolDriver stuff addresses ← [ [name: "msgSW"L, sw: toolData.msgSW], --[name: "formSW"L, sw: toolData.formSW], [name: "ParamSW"L, sw: toolData.paramSW], [ name: "CmdSW"L, sw: toolData.commandSW], [ name: "fileSW"L, sw: toolData.fileSW]]; ToolDriver.NoteSWs[ tool: "Boot Options"L, subwindows: DESCRIPTOR[addresses]]; END; MakeTool: PROCEDURE RETURNS [wh: Window.Handle] = BEGIN heraldName: STRING ← [80]; String.AppendString[heraldName, "System Tools: Copy VMem"L]; --String.AppendString[heraldName, " of "L]; --Time.Append[heraldName, Time.Unpack[Runtime.GetBcdTime[]]]; --heraldName.length ← heraldName.length - 3; --String.AppendString[heraldName, " on Pilot Version "L]; --Version.Append[heraldName]; RETURN[ Tool.Create[ makeSWsProc: MakeSWs, initialState: default, --clientTransition: ClientTransition, name: heraldName, initialBox: [[512, 400], [512, 400]], tinyName1: "Copy"L, tinyName2: "VMem"L]] END; Retrieve: PROC[] RETURNS [BOOLEAN] = BEGIN OPEN OthelloOps; access: Space.Access ← readWrite; base: LONG POINTER ← NIL; bufferPages: Space.PageCount = 100; created: BOOLEAN ← FALSE; destCap: File.File; destVolumeID: Volume.ID ← Volume.nullID; destVolumeOpen: BOOLEAN ← FALSE; srcFirstPage: File.PageNumber; destFirstPage: File.PageNumber; freePages: Volume.PageCount; pagesIn: Environment.PageCount; pagesOut: Environment.PageCount; pageCount: INTEGER ← 0; << space: Space.Interval ← Space.nullInterval; spaceBase: File.PageNumber ← 0; spaceInterval: Space.Interval ← Space.nullInterval; spacePtr: LONG POINTER; srcSpaceWindow: Space.Window; desSpaceWindow: Space.Window; --swapUnitSize: Space.SwapUnitSize = 10; >> srcCap: File.File; srcVolumeID: Volume.ID ← Volume.nullID; srcVolumeOpen: BOOLEAN ← FALSE; srcUCodeSize: File.PageCount ← 0; uCodeSize: File.PageCount ← 0; volSize: Volume.PageCount ← 0; Cleanup: PROC = BEGIN IF debug THEN { Put.Line[toolData.fileSW, "Enter Cleanup....."L]; Process.Pause[Process.SecondsToTicks[5]]; }; IF buffer # NIL THEN buffer ← Space.Unmap[buffer]; --CloseVolume[]; END; --Cleanup --spacePtr ← space.pointer; Put.Line[toolData.fileSW, "Will copy virtual memory from source volume into destination volume and then prompt to boot destination volume"L]; Put.Line[toolData.fileSW, "Click left-button to continue, right-button to skip"L]; IF ~ILT.Confirm[] THEN RETURN[FALSE]; IF debug THEN { Put.Line[toolData.fileSW, "GetSourceVolumeID..."L]; Process.Pause[Process.SecondsToTicks[5]]; }; [srcVolumeID, srcVolumeOpen] ← ILT.GetVolumeID[toolData.srcVolName]; IF srcVolumeID = Volume.nullID THEN RETURN[FALSE]; IF debug THEN { Put.Line[toolData.fileSW, "GetDestVolumeID..."L]; Process.Pause[Process.SecondsToTicks[5]]; }; [destVolumeID, destVolumeOpen] ← ILT.GetVolumeID[toolData.destVolName]; IF destVolumeID = Volume.nullID THEN RETURN[FALSE]; IF String.Equivalent[toolData.srcVolName, toolData.destVolName] THEN BEGIN Put.Line[toolData.msgSW, "Error: Source volume equals destination volume"]; RETURN[FALSE]; END; IF debug THEN { Put.Line[toolData.fileSW, "GetVolumeBootFile..."L]; Process.Pause[Process.SecondsToTicks[5]]; }; [srcCap, srcFirstPage] ← GetVolumeBootFile[srcVolumeID, hardMicrocode]; [destCap, destFirstPage] ← GetVolumeBootFile[destVolumeID, hardMicrocode]; IF destCap = File.nullFile THEN BEGIN IF debug THEN { Put.Line[toolData.fileSW, " = nullFile...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; destCap ← File.Create[destVolumeID, 1, FileTypes.tUntypedFile]; END ELSE BEGIN IF debug THEN { Put.Line[ILT.toolData.fileSW, " MakeUnbootable.."L]; Process.Pause[Process.SecondsToTicks[5]]; }; MakeUnbootable[ destCap, hardMicrocode, destFirstPage ! TemporaryBooting.InvalidParameters => BEGIN Put.Text[ILT.toolData.msgSW, "Warning: trouble making unbootable"L]; CONTINUE; END]; END; Put.Text[toolData.fileSW, " srcFirstPage = "]; Put.LongDecimal[toolData.fileSW, srcFirstPage]; Put.Text[toolData.fileSW, " destFirstPage = "]; Put.LongDecimal[toolData.fileSW, destFirstPage]; IF srcCap = File.nullFile THEN srcUCodeSize ← 0 ELSE srcUCodeSize ← File.GetSize[srcCap]; Put.Text[toolData.fileSW, " Source VMem size = "]; Put.LongDecimal[toolData.fileSW, srcUCodeSize]; Put.Text[toolData.fileSW, " pages; "]; <<File.SetSize[destCap, uCodeSize ! File.Unknown => { Put.Line[toolData.fileSW, " File.Unknown!"L]; Cleanup[]; GOTO noGood}]; IF debug THEN { Put.Line[toolData.fileSW, "SetSize...."L]; Process.Pause[Process.SecondsToTicks[10]]; }; File.SetSize[destCap, uCodeSize ! Volume.Unknown => { Put.Line[toolData.fileSW, " Volume.Unknown!"L]; Cleanup[]; GOTO noGood}];>> IF debug THEN { Put.Line[toolData.fileSW, "SetSize...."L]; Process.Pause[Process.SecondsToTicks[10]]; }; << File.SetSize[destCap, uCodeSize ! Volume.InsufficientSpace => { Put.Line[toolData.fileSW, " Not enough room on dest. volume!"L]; Cleanup[]; GOTO noGood}]; >> uCodeSize ← srcUCodeSize; File.SetSize[destCap, uCodeSize ! Volume.InsufficientSpace => { Put.Text[toolData.fileSW, " Not enough room on dest. volume for "L]; Put.LongDecimal[toolData.fileSW, uCodeSize]; Put.Line[toolData.fileSW, " pages; "]; uCodeSize ← uCodeSize - 100; RETRY;}]; IF debug THEN { Put.Line[toolData.fileSW, "Create...."L]; Process.Pause[Process.SecondsToTicks[10]]; }; << srcSpaceWindow ← [srcCap, spaceBase, bufferPages]; desSpaceWindow ← [destCap, spaceBase, bufferPages]; spaceInterval ← Space.Map[window: srcSpaceWindow, access: access, swapUnits: [uniform[swapUnitSize]]! Space.InsufficientSpace => { Put.Line[ILT.toolData.msgSW, "+++ Insufficient free pages"L]; Process.Pause[Process.SecondsToTicks[10]]; Cleanup[]; GOTO noGood}; ]; >> IF debug THEN { Put.Line[toolData.fileSW, "Map...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; buffer ← Space.Map[ window: [file: File.nullFile, base: NULL, count: bufferPages], class: data, swapUnits: [uniform[4]]].pointer; FOR windowPage: Space.PageOffset ← OthelloDefs.leaderPages, windowPage + bufferPages WHILE windowPage < Inline.LowHalf[uCodeSize] DO pagesIn ← Space.CopyIn[buffer, [srcCap, windowPage, bufferPages]]; pagesOut ← Space.CopyOut[buffer, [destCap, windowPage, bufferPages]]; pageCount ← pageCount + bufferPages; --pageCount ← pageCount + swapUnitSize; Put.Text[toolData.msgSW, "Pages transferred: "]; Put.Decimal[toolData.msgSW, pageCount]; Put.CR[toolData.msgSW]; InvertIndicator[]; ENDLOOP; << File.SetSize[destCap, srcUCodeSize ! Volume.InsufficientSpace => { Put.Line[toolData.fileSW, "srcUCodeSize!"L]; Put.Line[toolData.fileSW, "Not enough room on dest. volume for "L]; Put.LongDecimal[toolData.fileSW, srcUCodeSize]; Put.Line[toolData.fileSW, " pages. "L]; Cleanup[]; GOTO noGood}]; >> IF debug THEN { Put.Line[toolData.fileSW, "Cleanup...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; Cleanup[]; IF debug THEN { Put.Text[toolData.fileSW, "SetVolumeBootFile..."L]; Process.Pause[Process.SecondsToTicks[5]]; }; SetVolumeBootFile[destCap, hardMicrocode, OthelloDefs.leaderPages]; IF debug THEN { Put.Text[toolData.fileSW, "MakePermanent..."L]; Process.Pause[Process.SecondsToTicks[5]]; }; File.MakePermanent[destCap]; IF debug THEN { Put.Text[toolData.fileSW, "MakeBootable..."L]; Process.Pause[Process.SecondsToTicks[5]]; }; MakeBootable[ destCap, hardMicrocode, OthelloDefs.leaderPages ! TemporaryBooting.InvalidParameters => BEGIN Put.Text[toolData.msgSW, "Warning: trouble making bootable"L]; CONTINUE; END]; Put.Line[toolData.fileSW, " installed."L]; IF debug THEN { Put.Text[toolData.fileSW, "SetPhysicalVolumeBootFile..."L]; Process.Pause[Process.SecondsToTicks[5]]; }; SetPhysicalVolumeBootFile[destCap, hardMicrocode, OthelloDefs.leaderPages]; destVolumeOpen ← CloseVolume[destVolumeID]; srcVolumeOpen ← CloseVolume[srcVolumeID]; RETURN[TRUE]; END; --Retrieve END.