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