// PupBootInit.bcpl -- boot server initialization

// Last modified February 15, 1979  1:52 AM by Boggs

get "Pup0.decl"
get "Pup1.decl"
get "Streams.d"
get "PupBootServ.decl"

external
[
// outgoing procedures
CreateBootServ; DestroyBootServ
AddNameToBFQ; SetBootBcstInterval

// incoming procedures
BootServCtx; LockBootServ
Allocate; Free; InitializeContext
MoveBlock; Zero; Enqueue; Dequeue; Unqueue
SetFilePos; Endofs; Closes; ReadBlock; WriteBlock
OpenFile; DeleteFile; RenameFile

// incoming statics
@bs; @ms
]

manifest bsss = alto? 200, 100  // boot server stack size

//----------------------------------------------------------------------------
let CreateBootServ() be
//----------------------------------------------------------------------------
[
bs = Allocate(ms>>MS.zone, lenBS); Zero(bs, lenBS)
bs>>BS.ctx = InitializeContext(Allocate(ms>>MS.zone, bsss), bsss, BootServCtx)
Enqueue(ms>>MS.ctxQ, bs>>BS.ctx)
bs>>BS.stats.version = bootStatsVersion
bs>>BS.bcstTimer = 12  // wait 1 minute before first dir bcst
SetBootBcstInterval(1)  // default is 1 hour
]

//----------------------------------------------------------------------------
and DestroyBootServ() be
//----------------------------------------------------------------------------
[
LockBootServ()
Unqueue(ms>>MS.ctxQ, bs>>BS.ctx)
Free(ms>>MS.zone, bs>>BS.ctx)
let bfe = bs>>BS.bfeQ.head; while bfe ne 0 do
   Free(ms>>MS.zone, Dequeue(lv bs>>BS.bfeQ))
Free(ms>>MS.zone, bs)
]

//----------------------------------------------------------------------------
and SetBootBcstInterval(hours) be bs>>BS.bcstInterval = hours * 720
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
and AddNameToBFQ(bfn, name) be
//----------------------------------------------------------------------------
[
let bfe = Allocate(ms>>MS.zone, lenBFE + name>>String.length rshift 1 +1)
Zero(bfe, lenBFE+1)
bfe>>BFE.bfn = bfn
MoveBlock(lv bfe>>BFE.name, name, name>>String.length rshift 1 +1)

// AddNameToBFQ (cont'd)

let bootFile = OpenFile(name, ksTypeReadOnly, charItem, 0, lv bfe>>BFE.fp)
if bootFile ne 0 then
   [
   bfe>>BFE.exists = true
   //There are two kinds of boot file.
   //For more on boot files see the BuildBoot documentation

   //B-Files produced by BuildBoot.run:
   //	File page 1:	DiskBoot loader
   //	File page 2:	locations 0-377b
   //	File page 3:	locations 1000b - 1377b
   //	File page 4:	locations 1400b - 1777b
   //	...
   //	File page n:	locations (n-1)*400b - (n-1)*400b+377b
   //B-Files have 0 in the second data word
   //B-Files are started by jmp @0 when loading is complete

   //S-Files produced by Swat OutLd:
   //	File page 1:	InOutLd loader
   //	File page 2:	locations 1000b - 1377b
   //	File page 3:	locations 1400 - 1777b
   //	...
   //	File page 253:	locations 176400b-176777b
   //	File page 254:	locations 400b - 777b
   //	File page 255:	locations 0 - 377b
   //S-Files have a non-zero value in the second data word
   //Some S-Files can be started by jmp @0.
   //This is the kind we use, but we re-format them first

   let buffer = Allocate(ms>>MS.zone, 256)
   ReadBlock(bootFile, buffer, 256)
   MoveBlock(lv bfe>>BFE.date, buffer+3, 2)
   test buffer!1 eq 0
      ifso  // B-file
         Closes(bootFile)
      ifnot  //InLd format file - make it B-format
         [
         buffer!1 = 0 // mark it as a B-format file
         let newFile = OpenFile("TEMP.BOOT", ksTypeWriteOnly, charItem)
         WriteBlock(newFile, buffer, 256)  //useless swat InLdr

         //read page containing loc 0-#377
         SetFilePos(bootFile, 1, 254 lshift 9)  //last page of file (255)
         WriteBlock(newFile, buffer, ReadBlock(bootFile, buffer, 256))

         //now copy the rest of the file; stop on page count not end of file
         //note that file page 254 (core page 1) is discarded
         SetFilePos(bootFile, 0, 512)  //set up to read page 2
         //S-Format files are guaranteed to be at least 255 pages long
         for i = 2 to 253 do
            WriteBlock(newFile, buffer, ReadBlock(bootFile, buffer, 256))

         Closes(bootFile); DeleteFile(name)
         Closes(newFile); RenameFile("TEMP.BOOT", name)
         compileif alto then
            [
            Zero(lv bfe>>BFE.fp, 5)
            Closes(OpenFile(name, ksTypeReadOnly, 0, 0, lv bfe>>BFE.fp))
            ]
         ]
   Free(ms>>MS.zone, buffer)
   ]
Enqueue(lv bs>>BS.bfeQ, bfe)
]