// BootInit.bcpl - OS initialization
// Copyright Xerox Corporation 1979
// Last modified August 11, 1980 12:34 AM by Boggs
get "AltoFileSys.d"
get "Disks.d"
get "Bfs.d"
get "Streams.d"
get "SysDefs.d"
get "AltoDefs.d"
get "SysInternals.d"
external
[
// outgoing procedures
JuntaReturn; CreateSysDisk
// incoming procedures by Junta level
// levBasic
SwatTrap; SwatInterrupt
CallSwat; ParityInterrupt
// levBFSbase
SetBlock; MoveBlock; Zero
Usc; DoubleAdd
MyFrame; GotoLabel; ReturnFrom
Dvec; SysErrT; RealDiskDA
EnableInterrupts; StartIO
// levStreams
Resets; Gets; Puts; Closes; Endofs
ReadBlock; WriteBlock
FileLength; GetCompleteFa
// levAlloc
Allocate; InitializeZone
// levDirectory
OpenFile; OpenFileFromFp
BFSWriteDiskDescriptor
// levDisplay
CreateDisplayStream; ShowDisplayStream
// levKeyboard
CreateKeyboardStream
// levMain
FinishInitOs
// Install
Install; VerifyInstalled; RestoreLev
// MDI
LookupEntries
// BfsInit
BFSInit
// incoming statics by Junta level
// levBasic
OsVersion; OsVersionCompatible
AltoVersion; SerialNumber
OsFinishCode; juntaTable
SysErr; pTopStatics; LevBasic
// levFilePointers
EnumerateFp
fpSysDir; fpDiskDescriptor
fpSysFont; fpUserCm; fpComCm; fpRemCm
fpSysBoot; fpExecutive
sysFontHeight; sysFontSize; sysDisplayLines
// levBFSbase
lvIdle; Idle
// levBFSwrite
sysDiskZone; diskKd
// levKeyboard
keys; CursorLink
// init
stackRoot; page0; initStackLimit
// outgoing statics
sysZone; lvSysZone
protectedSysZone; lProtectedSysZone
sysFont; dsp
lvCursorLink; lvSysErr
sysDisk; sysMECR
]
static
[
// Some of the above have not really been allocated anywhere (bug?)
sysZone; lvSysZone
protectedSysZone; lProtectedSysZone
sysFont; dsp
lvCursorLink; lvSysErr
sysDisk
sysMECR = defaultMECR
// private to this module
namv; fpv
]
// O S I N I T I A L I Z A T I O N
//
// You get to JuntaReturn in two cases:
//
// 1) The first way is when returning during CounterJunta --
// very little of the machine is guaranteed set up at this point.
//
// 2) The other way you can get to JuntaReturn is during once-only
// processing when the OS is being initialized from a boot file.
// The file "StartOS.asm" is loaded just before bootinit and
// comes here for "once-only" processing.
//
// Note that installation (for disk and ethernet booting) uses
// a very different mechanism, which counts on saving the entire
// machine state on a file.
//---------------------------------------------------------------------------
let JuntaReturn() be
//---------------------------------------------------------------------------
// Be very careful here, because page 0 is not guaranteed set up.
// Until *** do not use Bcpl runtime (Getframe, etc.).
[
GotoLabel(stackRoot-JuntaReturn!2, JuntaReturnAux)
JuntaReturnAux:
stackRoot!0 = stackRoot //link base frame to itself
@335B = initStackLimit //use area between levMain.asm and page0.asm
if OsFinishCode eq fcOnceOnly then
[
MoveBlock(page0, 300b, 100b) //Save a copy of Bcpl runtime xfer table
Zero(400b, 171b); Zero(600b, 200b) //Zero all but time params
// Patch first instruction of JuntaReturn so that anyone
// can jump to it without a stack and get going properly
JuntaReturn!0 = 404b //jmp.+4
]
MoveBlock(300b, page0, 100b) //install Bcpl runtime xfer table
//*** OK, you can call procedures now
SysErr = SysErrT //the "True" SysErr
// Reset all interrupts, etc. to clean state
@displayListHead = 0 //No display
@activeInterrupts = 0
@displayInterrupt = 0
for i = 0 to 16b do interruptVector!i = 0
EnableInterrupts()
@wakeupsWaiting = 0 //Flush pending interrupts
// Get the keyboard going as quickly as possible.
CreateKeyboardStream()
// Do this every time in case it is clobbered or booting sans page 1
maskTable!-1 = 0 //Special end condition.
for i = 0 to 15 do maskTable!i = -1 rshift (15-i)
// JuntaReturn (cont'd)
// Now turn Swat on (assuming for the moment that its FPs are valid.
// This will normally be the case, as there was (we can hope) a Swat and
// Swatee present when the operating system was installed.
SetBlock(trapVector, SwatTrap, 40b)
interruptVector!swatInterruptLevel = SwatInterrupt
@activeInterrupts = @activeInterrupts % swatInterruptBit
@displayInterrupt = @displayInterrupt % swatInterruptBit
// ********** OS disk's Swat & Swatee ***********
// These are the FPs (with REAL disk addresses) for Swat and Swatee
// on the OS Sources disk. They will have to be changed if the
// files move. They are here so that very early during once-only
// initialization, you can get into swat to set breakpoints to debug
// the rest of the init code.
if RestoreLev(levBasic) then
[
MoveBlock(lv SwatTrap>>SCM.Swatee, table [ 0; 161b; 1; 0; 130170b ], 5)
MoveBlock(lv SwatTrap>>SCM.Swat, table [ 0; 213b; 1; 0; 130460b ], 5)
if OsFinishCode eq fcOnceOnly then CallSwat("OS debug")
]
// Parity initialization -- done AFTER initializing Swat
// because parity errors call Swat!
@MESR = 0 //Clear any pending errors
@MECR = sysMECR
interruptVector!parityInterruptLevel = ParityInterrupt
@activeInterrupts = @activeInterrupts % parityInterruptBit
if OsFinishCode eq fcOnceOnly then
[
if (lv pTopStatics) ne 176777b then CallSwat("pTopStatics")
if Usc(LevBasic, 175000B) ls 0 then CallSwat("LevBasic too low")
pTopStatics = lv EnumerateFp
lvSysZone = lv sysZone
lvIdle = lv Idle
lvCursorLink = lv CursorLink
lvSysErr = lv SysErr
OsVersion = nOsVersion
OsVersionCompatible = nOsVersionCompatible
]
// Init the cursor
MoveBlock(cursorBitMap, (table [ 100000B; 140000B; 160000B; 170000B;
174000B; 176000B; 177000B; 170000B; 154000B; 114000B; 006000B; 006000B;
003000B; 003000B; 001400B; 001400B ]), 16)
// Now we go off to RestOfBootInit re-using this stack frame.
// The stack is set to below OSMain. This means that we should
// leave a good deal of space below LevMain code when loading.
GotoLabel(stackRoot, RestOfBootInit, stackRoot)
]
//---------------------------------------------------------------------------
and RestOfBootInit(stackRoot) be
//---------------------------------------------------------------------------
// Come here to do most (and subtle) system initialization.
// We can get here either:
// -- From call above, after CounterJunta or OnceOnly
// -- From GotoLabel below, after booting.
[
// Turn off display because we may be coming here after booting,
// in which case it is set up.
@displayListHead = 0; for i = 0 to 30000 loop
// Find the serial number and Alto version information.
SerialNumber = StartIO(0) & 377b
AltoVersion = (table [ 61014B; 1401B ])()
@613B = AltoVersion<<VERS.eng gr 1? -1, 0 //used by trident microcode
CreateSysDisk() //sets sysFontHeight, sysFontSize
// Set up a free storage zone for the OS
let fHeven = (sysFontHeight+1) & -2
let disAreaNeeded = (sysDisplayLines*(lDCB+fHeven*sysDisplayWidthInWords)+1)/2
let lDisZone = sysFontSize + disAreaNeeded + lDS + 12
let disZone = lDisZone
// 2 display streams + 7 disk streams + room to play
lProtectedSysZone = lDS*2 + (lKS+256)*7 + 5*lST + 100
let w = lProtectedSysZone
Dvec(RestOfBootInit, lv disZone, lv w)
disZone = InitializeZone(disZone, lDisZone)
sysZone = InitializeZone(w, lProtectedSysZone)
protectedSysZone = w
// Read in the SysFont and save it in fixed storage.
let f = Allocate(disZone, sysFontSize)
let s = OpenFile("SysFont.al", ksTypeReadOnly, 0, 0, fpSysFont)
ReadBlock(s, f, sysFontSize)
Closes(s)
sysFont = f+2 // sysFont points to "word 2" of the font.
let w = Allocate(disZone, disAreaNeeded)
dsp = CreateDisplayStream(sysDisplayLines, w, disAreaNeeded, 0, 0, 0, disZone)
ShowDisplayStream(dsp, DSalone)
// Now we can really print error messages!
SysErr = SysErrT
// Save place to go on a finish
juntaTable>>JT.FinishAC2 = MyFrame()
juntaTable>>JT.FinishPC = FinishInitOs
juntaTable>>JT.jAtLevel = 0 //No junta yet
// If started cold, ask whether the system should be installed.
// Now is the time to install if the user really wants to.
// Thereafter, whenever the system is booted, we return from Install.
if OsFinishCode eq fcOnceOnly then
[
let once = OsFinishCode eq fcOnceOnly
// Set code to 0 in case user aborts the Install or patches it out
// (sometimes used for debugging new systems)
OsFinishCode = 0
Install(once) //Booting the OS appears as a return from Install.
GotoLabel(stackRoot, RestOfBootInit, stackRoot)
]
FinishInitOs() //And run the OS!!!!
]
//---------------------------------------------------------------------------
and CreateSysDisk() be
//---------------------------------------------------------------------------
// Hooks up the OS to the disk currently spinning in DP0.
[
// If starting afresh (Ether boot or initial time only) then
// verify that the system is installed:
if RestoreLev(levBasic) then VerifyInstalled()
// Set up a temporary free storage zone for disking
manifest lTempZone = 450
let v = vec lTempZone
let realSysZone = sysZone
sysZone = InitializeZone(v, lTempZone)
// Get sysDisk set up so the BFS can work.
if RestoreLev(levBFSwrite) then
[
sysDiskZone = InitializeZone(sysDiskZone, sysDiskZone!-1)
sysDisk = BFSInit(sysDiskZone, true, 0, 0, false, sysZone)
if sysDisk eq 0 then CallSwat("BFSInit failed")
diskKd = sysDisk>>DSK.diskKd
MoveBlock(fpSysDir, sysDisk>>DSK.fpSysDir, lFP)
MoveBlock(fpDiskDescriptor, sysDisk>>DSK.fpDiskDescriptor, lFP)
]
if RestoreLev(levFilePointers) then
[
// Prepare to do "multiple lookup" in directory
manifest nNams = 8
let nams = vec nNams; namv = nams
nams!0 = "Swat."
nams!1 = "Swatee."
nams!2 = "User.Cm."
nams!3 = "Com.Cm."
nams!4 = "Rem.Cm."
nams!5 = "Executive.Run."
nams!6 = "SysFont.Al."
nams!7 = "Sys.Boot."
let dvs = vec nNams*(lDV); fpv = dvs
// Do a multiple-lookup on all these files. But be careful when reading
// the directory. Chances are all the files we need are near the
// beginning, but the end of the directory may be smashed.
let RetFromBadDirectory() be ReturnFrom(LookupEntries)
let s = OpenFile("SysDir", ksTypeReadOnly, 0, 0, fpSysDir)
if s eq 0 then CallSwat("No directory")
s>>ST.error = RetFromBadDirectory
LookupEntries(s, namv, fpv, nNams, true)
Closes(s)
if RestoreLev(levBasic) then
[
GetPage1(0, lv SwatTrap>>SCM.Swat)
GetPage1(1, lv SwatTrap>>SCM.Swatee)
]
SetFp(2, fpUserCm)
SetFp(3, fpComCm)
SetFp(4, fpRemCm)
SetFp(5, fpExecutive, 5)
s = SetFp(6, fpSysFont, 7)
sysFontHeight = Gets(s)
sysFontSize = FileLength(s)/2
Closes(s)
sysDisplayLines = nSysDisplayLines
SetFp(7, fpSysBoot, 1)
]
// If disk descriptor changed (e.g., by making files) write it out.
BFSWriteDiskDescriptor(sysDisk)
// restore the real sysZone
sysZone = realSysZone
]
//---------------------------------------------------------------------------
and GetPage1(n, lvfp) be
//---------------------------------------------------------------------------
// Set up lvfp with a real disk address for page 1.
[
let s = SetFp(n, lvfp, 3)
if s eq 0 then
[
// If you fail to find a legal FP, it is essential to leave behind one
// that will be thoroughly checked by the write operation in OutLd.
// If you leave a block of zeroes behind, an unsuccessful Swat call
// will wipe out the boot loader page!!!! (real disk address 0)
SetBlock(lvfp, 52525b, lFP)
return
]
let cfa = vec lCFA; GetCompleteFa(s, cfa)
RealDiskDA(sysDisk, cfa>>CFA.fa.da, lv lvfp>>FP.leaderVirtualDa)
Closes(s)
]
//---------------------------------------------------------------------------
and SetFp(n, lvfp, open; numargs na) = valof
//---------------------------------------------------------------------------
// SetFp records an FP found by directory scan, and does other things
// specified by the third argument:
// 0 => (default) create file if non ex
// 1 => do not create if non ex
// 2 => open file and return stream
// 4 => complain if non-ex
[
if na eq 2 then open = 0
MoveBlock(lvfp, fpv+n*(lDV)+(offset DV.fp/16), lFP)
if lvfp>>FP.version eq 0 then //file doesn't exist
[
if (open & 4) ne 0 then //bomb
CallSwat("Essential file missing:", namv!n)
if (open & 1) eq 0 then //create
Closes(OpenFile(namv!n, 0, 0, verLatestCreate, lvfp))
]
if (open & 2) ne 0 resultis lvfp>>FP.version eq 0? 0, OpenFile(namv!n,
ksTypeReadOnly, 0, 0, lvfp)
]