Bob Sproull and David Boggs -- May 2, 1980 1:32 PM
Copyright Xerox Corporation 1979, 1980
The OS comes in two parts, the "top" part, and the "main" part. The reason for the two parts is to minimize the number of statics loaded with the top part, so that people who want to Junta away almost all of the code (except, perhaps, the Swat interface), do not get statics for the bulk of the Os.
There is a somewhat complicated linkage between top and main and between the OS and user programs (read the Bcpl manual, section 9-8, for a ’description’). The basic idea for linkage to user programs is: Sys.Bk is "loaded" with user programs, and causes each static that refers to an Os function to (1) contain as value the "index" in the file Sys.Bk, and (2) the address of the static is added to a special relocation list at the end of the first portion of the .Run file. Statics for the "main" part have small indices; statics for the "top" part have indices with the high order bit on (see Sys.Bk.) NOTE: YOU MAY NOT CHANGE INDICES LISTED IN SYS.BK, BECAUSE MANY .RUN FILES HAVE BEEN LOADED WITH THE OLD INDICES; THESE WOULD STOP WORKING IF YOU CHANGE VALUES! The CallSubsys function reads the list of statics that refer to the Os and fixes them up by looking at the index: two tables of statics (main and top) are kept in the Os in EXACTLY the same order as the order of indices. This ordering is assured by loading the Os parts in conjunction with the files OsMain.Bj and OsTop.Bj.
CHANGING LINKAGE (e.g., adding new public Os functions)
To add a new function in the X part of the Os (x=Top or x=Main), you must carefully follow the incantation:
1. Edit the file OsX.Bj (i.e., OsTop.Bj or OsMain.Bj). Identify a unique new "index" that does not appear already in a line of the file. There should be a comment at the top of the file about indices currently unused. Add a new line, with the name of the function you are creating, followed by the index, followed by either P (for "procedure" -- Swat will expect to find the static pointing to a piece of code) or V (for "variable" -- Swat will print the contents of the static when asked to print the symbol). Be sure to update the comment at the head of the file to reflect the index you have chosen.
1a. You will notice a 6-digit number on a line by itself near the beginning of OsX.Bj. This is the (actual) address where the statics listed in the file will begin to be "nailed down." Decrease this number by 1 (because you are adding one new static, and it is the last of the statics that should not move).
2. Edit the file Sys.Bk, and make a corresponding change. You will observe that the first part of the file corresponds to OsMain.Bj and the last part to OsTop.Bj. Be sure to make the edit carefully -- if the Bj and Bk files get out of sync, you will be very confused.
3. Edit the command file "LoadOsX.Cm" (i.e., LoadOsTop.cm or LoadOsMain.cm). You will find a piece of the form xxxxxx/V, giving the starting address of the static area (not equal to the number given in step 1a, because only statics that "exit" top or main need be given this .Bj, .Bk file treatment). Decrease this number by 1.
3a. You will also find an entry yyyy/W, which gives the total permissible length of the static area. Increase this number by 1.
4. Reload, by invoking "@LoadOsX.Cm". If errors are generated, see the section on loading errors.
5. Be sure to put the updated Sys.Bk on <Alto>.
Note: Some functions or statics (e.g. sysFontHeight) are only linked between top and main, and are not exported to user programs via Sys.Bk. These are given at the end of OsTop.Bj, and always have indices higher than any exported symbol. You may change around any of these indices you like (e.g., if you want to add a new exported symbol to OsTop.Bj, you may want to increase by 1 all of the indices for non-exported symbols). This is perfectly fine, as long as you re-load BOTH top and main parts.
Note: The static pTopStatics must always be loaded in the maximum address: 176777b. This is the way Mesa and SmallTalk discover where the top statics are. Their order is of course published in Sys.bk, so these other environments can manipulate things like UserName, EventVector, etc.
Note: Mesa and SmallTalk assume that Junta(levBasic) leaves 174777b and below available - it currently makes it with 5 words to spare. Beware!
The Os is loaded as two .Run files: the "top" part and the "main" part. Both of these .Run files are rather special, and it does not make sense to think of executing either of them by themselves. The top part is loaded with the command file "LoadOsTop.Cm", which produces OsTop.Run and OsTop.Xc (the page 0 values that would otherwise overwrite the current Bcpl linkage statics--it is normal to get 1 warning during loading, the "not enough common space" message). The main part is loaded with the command file "LoadOsMain.Cm", which produces OsMain.Run, Sys.Syms. You need only reload a part (top or bottom) if something has changed within the part. (If errors crop up during loading, see below).
The two parts are combined into a type B boot file with the command file "MakeBoot.Cm," which produces NewOS.Boot. Be sure to check NewOS.map: the upper address of the statics in OsMain.Run must be below the lower address of code in OsTop.Run!
The system can be initialized by invoking "Bootfrom Os.Boot" (MakeBoot.cm does this automatically). This new, never executed OS built by BuildBoot is a type-B boot file which uses the boot loader contained in DiskBoot.asm. This loader displays three rows of flashing boot lights as the disk runs. The OS is started at JuntaReturn, with the OsFinishCode set to fcOnceOnly -- it is doing once-only processing.
Then you should fall into Swat with the message "OS debug." This permanent break-point is hit only during once-only initialization, and is inserted so that you may set break points within the installation code, etc. (Note: If you fail to fall into Swat, and a single row of stationary boot lights appears on the screen, it is probably because the system has not properly read Swat. In the file BootInit.Bcpl are two statements:
MoveBlock(lv SwatBreakEntry>>SCM.Swat, table [xxxx], 5).
MoveBlock(lv SwatBreakEntry>>SCM.Swatee, table [xxxx], 5).
The xxxx values are the FPRDs (FPs with REAL disk addresses) of Swat and Swatee on the OS Sources disk. If you are doing OS work on some other disk, you may have to change these and recompile BootInit. The way to locate the proper numbers is to enter Swat on your disk, look at #567, which contains the address of SwatBreakEntry. You can figure out the rest by looking in core at the values for the SCM.Swat and SCM.Swatee fields.
After proceeding from the permanent breakpoint, the system will OutLd itself on Sys.boot. Note, however, that the OS does not think it is installed. This is a feature of "once only" processing, so that Sys.Boot files that are distributed will never be transferred to a disk and appear to be installed properly. Sys.boot is a type S0 boot file with a format and loader which is different from the type-B file above; the type B format is only used to start the OS the first time.
Unfortunately, you may not run any program that does a Junta; notably FTP, until the OS is ’really’ installed. Therefore, it is necessary to save a copy of the ’uninstalled’ OS for distribution (MakeBoot.cm saves it on NewOS.boot, which by convention is the name under which new OSs are distributed) and then install the system again (by saying "install", not bootfrom -- MakeBoot.cm does this for you also), responding however you like to the installation questions. Now you may run FTP.
The following files should be distributed to <Alto>:
NewOS.Boot (NOT Sys.boot from your disk!)

The file <AltoSource>OsSources.Dm is advertised to contain those Bcpl programs within the OS that can also be used as packages. The file <Alto>OsBrs.Dm is advertised to contain the .br files for the OS, for the convenience of people who Junta away part of the OS, but want some of it back. Beginning with OS 16 the BFS is maintained separately from the OS.
The file <AltoSource>OsSources.Dm (see last section) contains all the sources necessary to re-make the operating system.
OsTop: There is always one warning issued ("NOT ENOUGH COMMON SPACE"), which refers to the fact that LevBcpl.asm defines statics that overlap the existing BCPL linkage statics; this is normal. Instead of emitting these statics to OsTop.run, BLDR writes them on OsTop.xc; the BuildBoot command line causes it to get included in the right place.
If you get the message "Warning -- xxx.Br overlaps static area," this means that the length of code has increased too far; it will be necessary to start loading the code somewhat lower in core. Examine OsTop.Bs to determine how much lower the code should start; then revise downward the xxxxxx/O entry in LoadOsTop.Cm, and re-load. (This will probably cause a conflict with OsMain; see below.)
If you get the message "Warning -- not enough static space", one of two things has happened:
You entered a new function into OsTop.Bj and did not observe the rules above explicitly. If you suspect this, study very carefully OsTop.Bs -- remember that static addresses should correspond to the indices in OsTop.Bj + the number at the beginning of the file.
You defined a new (internal) static for which there was not room. If you suspect this, revise the yyyyy/V in LoadOsTop.Cm downward by n (where n is the number of new statics; you can deduce this from reading OsTop.Bs), revise the xxx/W in the file upward by n, and re-load.
OsMain: If you get the message "Warning -- xxx.Br overlaps static area," the code in the main part of the Os has grown too big; it will be necessary to start loading the code lower in core. Examine OsMain.Bs to determine how much lower, and revise downward the second xxxxxx/P entry in LoadOsMain.Cm (the one immediately preceding LevMain), and re-load. WARNING: Do not revise the xxxxxx/O entry -- it will have no effect.
If you get the message "Warning -- not enough static space", see the procedure above for OsTop; but use the corresponding OsMain files.
OsMain/OsTop conflict during BuildBoot: If you had to move the code region in OsTop down, you may have moved it down so far that it overlaps OsMain’s static area. In this case, note the difference (BuildBoot shows you the numbers and also writes them on NewOS.map), i.e., the amount by which it is necessary to lower all the OsMain stuff in core. Then:
-- revise downward the xxxxxx/V in LoadOsMain.Cm for the statics
-- revise downward the xxxxxx/P in LoadOsMain.Cm for the code
-- revise downward the six-digit octal number near the beginning
of OsMain.Bj
By "revise downward," I mean "subtract the same octal number" -- the number to subtract is the amount by which all this stuff must be moved down in core. Now re-invoke LoadOsMain.Cm.
Most common error. The most common difficult snafu is that the xxxxxx/V in a command file and the six-digit octal number in the corresponding .Bj file are not kept in sync. This will cause Bldr to complain that not enough static space is available, although you will count the statics listed in the .Bs file and find that you have allocated plenty of space. But if you look at the addresses actually assigned to the statics, the light will slowly dawn!
This paragraph attempts to define the memory layout and explain why it is that way. Some of the funny /P and /O entries in command files may thereafter make sense.
The layout of memory when OutLd’ed on the disk (that is, when the OS is read back into core correctly, memory will look like this, various boot file formats permute some of the core pages):
page 0 -- has pointers to Bcpl runtime routines
page 1 -- I/O stuff + mask tables already initialized
1000b -- User Name and Disk name (see AskUser in Install.Bcpl) This position is "published" to the Executive, which reads the boot file to find the disk name.
1200b -- The encrypted password -- see AskUser, TellUser in Install.Bcpl. The installation procedure goes to great pains to prevent the clearText password from being saved in the core image.
1375b -- Local time zone parameters are saved here
1377b -- Length of Ftp.Run file saved in core
1400b to ~100000b -- FtpOs.Run file saved during once-only installation so it can initialize a virgin disk.
StartOS -- a piece of machine language code just for starting up the first (once-only) time -- thereafter not needed
JuntaReturn -- this is the lowest piece of the "OS"
JuntaReturn to initStackLimit -- This is the "initialization" code of the OS, including BootInit, NewDisk, EraseDisk, InstallUtils, MDI, Install, etc. It is run during Boot, InLd and CounterJunta, but is not needed when the main (real) OS runs. When this initialization is done, the stack is just below LevMain, and the routine FinishInitOs (in OsMain.Bcpl) is called, just as if a program were "finish"ing.
initStackLimit to stackRoot is free -- for system stack.
stackRoot to 176777b is the real OS -- the part that is around
when user programs (including the Exec) run.
175000b to top of memory -- LevBasic. A Junta to levBasic is guaranteed to clear out up to and including 174777b. Mesa and Smalltalk depend on this.
176777b -- contains a pointer to the top statics region. Mesa and SmallTalk use this and the static indices published in Sys.Bk to access objects in levBasic.