Self-hosting Unix System V Release 4, i386

In this post we’ll be developing a process for taking binary and source resources on the internet to create a self-hosting (i.e. can recompile itself and make a new machine) environment for Unix System V Release 4, i386.

Setting Up

We’ll need some things initially on linux:

$ sudo apt-get install p7zip qemu

On linux we’ll also need a System V-compatible ‘compress’ program. I used vapier’s ncompress-v5.0, on github: https://github.com/vapier/ncompress/tree/v5.0

We’ll also need a binary release for i386 of System VR4. I used the one found on winworldpc.com: https://winworldpc.com/download/4061c39c-c39b-18c3-9a11-c3a4e284a2ef. This comes in a 7z file, which needs p7zip above to unpack.

Installation of binary Unix System V Release 4

Create disk images for primary and secondary IDE drives. I use 496Mb drives but smaller could be used, down to perhaps 200Mb? Your mileage may vary.

$ qemu-img create -f qcow2 0-0.qcow2 496M
Formatting '0-0.img', fmt=qcow2 size=10485760 cluster_size=65536 lazy_refcounts=off refcount_bits=16

If you have a lot of disk space on the host machine, then make another drive image to be used as temporary storage in the emulator:

$ qemu-img create -f qcow2 0-1.qcow2 496M
Formatting '0-1.img', fmt=qcow2 size=10485760 cluster_size=65536 lazy_refcounts=off refcount_bits=16

This qemu invocation tells the emulator to boot from “Base 01 (2.1a).img” One can use -curses or not as one prefers. For the -m switch (memory size), one can use any value > 4 and below 255; for some reason 256 causes problems with unix, usually a hang when booting.

Be aware that the memory probe by default in the binary release limits itself to 64Mb, so using more than 64Mb is probably not useful. When the installer sets up the partitions on the first disk, it’ll choose a swap space number appropriate to the current memory size, not any future target size; just something to be aware of.

For reference, the configuration for limiting Unix’s memory probe is the MEMRANGE parameter found in /stand/boot.

$ qemu-system-i386 -m 192 -fda "Base 01 (2.1a).img" -hda 0-0.qcow2 -hdb 0-1.qcow2 -boot a -curses

Follow the instructions from the installer to install all the (3 to 13) Base floppies, Standard C Development Environment (scde), and “Editing Utilities”. You can install “Maintenance 1” and “Maintenance 2”, if you wish, but for recompiling this is likely irrelevant. You can use CTRL-ALT-2 (or ALT-2 on -curses) to enter the qemu monitor, and CTRL-ALT-1 to return to the simulated environment for swapping floppies, using:

(qemu) change floppy "Base 03.img"

After rebooting one can continue installing packages if needed using:

# pkgadd -d diskette1

Adding second hard drive (optional)

Not strictly necessary, but having another 500Mb-ish of storage makes manipulating the ‘large’ source archive a bit less of an issue. I usually mount it as /home.

# diskadd 1

Changing some system paramters.

Update /etc/conf/cf.d/stune to raise NINODE, N5INODE, and UFSNINODE limits to 1300 from 400 to silence ufs_iget – inode table overflow messages while performing the compile.

# cd /etc/conf/cf.d
# ../bin/idtune NINODE 1300
# ../bin/itdune NS5INODE 1300
# ../bin/idtune UFSINODE 1300
# ../bin/idbuild
# cd / ; shutdown -g0 -y

Copying source archives

For Unix System V R 4 source code we’re going to use the archive found on archive.org: https://archive.org/details/ATTUNIXSystemVRelease4Version2. Click on ‘SHOW ALL’ under Download Options to get a more complete file list, and find ‘sysvr4.tar.bz2’. Un-bzip this file somewhere, but don’t untar.

Sadly the binary SVR4 doesn’t have any network drivers compatible with qemu (or any emulator, for that matter. However with some compress and split hackery we can work around that.

$ compress sysvr4.tar
$ split -b 1474560 sysvr4.tar.Z

This serves to split the 27Mb compressed tarball into several files that are the size of a 1.44Mb 3.5″ floppy. This allows us to one-by-one attach the xa? files to the first floppy drive, then read the contents of each within the System V simulated machine:

ALT-2 to the qemu monitor like above:
(qemu) change floppy0 xaa
ALT-1 back to System V:
# dd if=/dev/rdsk/f0t of=/dev/xaa ibs=512

..substituting for xaa each split section of the source file tarball. We can verify that the files have the proper contents by using on FreeBSD ‘sum -o 2’ with ‘algorithm 2’ (the AT&T System V algorithm) or sum -sysv (linux):

$ sum -o 2 xa?
52111 2880 xaa
39644 2880 xab
42799 2880 xac
53363 2880 xad
5327 2880 xae
40657 2880 xaf
58584 2880 xag
30271 2880 xah
41179 2880 xai
34519 2880 xaj
30224 2880 xak
65431 2880 xal
37201 2880 xam
43081 2880 xan
682 2880 xao
11745 2880 xap
1183 880 xaq
$ 

and verify the checksums in System V using ‘sum’. We can truncate the last file using ‘dd’ with ibs=1 count=x, for x equals the length of the source file on the host just to check the checksum, but neither uncompress nor tar will care.

# sum xa?
52111 2880 xaa
39644 2880 xab
42799 2880 xac
53363 2880 xad
5327 2880 xae
40657 2880 xaf
58584 2880 xag
30271 2880 xah
41179 2880 xai
34519 2880 xaj
30224 2880 xak
65431 2880 xal
37201 2880 xam
43081 2880 xan
682 2880 xao
11745 2880 xap
1183 880 xaq

In System V we’ll need to raise the ulimit so we can create sufficiently large files before uncompressing and untarring:

# /etc/conf/bin/idtune SFSZLIM 0xA00000
# /etc/conf/bin/idtune HFSZLIM 0xA00000
<edit /etc/default/login to remove the ULIMIT line>
# cd / ; /etc/conf/bin/idbuild && /etc/conf/bin/idreboot
<rebooted>
# cat xa? > sysvr4.tar.Z
# uncompress sysvr4.tar.Z

Note that if one of the files is out of order or mangled, the uncompress will fail gracefully so one can go back and determine the problem bits and try the cat again. Now we’re going to unpack the archive, and shuffle directories a bit to ensure the content lands in the expected location:

Note that it’d be a good idea to do this as a non-root user. Look at /sbin/adduser for how to create a new user.

Now set up directories for the compile then extract.

# ROOT=/usr/src386; export ROOT
# mkdir $ROOT; cd $ROOT
# mkdir usr; cd usr
# tar xf <pathto>/sysvr4.tar
# mv svr4 src

We can check that the source tree has landed in the right place if you see something like this:

# cd $ROOT/usr/src
# ls
:mk         :mkcmd      :mkucbcmd   :mkxcplib   pkg         uts
:mk.addon   :mkhead     :mkucbhead  add-on      proto       xcplib
:mk.arch    :mklib      :mkucblib   arch        ucb.dirs
:mk.csds    :mkoam      :mkuts      cmd         ucbcmd
:mk.fnd     :mksyshead  :mkxcp      head        ucbhead
:mk.i386    :mkucb      :mkxcpcmd   lib         ucblib
# 

We can get some info on how to compile the whole tree from /usr/src386/usr/src/proto/i386/README.

# ROOT=/usr/src386;export ROOT
# cd $ROOT/usr/src
# nohup sh ./:mk AT386 &
Sending output to nohup.out
100   <- or some random PID

This process sets up the ‘cross-compiling’ environment and builds all the libraries, dependencies, and the utility programs.

We can watch the compile’s progress by using tail:

# tail -f nohup.out

…and using <DEL> to break tail. Wait a bit for this to finish.

For building a kernel, we have to add a little to the recipe in the README:

# cd $ROOT/usr/src
# sh ./:mk.arch AT386
# sh ./:mkuts AT386

The :mk.arch invocation ensures that the AT386 dependent files are copied into the unix kernel directories. After :mkuts there will be a compiled unix kernel in $ROOT/etc/conf/cf.d.

Writing base system installation floppies

The Base System Package recipe in the README works. This will require 12 floppy disks (or images), assuming that one uses 1.44Mb floppies.

# cd $ROOT/usr/src/proto/i386/at386
# PATH=$ROOT/xenv:$PATH; export PATH
# make -f proto.mk package

However, it appears that the makefiles for csds (csds.mk) and PACKAGES (PACKAGES.mk) are missing, precluding at the moment of regenerating the other distribution packages. Fortunately there’s some example of what a package should look like internally in $ROOT/usr/src/proto/i386/PACKAGES/peruser for future work.

Writing boot floppies

‘Tape’ here generally refers to Wangtek 5xxx tape controllers with QIC-24 drives (typically DC450 or DC600 tape cartridges), though it’s not clear how we actually write a tape. Nevertheless, the same makefile is used to write the boot floppies. This makefile will require 2 (not necessarily formatted) 1.44Mb floppies, or floppy images in the simulator.

make -f tape.mk bootflop

With these new images I was able to round-trip the system, booting from boot floppies generated from the sources provided exclusively rather than relying on the R4v2.1 floppies. This new system claims it’s R4v3.0.

Getting man pages

For some reason this distribution of System V doesn’t come with either source or compressed man pages. What I did instead was to snarf the catman pages out of /usr/share/man from a Dell Unix System V R 4 v4 distribution, a vm of which can be found on the net. This unix version targets the same hardware but is just a bit more modern, so the contents should align well. I had to also use the /usr/ucb/man from Dell Unix so I don’t have the source. Shouldn’t be hard to concoct a shell script to do the ‘right thing’, though.

Future work

It should be straightforward to get a qemu-compatible ethernet controller working based on content found in $ROOT/usr/src/add-on/e503, which is a driver for a 3com 3c503 card. I started a bit of work for an NE2000 based on the Minix3 drivers, but my eyes bled a bit at the #ifdef-hell therein and I lost interest for the moment.