I had to resort to some old-school UNIX shell hackery to get V6 UNIX running in SIMH as an automated process.
- Boot from “tape” and copy an image of the root filesystem onto a simulated RK disk
- Boot from the RK disk, modify source code for several programs such as “df” and the kernel. Compile the new kernel, copy it into place in the root filesystem.
- Boot the new kernel from the new root filesystem.
This post covers step 2, which involves creating and editing several files to include information about new device drivers, then then compiling the new kernel. The entire process is very well documented at: https://gunkies.org/wiki/Installing_Unix_v6_(PDP-11)_on_SIMH so I won’t cover it in detail.
Recall that while we have a running V6 system, there’s no way to copy files into the virtual machine. We can enter shell commands, but not copy files into the emulated system. This means that we have to play games with “cat”, “ed” and other UNIX commands to create new files or edit existing ones. There’s a bit of a complication in that to enter commands into UNIX running within the SIMH emulator, we have to use the SIMH EXPECT/SEND commands. These are documented in the SIMH user’s guide for Version 4.
Also, remember that this is the 1975 “sh” shell. It’s very primitive. If we had the modern “here document” feature, this would have been much simpler. I’m not sure, but I believe that feature didn’t appear until 4BSD (1980). Instead we’ll have to rely on the commands that were there 44 years ago.
For example, this set of commands would normally just be entered on the command line.
chdir /usr/sys/conf cc mkconf.c mv a.out mkconf
But to use the EXPECT command, it looks like this, using “;” as the command separator to do this all on a single input line:
expect '#' send 'chdir /usr/sys/conf; cc mkconf.c; mv a.out mkconf\r'; continue
So far so good, but what about something more complex, where we’re even farther down the rabbit hole? Passing input to a program that’s running in the shell, in the emulated OS is one step further in and requires some “old school” shell hackery. For example, what about sending input into the “mkconf” program:
# ./mkconf rk tm tc 8dc lp done #
It turns out that we can’t just feed this in as multiple EXPECT/SEND combinations due to the need for embedded newlines. Any newlines in the EXPECT script would end the line, any newlines embedded in the SEND strings would also be lost.
This was a head scratcher for an hour, until I remembered some similar problems I’d had years ago doing stream editing (sed) to patch binary program files on the fly instead of re-compiling the source (don’t ask, ugly).
This led me to using the “tr” program to “send” newlines without ever using the newline character in my command.
expect '#' send 'echo \'rkXtmXtcX8dcXlpXdone\' | tr X \\\\012 | mkconf\r'; continue
You can see that the newline character never appears anywhere in the SEND string. The echo command will emit the needed lines, but with X instead of newline. The tr command will replace the X character with an escaped-and-escaped-again 012, the octal for newline. This feeds 6 newline separated strings (lines) into the mkconf program, without ever actually using a newline!
After that, it was back to vanilla scripting, until I hit another similar glitch. To add the RK disk to the list of supported devices in the “df” command, you need to edit the source to add 2 lines into an array that lists the supported devices. Interactively, this is pretty trivial (if you know “ed”).
# chdir /usr/source/s1 # ed df.c /rp0/d .-2a "/dev/rk0", "/dev/rk1", . w q # cc -s -O df.c # cp a.out /bin/df # rm a.out
And here we are again, needing to enter multiple lines to a program, without using the newline character. It’s “tr” to the rescue again:
expect '#' send 'chdir /usr/source/s1 ; echo \'/rp0/dX.-2aX "/dev/rk0",X "/dev/rk1",X.XwXqX\' | tr X \\\\012 | ed df.c\r' ; continue
And finally, one last time:
# ed /etc/ttys 1,8s/^0/1/p w q #
expect '#' send 'echo \'1,8s/^0/1/pXwXqX\' | tr X \\\\012 | ed /etc/ttys\r' ; continue
You can find all this hackery (and some other uglier things) in the “buildunix.ini file in the github repository.
For me, this was a fun trip down memory lane and the weird things we had to do, back when computers were more primitive and yet sometimes more fun.