// IfsBootSend.bcpl -- Boot Server -- overflow from IfsBootServ.bcpl
// Copyright Xerox Corporation 1981, 1982, 1983

// Last modified January 22, 1983  10:48 AM by Taft

get "Pup0.decl"
get "Pup1.decl"
get "Ifs.decl"
get "IfsRs.decl"
get "IfsBootServ.decl"
get "IfsServEFTP.decl"

external
[
// outgoing procedures
SendBootFile; SendMicrocodeFile; FindBFE; BFTCompareKey

// incoming procedures
PupServSend
OpenLevel1Socket; CloseLevel1Socket; GetPBI; CompletePup; DeclarePupSoc
IFSOpenFile; SetFilePos; ReadBlock; Closes
Free; Zero; Usc; DoubleIncrement; DestroyJob; ReadRecLE

// incoming statics
@bs; sysZone
]

//----------------------------------------------------------------------------
let FindBFE(bfn) = valof
//----------------------------------------------------------------------------
// Looks up boot file number bfn and returns a pointer to the
// corresponding boot file entry (bfe) if found and zero if not found.
// Caller must keep bfe in a locked cell until finished with it.
// Caller is responsible for locking the BFT to maintain consistency.
[
let bfe = ReadRecLE(bs>>BS.tree, bfn, 0, true)
resultis bfn eq bfe>>BFE.bfn? bfe, 0
]

//----------------------------------------------------------------------------
and BFTCompareKey(bfn, bfe) = Usc(bfn, bfe>>BFE.bfn)
//----------------------------------------------------------------------------
// CompareKey routine handed to the B-tree package

//----------------------------------------------------------------------------
// and BFTEntryLength(bfe) = bfe>>BFE.length
//----------------------------------------------------------------------------
// Length routine handed to the B-tree package; hand-coded in IfsBootA.asm

//----------------------------------------------------------------------------
and SendBootFile(ctx) be	// a BootCtx
//----------------------------------------------------------------------------
[
let ftp = vec lenFTP; Zero(ftp, lenFTP)
ftp>>FTP.frnPort = lv ctx>>BootCtx.port
ftp>>FTP.realName = ctx>>BootCtx.name
let fast = (ctx>>BootCtx.booterFlags & bsFastBooter) ne 0
ftp>>FTP.timeOut1 = fast? 100, 3000  // 1 sec, 30 sec
ftp>>FTP.timeOut2 = fast? 400, 6000  // 4 sec, 60 sec
if PupServSend(ftp, ctx>>BootCtx.bytesToSkip) then
   DoubleIncrement(fast? lv bs>>BS.stats.fastSends, lv bs>>BS.stats.slowSends)
Free(sysZone, ctx>>BootCtx.name)
bs>>BS.flags = bs>>BS.flags & not ctx>>BootCtx.booterFlags
DestroyJob()
]

//----------------------------------------------------------------------------
and SendMicrocodeFile(ctx) be	// a BootCtx
//----------------------------------------------------------------------------
// Send microcode boot file by skipping the overhead page at the beginning
// and sending the rest of the file as Pups containing multiples of
// 3 words (for the benefit of D0s), terminated by an empty Pup.
// The protocol employs no acknowledgments -- if a packet is lost, the
// requestor must ask the boot server to send the whole file over again.
[
let soc = vec lenPupSoc
OpenLevel1Socket(soc, 0, lv ctx>>BootCtx.port)

// D0s require that the boot file come from a socket whose
// low-order socket number is 4!
soc>>PupSoc.lclPort.socket↑2 = socketMiscServices
DeclarePupSoc(soc)

let stream = IFSOpenFile(ctx>>BootCtx.name)
if stream ne 0 then
   [
   SetFilePos(stream, 0, 512)  // skip overhead page
   let words = nil
   let seqNo = 0

      [ // repeat
      let pbi = GetPBI(soc)
      words = ReadBlock(stream, lv pbi>>PBI.pup.words, uCodeWordsPerPup)
      pbi>>PBI.pup.id↑1 = 1  // D0s require this
      pbi>>PBI.pup.id↑2 = seqNo
      CompletePup(pbi, ptBootMicrocodeReply, pupOvBytes + words lshift 1)
      seqNo = seqNo+1
      ] repeatuntil words eq 0

   Closes(stream)
   ]

CloseLevel1Socket(soc)
DeclarePupSoc(0)
Free(sysZone, ctx>>BootCtx.name)
bs>>BS.flags = bs>>BS.flags & not ctx>>BootCtx.booterFlags
DestroyJob()
]