In the previous post, I alluded to some “extreme expect hackery” needed to configure and install a new UNIX kernel.
Note: The repository name has changed to: https://github.com/tomperrine/unix-v6-pdp11-simh-gcp
To get the most out of this post, get the files from the GitHub repo to follow along.
During the era of PDP-11 and even VAX UNIX, adding device drivers to the kernel required changing the source code. Specifically, there are a set of data structures that define the mapping from UNIX device numbers to the names of the device driver entry points (C functions). Hence, adding a device driver to the kernel requires source code to be edited and a new kernel compiled from the new sources.
The entire process is pretty well documented here.
To get from “first boot” to “booting from rk disk with all patches applied” takes a few steps:
- 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 will cover step 1 and the SIMH scripting needed to automate this process.
If we could just copy new files from “outside” (Ubuntu OS) into the file system of the “inside” or guest OS (v6 UNIX), none of this would be necessary. However, since we can’t, the only way to create files is by executing commands.
We’ll get started by figuring out how to send commands into a program that’s running inside the OS that’s inside the emulator, then (in a future post) work up to some very old-school UNIX tricks to create the needed files.
The first challenge is to pass commands to the SIMH emulator. This is done simply by giving the emulator a script file on the command line. See this example:
$ more buildunix.ini set cpu 11/40 set tto 7b set tm0 locked attach tm0 dist.tap attach rk0 rk0 attach rk1 rk1 attach rk2 rk2 dep system sr 173030 boot rk
When you start the emulator with that script file, you get this result:
$ ./simh-master/BIN/pdp11 buildunix.ini PDP-11 simulator V4.0-0 Current git commit id: 0de9b628 sim> set cpu 11/40 Disabling XQ sim> set tto 7b sim> set tm0 locked sim> attach tm0 dist.tap sim> attach rk0 rk0 sim> attach rk1 rk1 sim> attach rk2 rk2 sim> dep system sr 173030 sim> boot rk0 @
As you can see, we just gave the emulator a list of commands and they were executed by the emulator, which loads and then runs the UNIX bootloader. It’s the bootloader, running in the emulator that presents the “@” prompt. At this point, the emulator stops passing its input file to the console, leaving us “stranded” at the boot prompt. The bootloader needs the name of the kernel to load, which would normally just be entered by the user. Since we want to automate the entire process, we need to find a way to enter data but not just a a line in the script.
The emulator provides a way to SEND input into the running programs, using its own internal implementation of “expect“. This means that we can use EXPECT/SEND combinations to enter information in the programs that are running inside the OS that’s running inside the emulator. Clear as mud, right?
The “hook” is to set up an EXPECT/SEND combination BEFORE we enter the boot command, so that when the boot command executes and presents the “@” prompt, the emulator knows what to send in response. Now the script looks like this:
$ more buildunix.ini set cpu 11/40 set tto 7b set tm0 locked attach tm0 dist.tap attach rk0 rk0 attach rk1 rk1 attach rk2 rk2 dep system sr 173030 : this sets up the rkunix information to be sent later, : after we enter the boot rk command expect "@" send "rkunix\r"; continue boot rk
Which results in something more like this:
$ ./simh-master/BIN/pdp11 buildunix.ini PDP-11 simulator V4.0-0 Current git commit id: 0de9b628 sim> set cpu 11/40 Disabling XQ sim> set tto 7b sim> set tm0 locked sim> attach tm0 dist.tap sim> attach rk0 rk0 sim> attach rk1 rk1 sim> attach rk2 rk2 sim> dep system sr 173030 sim> boot rk0 @rkunix mem = 1035 RESTRICTED RIGHTS Use, duplication or disclosure is subject to restrictions stated in Contract with Western Electric Company, Inc. #
And now we have UNIX running inside the emulator, and a command prompt. At this point, our terminal is attached to the UNIX shell, and we can start to manually enter commands. But that’s not enough. We have an entire set of commands that we need to enter to add the new device drivers to the source code so we can compile a new kernel. If it was a single shell script, it would be about 70-90 lines, and of course, we still can’t just copy files into the V6 file system.
Next time, entering all the commands needed to configure and build a new kernel.