// LocalVMemInit.bcpl - does VMem setup for MainInit
// Last change January 14, 1985 5:04 PM by Bill van Melle
// Last change May 21, 1984 4:25 PM by Bill van Melle
// Last change October 6, 1982 6:44 PM by Bill van Melle
// Last change July 20, 1982 10:33 PM by Bill van Melle
// everything from here on gets flushed after /I is finished
get "LispBcpl.decl"
get "Stats.decl"
get "VMem.decl"
get "AltoDefs.d"
get "AltoFileSys.d"
get "Streams.d"
external [ // procedures defined here
LocalInitVmem; CheckIPage; RemoteDskInitVmem; RetrieveVmem
SysinFailure; ShowSysoutName; AppendString
GiveUp; ShortStack
// O.S. procedures
Closes; Endofs; ReadBlock; OpenFile; PositionPage; SetFilePos
CallSwat; WriteBlock; BFSInit; InitializeZone; Ws; MoveBlock
UNPACKDT; WRITEUDT
// misc
UCase; Password; ReadStrng; MachineType
// statics
VmemStream; MinLispForRam; RamVersion; haveUcode
SysinName; SysinHostName; dsp; UserName; UserPassword
]
manifest [ // same as in RemoteVmemInit.bcpl
firstMouseX = 260
firstMouseY = 50
lastMouseY = 800
spaceForDisk = 2*WordsPerPage
offsetDiskName = #1000 // byte locations in Sys.boot
offsetDiskPass = #1400
nWordsPassword = 9
]
structure String: [ length byte; char↑1,255 byte ]
let LocalInitVmem (SysinStream) be
[
unless SysinStream do SysinErr(0,0)
@mouseX, @mouseY = firstMouseX, firstMouseY
// We can use the rest of the space between the end of the code and the
// current end of stack for buffers. This space will eventually go to
// the assorted allocations, but for now it is empty.
let buffers = (@StackEnd+WordsPerPage-1) & not (WordsPerPage-1)
// first buf page, page-aligned
let LowStackPage = ShortStack(1000) // allow 1000 words of stack
let bufferLength = ((LowStackPage - buffers) & not (WordsPerPage-1)) - WordsPerPage
// size of buffer region
if bufferLength ls WordsPerPage
then CallSwat("No buffers for SYSIN")
let OldLowStack = @StackEnd // save old low stack
@StackEnd = LowStackPage // enforce stack end in read
PositionPage(SysinStream, 0)
ReadBlock(SysinStream, buffers, WordsPerPage) // read leader page
MoveBlock(SysinName, lv buffers>>LD.name, maxLengthFnInWords)
// now we know the real name
ShowSysoutName (lv buffers>>LD.created)
PositionPage(SysinStream, FirstVmemBlock) // prepare to read ifpage
RetrieveVmem (SysinStream, buffers, bufferLength, ReadBlock, Closes)
@StackEnd = OldLowStack // restore previous stack end
]
and RetrieveVmem (SysinStream, buffers, bufferLength, ReadFn, FinishFn) be
[
// Main routine that copies a sysout into Lisp.virtualmem. Assumes that
// VmemStream is already open, and that SysinStream is positioned ready to
// read the InterfacePage. buffers & bufferLength specify a chunk of buffer
// space that is page-aligned and a multiple of the page size long.
// Supplied procedures: ReadFn copies from SysinStream, FinishFn is called
// after "enough" has been retrieved.
// ReadFn(stream, buffers, nWords) reads nWords from stream into buffers.
// FinishFn(stream, buffers) does whatever is needed to clean up stream after.
let IFBuf = buffers
buffers = buffers + WordsPerPage
bufferLength = bufferLength - WordsPerPage
PositionPage(VmemStream, FirstVmemBlock)
ReadFn(SysinStream, IFBuf, WordsPerPage) // read InterfacePage
CheckIPage(IFBuf) // Is it ok?
@(IFBuf+IFPKey) = not IFPValidKey // invalidate vmem for now
WriteBlock(VmemStream, IFBuf, WordsPerPage)
// figure out how big the sysout is so we can move cursor appropriately
let nPages = @(IFBuf + IFPNActivePages) - FirstVmemBlock
// number of pages left to go
let bufSize = bufferLength / WordsPerPage
let nbufs = nPages / bufSize
// number of buffers full it will take to retrieve this
let mouseInc = ((lastMouseY-firstMouseY) lshift 4) / nbufs
let mouseOff = mouseInc
// thus the mouse crawls down screen as we read.
// mouseInc is 2↑4 times amount to move per buffer full
// mouseOff = mouseInc*pgno
// now read the pages off the file and into vmem
[ let wordsRead = ReadFn(SysinStream, buffers, bufferLength)
WriteBlock(VmemStream, buffers, wordsRead)
if wordsRead ls bufferLength
then if wordsRead rshift 8 ls nPages
then SysinFailure ("Sysout too short")
@mouseY = firstMouseY + (mouseOff rshift 4)
mouseOff = mouseOff + mouseInc
nPages = nPages - bufSize
] repeatuntil nPages le 0
@(IFBuf+IFPKey) = IFPValidKey // make valid again
PositionPage(VmemStream, FirstVmemBlock)
WriteBlock(VmemStream, IFBuf, WordsPerPage)
FinishFn(SysinStream, buffers)
Closes(VmemStream); VmemStream = 0
]
and CheckIPage(buffer) be
[ // checks the critical items in buffer, a copy of the Interface
// page before it gets written into the vmem
// Key check - verify file is valid and complete
if @(buffer+IFPKey) ne IFPValidKey
then SysinFailure(@(buffer+IFPKey) eq (not IFPValidKey) ?
"Can't resume: Inconsistent VMem file " ,
"File not in sysout format", SysinName)
// unless haveUcode do return
let LispV = @(buffer+IFPLVersion)
unless LispV ge MinLispForRam
do SysinFailure("Sysout too old for this microcode")
unless LispV ge MinLispForBcpl
do SysinFailure("Sysout too old for this Lisp.Run")
unless RamVersion ge @(buffer+IFPMinRVersion)
do SysinFailure("Microcode too old for this sysout")
unless BcplVersion ge @(buffer+IFPMinBVersion)
do SysinFailure("Lisp.Run too old for this sysout")
if (MachineType() eq Dolphin) & (@(buffer+IFPFullSpaceUsed) ne 0)
then SysinFailure("Sysout has larger virtual address space than this machine can read")
]
and AppendString(str, newstr) = valof
[
let i = str>>String.length
for j = 1 to newstr>>String.length
do [ i = i+1; str>>String.char↑i = newstr>>String.char↑j ]
str>>String.length = i
resultis str
]
and SysinFailure(reason) be
[ // inline concat here
let errstring = vec 50
test SysinName!0
ifso [
errstring!0 = 0
AppendString(errstring, "Retrieve of sysout ")
if SysinHostName
then [
AppendString(errstring, "{")
AppendString(errstring, SysinHostName)
AppendString(errstring, "}")
]
AppendString(errstring, SysinName)
AppendString(errstring, " failed*N// ")
]
ifnot errstring = "Could not start Lisp*N// "
GiveUp (errstring, reason)
]
and SysinErr(a, code) be SysinFailure("Can't open file")
and RemoteDskInitVmem() be
[ // do Sysin from another partition
// need to open a new disk device
let zone = vec spaceForDisk
InitializeZone(zone, spaceForDisk)
let part = SysinHostName>>String.char↑4 - $0
let otherDisk = 0
if part le 7 then otherDisk = BFSInit(zone, false, part lshift 1)
unless otherDisk & CheckPartPassword(otherDisk, zone)
do SysinFailure("Can't access partition")
let st = OpenFile(SysinName, ksTypeReadOnly, wordItem, 0, 0, SysinErr, zone, 0, otherDisk)
unless st do SysinFailure("File not found")
LocalInitVmem(st)
]
and CheckPartPassword (otherDisk, zone) = valof
[ // if otherDisk is password-protected, check password
let bootStream = OpenFile("Sys.boot", ksTypeReadOnly, charItem, 0, 0, SysinErr, zone, 0, otherDisk)
let diskName = vec #200
let passVector = vec nWordsPassword
SetFilePos(bootStream, 0, offsetDiskName)
ReadBlock(bootStream, diskName, #200)
SetFilePos(bootStream, 0, offsetDiskPass)
ReadBlock(bootStream, passVector, nWordsPassword)
Closes(bootStream)
if passVector!0 eq 0
then resultis true // not password-protected
let nameLength = UserName>>String.length // name logged in now
let diskLength = diskName>>String.length // name on partition
let trialPass = vec 20 // vector to mimic UserPassword
let newUserP = false
test UserPassword!0
ifnot [ newUserP = true; trialPass = UserPassword ] // not logged in yet
ifso [
if nameLength eq diskLength
then [
for i = 1 to nameLength
do if UCase(diskName>>String.char↑i) ne UCase(UserName>>String.char↑i)
then goto diskPrompt
// names match, see if password ok
if Password(UserPassword, passVector, false)
then resultis true
trialPass = UserPassword // names match, so smash pass
]
]
diskPrompt:
let nameLengthInWords = (diskLength rshift 1) + 1
[ // need to get password
Ws ("*n{"); Ws(SysinHostName); Ws ("} (")
Ws (diskName + nameLengthInWords) // disk name after username
Ws (") Login user: ")
Ws (diskName)
Ws (" Password: ")
if not ReadStrng (trialPass,
(trialPass eq UserPassword ? (trialPass!-1 lshift 1) - 1, 39),
false, true)
then resultis false // declined to state
if Password(trialPass, passVector, false)
then [
if newUserP
then // login succeeded, make this the username too
MoveBlock(UserName, diskName, nameLengthInWords)
resultis true
]
] repeat // prompt again
]
and ShowSysoutName (crDate) be
[ // print sysout name and its crDate to show what we're reading
Ws ("*n{"); Ws (SysinHostName ? SysinHostName, "DSK"); Ws ("}")
Ws (SysinName)
let utv = vec 7
if crDate
then [
Ws (", ")
UNPACKDT (crDate, utv)
WRITEUDT (dsp, utv)
]
Ws ("...")
]