Running MINI-UNIX on the LSI-11


Intro

The ground-breaking
V6 Unix normally required PDP-11's with memory management, such as the PDP-11/45 which early Unixes ran on. Two cut-down versions of V6, MINI-UNIX and LSX, were later made available for PDP-11's without memory management.

The former ran on machines such as the PDP-11/05 and similar machines, and the latter was intended for the PDP-11/03, which used the LSI-11 procesor. MINI-UNIX was the more capable of the two; its kernel was less cut-down than LSX's, and it could support multiple simultaneous users. (LSX was intended for systems with the absolute minimum amount of main memory; a real concern with early LSI-11's, which often came with limited amounts of expensive core memory.)

In the classic computer world, LSI-11's are still relatively easy to find, and not expensive, and people who have them would like to run an early Unix. Although MINI-UNIX is the more capable, it does not run on LSI-11's 'out of the box'. However, there are no major fundamental differences between the LSI-11 and the models MINI-UNIX was intended for. MINI-UNIX was actually historically moved to the LSI-11; however, that version is apparently now lost. It has recently been moved to the LSI-11 again; this page provides the code needed to run it on the LSI-11 (either real hardware, or a simulator), and explains how to do it.

A pre-built -11/03 MINI-UNIX is not made available (although it would be possible to do so); instead, you'll have to build it yourself. The advantage of this approach is that it will teach you a lot about MINI-UNIX in the process. It's not hard, so it's not a major imposition.



Hardware Needed

Running MINI-UNIX on an actual hardware LSI-11 requires only an LSI-11 with the maximum amount of memory for the machine. This is normally 56KB, but most DEC memory boards can be configured to allow one to have 60KB. A minor adjustment will be needed on MINI-UNIX to allow use of the full 60KB, though.

Note that LSI-11's only work with Q18 memory, so most 256KB boards (both DEC and off-brand), which are Q22, won't work with an LSI-11.

It is also recommended that LSI-11's have the KEV11 EIS chip (either an -A or the rumoured -B); this will allow the build to omit the EIS emulator code, and save memory. (This obviously applies to simulated systems as well as real ones.)

(It is possible to increase the amount of space for the kernel, but this requires re-linking every single user command, including the shell and 'init'. Not recommended.)



Building a MINI-UNIX Kernel Image

Before you try to build an -11/03 MINI-UNIX kernel, you should start by building an 'ordinary' MINI-UNIX kernel, to familiarize yourself with the process. There are two broad approaches to building new MINI-UNIX kernel load images: You can start by down-loading a set of working MINI-UNIX disk images from the
TUHS archive. Once you've done that, MINI-UNIX includes directions on how to build a new image, here, starting on page 6.

Note: DON'T just follow this document blindly; it may be out of date. Instead, read it to get an idea of how the whole process works, and then look to see what you've actually got on disk, and then go from there.

This site also contains much useful information, including this collection of documents.



MINI-UNIX Booting

Here's a brief explanation of what happens when MINI-UNIX boots, in case you run into a problem which you have to debug. (It's completely identical to larger Unixes.)

Unix kernels consists of a number of smallish relocatable binary modules which statically linked into a large object code image; during booting, that image is loaded into memory and started. After the usual initialization, the '0th' process (which in V6 has the task of swapping processes in and out) is hand-crafted; if then 'forks' into two, using the standard Unix fork() system call (which creates a 'clone' of the existing process).

The second process then runs a tiny program (the binary for which is built into the kernel) which does an 'exec()' system call, to read in and run "/etc/init". That process/command then does another fork(), and the child process from that exec()'s the shell (command interpreter, in "/bin/sh").



MINI-UNIX File Layout

Here's an explanation of where things are in the MINI-UNIX file-system, to help you find your way around. All of the MINI-UNIX sources (both kernel, and important user mode commands) are in "/usr/sys". "/usr/sys/source" contains all the user-mode commands which are different in MINI-UNIX from V6 UNIX.

"/usr/sys" is where new kernel loads are built; two shell command files are relevent. "shld" contains the command to actually build a kernel image. "run" is a longish commad file which builds a number of different kernel images for different disk devices.

"/usr/sys/mxsys" is where the main sources for the kernel are found. They are all in C, except for two files in assembly language: "mch.s", which contains things like a number of low-level operations inaccessible from C, low-level initialization code, etc; and "low.s", which contains interrupt vectors. "/usr/sys/dev" contains the sources for the low-level device drivers - the parts which talk to the actual device hardware. Two higher-level modules of device code, "bio.c" (which deals with the block-structure mass storage devices which hold the file system(s)) and "tty.c" (which deals with the serial lines through which users interact with the system) are in "mxsys".

Building MINI-UNIX under MINI-UNIX

Unless you happen to have a working PDP-11/05 with RK drives, the best way to work with them is to bring a MINI-UNIX system up under a simulator.

The MINI-UNIX linker, which normally creates binaries starting at 060000, can do kernels (which start at 0); there's a special flag, '-a', to say 'link at 0'.

Building MINI-UNIX under V6

V6 is an incredibly good system to use as a host because MINI-UNIX uses the V6 file system, so one can mount MINI-UNIX disk packs and work on them with standard V6 tools. MINI-UNIX also uses more-or-less the standard V6 tool-chain (assembler, C compiler, and linker), so both the MINI-UNIX system, and user commands, can be built using the V6 tools.

Instructions on how to bring up V6, including how build a new version of its kernel (very similar to the procedure for MINI-UNIX, so a good learning experience) are available here and here.

The one exception to the above observations about the dual applicability of the V6 tool-chain is that MINI-UNIX requires user commands to be linked to run at a high address (usually 060000, but see below), instead of at 0 as on standard V6. This is a result of the lack of memory management in systems that run MINI-UNIX; the kernel and user commands share a single PDP-11 address space, with the kernel in low memory, and user commands (as processes, one at a time) in high memory.

So, while operating system images can be built with the standard V6 linker ('ld'), building user command binaries requires a special version of the linker. This is a lightly edited version of the standard V6 linker; it is trivial to copy the source over (avilable once a MINI-UNIX disk pack is mounted), and compile it under V6 to produce binary of a MINI-UNIX linker which runs under V6.

That can be used to create, on V6, MINI-UNIX versions of commands, e.g. a version of the shell which uses 'cd' instead of 'chdir'. (Note that un-linked relocatable binaries for most commands, etc are the same for both V6 and MINI-UNIX; they are also the same for all the PDP-11 CPU models on which V6 and MINI-UNIX run. Only one kernel module (mch.o) differs from model to model.)

One additional issue is that MINI-UNIX uses the 'new' archive format, not the 'old' one of stock V6; this includes in the linker. There are a number of ways around this: the so-called 'Shoppa disks' include a V6 binary for the new archive command ('nar'); MINI-UNIX also includes the source for it, and like the linker, it can be copied over and compiled. Dealing with existing libraries (liba.a and libc.a) is left as an exercise for the reader (hint; the V6 libraries seem to work for MINI-UNIX).



Details about Changes Needed for the -11/03

There are three areas where the LSI-11 version needs work, over the original /05 version:
For the first two, the needed changes are identical to the ones needed to run the full V6 on the PDP-11/23, detailed here. (These had all been tested on the /23.) Rather than have anyone make the exact same changes independently, modified versions of the MiniUnix files for them (low.s, main.c and param.h) are available here. (It is also necessary to re-compile sys4.c, once the new param.h has been down-loaded.)

For the third, I have a modified version of mch.s which has the required changes for the LSI-11, along with a conditional assembly flag.

In addition, there are also really minor edits to bio.c, clock.c, slp.c, and tty.c, to remove in-line accesses to the PS. The DH driver had a similar issue; a fixed version is here.

To avoid having to edit source files to turn configuration conditional assembly flags on and off, those have been moved to separate header files, available here and here. The former goes with low.s (this version provides an RK11 disk controller, and requires the EIS, and so allows the elimination of the EIS emulation package normally included in MINI-UNIX); the latter goes with mch.s. To use them, one says:

  as 03mch.s mch.s
etc. I recommand following that with something like:
  mv a.out 03mch.o
(most V6 commands do not have the -o flag).


Building an -11/03 MINI-UNIX Kernel Image

Building a MINI-UNIX kernel for the LSI-11 is pretty simple; just do what you did to build a stock kernel, but substitute the modified files (from above): along with the LSI-11 mch.o (which you've hopefully given an informative name like 03mch.o, to keep it separate), and the new low.o (again hopefully with informative, specific name, not the generic 'low.o'). (To help out, here are links to all the source files you will need:
to build the /03 version.)

I advise against trying to use 'mkconf'; it is only used to create new conf.c and low.s files, and the existing ones should be good. (In fact, low.s has some needed changes, which mkconf can't generate. So I recommend not using it, since it will trash the low.s with the needed custom changes.)

I also advise running 'nm -ng' on the resulting image, and making sure that the end of the kernel's BSS is less than 056000 (the location of the 'user' structure, unless you've changed the system's layout). If the kernel's data overlays that, the system will die in a horrible and un-predictable way when you start it. (I am adding an automatic check for this on start-up, but I'm having some issues getting it to work properly; the V6 linker is not setting '_end' correctly.)



New 'lib1' Needed

To build the -11/03 kernel,you can't use the existing 'lib1'! The 'shr' of MINI-UNIX does this to create it:
  ld -a -x -r *.o
  mv a.out syso
  ar r ../lib1 syso emulo
so the constituents (including main.o) don't exist any more as individual files in lib1, so that your build can't use the existing version of un-modified files, but the new versions of the modified ones, with a link command like:
  ld -x lowrkne.o conf.o mxsys/03mch.o mxsys/xmain.o mxsys/xsys1.o lib1o lib2o

The linker will try to pull in the monolithic 'syso' (since it contains some missing symbols) and then you'll get a 'multiply defined symbol' error (because it contains old copies of things you have new ones of). Hence the need to create a new lib1, with the individual files in it.

I'm not sure if the files in the library have to be in any particular order (with that early Unix linker, if a module X in a library has an un-resolved external which is met by a different module Y, they have to be in the library in order X,Y since libraries are only searched once).

The order in my lib1o is:

I have no idea how I came up with that order, but it works.

Which library manager version you will have to use to build the new 'lib1' will depend on whether you are doing your build under V6 or MINI-UNIX; i.e. which version of the linker you are using.

That division as to which library bio.o, tty.o, etc is kind of arbitary, though; personal taste as much as anything. Historically, in V6, all the I/O files went in lib2.

Having cone all that, a MINI-UNIX kernel can be created with a very simple command:

  ld -x lowrkne.o mxsys/03mch.o conf.o lib1 lib2
  mv a.out /03rkmx
mostly doing demand loading from the libraries (which is how the distributed V6 was normally built).

Kernel printf()

The standard MINI-UNIX does not include the kernel printf(), probably to reduce the size of the kernel, as a larger kernel will reduce the space available for user commands.

I added it to my MINI-UNIX to make it easier to debug the system when I was bringing it up on the LSI-11. It is not required to run MINI-UNIX, though. If you want to include it, here is a copy. (If you leave out the EIS emulator there's plenty of room for it.

I have added a small assembler kernel 'prs()' so the kernel can print things; main() currently calls it for messages about the clock (on hardware -11/03's, the LTC MUST be turned off while booting; so a message pops up once it's safe to turn it on). In the latest version of mch.s; prs() has beeen fixed to save and restore the console CSR.



RL11 Support

Work has been done to allow MINI-UNIX to use the
RL11 disk controller (which supports the RL01 and RL02 disk drives - the V6 driver required some minor changes to work under MINI-UNIX). It is available here; place it in the 'dev' directory, and add the binary to 'lib2', as usual.

The 'low.s' (above) can support the RL, but you will need to conditionally assemble support for it; here is a header file for 'low.s', 'lowrkrlne.s', which does that; 'conf.c will also need to have a line added to support the RL block device: here is a copy which has the RL line added.

The RL driver calls several routines which are not normally present in MINI-UNIX (such as 'deverror()'), so this has those. (I suppose I could have diked the calls, but I like to see printout when something goes wrong.)

You'll also need to "mknod /dev/rl0 b 1 0", to provide access to the device from command level; the OS itself doesn't need that special file. Note: the driver probably produces EIS instructions when compiled, so it won't run on a machine without EIS or simulator.



Booting From an RL11

To boot off an RL, a fair amount more work is needed. First, one needs an RL
bootstrap, to go in block 0 of the RL pack (either real; or simulated, if your MINI-UNIX is running on an emulator) is needed. That is available: here.

The real problem is that MINI-UNIX looks like it supports switching around the devices used for the 'root' file system, and for swapping: but it doesn't - at least, not easily.

Confusingly, there are ROOTDEV and SWAPDEV constants, set in param.h, but neither ROOTDEV nor SWAPDEV is used anywhere in the code that I could find! Instead, there are 'rootdev' and 'swapdev' variables, which is what the code uses, but they aren't statically initialized:

  int  rootdev;                /* dev of root see conf.c */
  int  swapdev;                /* dev of swap see conf.c */
and nothing in the code initializes them (i.e. no 'rootdev = ROOTDEV'). Since they are in BSS (which is cleared on startup), they are both '0'. So one could edit param.h all one likes and nothing will happen. So whatever device is set up in conf.c as block device 0, that's what MINI-UNIX will be trying to boot/swap off of.

Note that SWPLO and NSWAP are also set in param.h as constants, so to switch from one type of drive to another, since they will generally have their swap partitions in different places, one would have to edit it param.h, and then re-compile 'the appropriate modules'.

Probably the best solution, overall, it to move them all back info conf.c as variables, the way V6 had them:

  int     rootdev {(1 << 8) | 0};
  int     swapdev {(0 << 8) | 0};
  int     swplo   4000;                   /* cannot be zero */
  int     nswap   800;
so you can have diffenent ones for different configurations (e.g. rkconf.c, rlconf.c, etc - actually I'd probably have {bd}{ad0}..{adn}conf.c, so rkrlconf.c would be a system that uses the RK as root, but also has the RL driver; rlconf.c would be booting off the RL, with no other disk drivers) without having to re-compile chunks of the system to switch to a different configuration. This will take almost no extra room (a couple of words, is all) so seems like the optimal choice. The one given above is allegedly set to use the 0th disk of major type 1 (hopefully an RL) as the root, and the back end of 0/0 (hopefully an RK) for swapping. Adjust as needed.

Back to JNC's home page


© Copyright 2020, 2022 by J. Noel Chiappa


Last updated: 14/June/2022