// 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<>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) ]