// CopyDisk.bcpl
// Copyright Xerox Corporation 1979, 1980
// Last modified November 27, 1980  1:27 PM by Boggs

get "CopyDisk.decl"
get "BcplFiles.d"
get "AltoDefs.d"
get "SysDefs.d"

external
[
// outgoing procedures
SysErr

// incoming procedures
BeforeJuntaInit; Junta; AfterJuntaInit
CallContextList; AddToZone
MoveBlock; Zero; StartIO; DisableInterrupts
BfsTryDisk; EtherBoot; OsFinish

// outgoing static
versionText

// incoming statics
ctxQ; sysZone; bootFlag; ramFlag
lvUserFinishProc; lvAbortFlag
]

static [ savedUserFinishProc; endCode; versionText ]

//----------------------------------------------------------------------------
let CopyDisk(blv, upe, nil) be
//----------------------------------------------------------------------------
[
versionText = "CopyDisk of 29 Sept 82"
endCode = blv>>BLV.endCode
BeforeJuntaInit(blv, upe, nil)
Junta((ramFlag? levBuffer, levBcpl), AfterJunta)
]

//----------------------------------------------------------------------------
and AfterJunta() be
//----------------------------------------------------------------------------
[
savedUserFinishProc = @lvUserFinishProc
@lvUserFinishProc = CopyDiskFinishProc
AfterJuntaInit()
AddToZone(sysZone, BeforeJuntaInit, endCode-BeforeJuntaInit)
@lvAbortFlag = @lvAbortFlag +1
   [
   CallContextList(ctxQ!0)
   //Shift-Swat is handled manually because aborting OutLds the
   // environment onto Swatee which may not be there since the disk
   // may not be ready!
   if kbdAd!2 eq 177677B & kbdAd!3 eq 177773B then OsFinish(fcAbort)
   ] repeat
]

//----------------------------------------------------------------------------
and CopyDiskFinishProc() be
//----------------------------------------------------------------------------
[
@displayListHead = 0; for i = 0 to 32000 loop  //turn off display
if ramFlag then
   [
   (table [ 61010B; 1401B ])(177776B, 22B)  //JMPRAM 22: SetBLV(177776B)
   StartIO(100000B)  //Silent boot back into ROM0.
   ]
@lvUserFinishProc = savedUserFinishProc
unless BfsTryDisk(0, 0, 0, 0) do EtherBoot(10b)  //NetExec
unless bootFlag return

// manual disk boot:
structure KCB:
   [
   link word
   status word
   command word
   headerAddress word
   labelAddress word
   dataAddress word
   normalWakeups word
   errorWakeups word
   header word
   diskAddress word
   ]
manifest lenKCB = size KCB/16

DisableInterrupts()
StartIO(3)  //reset ethernet

let kcb, data, label = vec lenKCB, vec 256, vec 8
   [
   Zero(kcb, lenKCB)
   kcb>>KCB.command = 44100b  // check header, read label, read data
   kcb>>KCB.headerAddress = lv kcb>>KCB.header
   kcb>>KCB.labelAddress = label
   kcb>>KCB.dataAddress = data
   kcb>>KCB.diskAddress = kbdAd!0 xor -1
   until @diskCommand eq 0 loop
   @diskCommand = kcb  //spin the disk
   while (kcb>>KCB.status & 7400b) eq 0 loop  //wait for it to stop
   if (kcb>>KCB.status & 7667b) eq 7400b break  //good
   ] repeat

MoveBlock(402b, label, 8)  //402-411 ← label
MoveBlock(1, data, 256)  //1-400 ← data
@2 = kcb>>KCB.status  //2 ← status
goto 1  //jump into bootloader
]

//----------------------------------------------------------------------------
and SysErr(p1, errNo, p2, p3, p4, p5) be
//----------------------------------------------------------------------------
[
let t = p1; p1 = errNo; errNo = t
(table [ 77403b; 1401b ])("Sys.Errors", lv p1)
]