Using a CP/M machine to log into a Linux server using an RS232 connection

terminal prompt Because -- why not?

Also, this is a good test that the serial communications ports and cables are working properly. The objective here is to use my CP/M system, which is based on the RC2014 bus, to operate a Linux server using RS232. It's a reasonable place to start fiddling with serial communications, because we know that Linux will support terminal sessions over a serial connection -- although this can be a little fiddly to set up.

System set-up

The diagram below shows the test configuration.

Diagram of the system set-up

The CP/M system has its serial console port connected to a terminal emulator (which is a self-contained unit based on a Raspberry Pi 3, but that's not really important). The second serial port is connected via a serial cable to the Linux machine which, since modern PC-type hardware doesn't have a real serial port, uses a USB-serial adapter. At the Linux level, this serial connection appears as /dev/ttyUSB0. Most USB-serial adapters are supported by modern Linux distributions without additional software or configuration.

All the 'RS232' lines in this diagram are actually using 5V TTL logic levels, not real RS232 (which typically uses 12V). In a simple test like this, there's no point adapting the logic levels to real RS232 and back again. Of course, to use a 'real' RS232 device, like a serial printer, you'd need a level converter.

The CP/M system

The system I'm using has a Z180-based main board with two serial ports. One of these is used for the main user console, while the other is unassigned. This second serial port appears in CP/M as UC1 ("user console 1"), among other things.

The CP/M system uses ROMWBW firmware, which supplies a CP/M utility mode for setting the serial port properties (baud rate, etc). This utility is specific to the CP/M implementation -- other firmwares will have their own ways of setting up ports. Within the mode utility, the second serial port is referred to as COM1.

I'm using Kermit on CP/M to make the connection, although ROMWBW supplies a simple utility which will actually work fine for this simple test. I've been using Kermit because it's supposed to support software flow control (of which, more later). CP/M Kermit exists in various versions for particular hardware. I'm using the 'generic' version, which should work on any CP/M whose BIOS has IOBYTE support. That is, it has the ability to redirect the standard console to auxiliary hardware. Because Kermit can be slightly awkward to build, here is a binary of Generic Kermit 4.11 for CP/M.

The fastest baud rate I've been able to use reliably is 19200. To set the serial port to use this baud rate, I do:

B> mode com1 19200

The Linux system

My Linux system is running Fedora which, for better or worse, uses systemd to control log-in access to serial terminals. To start a log-in listener on the USB-serial port, I use systemctl as follows:

# setenforce 0
# stty -F /dev/ttyUSB0 19200 
# systemctl start getty@ttyUSB0

setenforce 0 turns off SELinux security enforcement, which might not be a good plan in a production system. This is only necessary because of a bug (sigh) in the systemd implementation in my version of Fedora -- other systems might not need this measure.

It's necessary to set the baud rate before starting the listener -- I've noticed that if I do it later, it appears to change but, in fact, does not.

For the record, what systemctl actually ends up doing is to run agetty, like this:

agetty -o -p -- \u --noclear ttyUSB0 vt220

agetty is a modern, cut-down version of the traditional Unix getty, which listens for serial connections, and invokes login to start a user session. The way that systemd invokes agetty can be modified by hacking on various systemd configuration files, but the default behaviour is fine for simple testing.

Logging in

With agetty running on the Linux system, and both systems configured to use the same (low-ish) baud rate, it's just a matter of running kerm411 on the CP/M system, and typing CONNECT at the prompt. Here is a screenshot of a log-in session, just to demonstrate that it actually works.

screenshot of the Kermit session


I expected to have problems with terminal compatibility but, in fact, I did not. I feel that it's only fair to point out that this is because I'm using a Linux-based terminal emulator with my CP/M system. By default, Linux assumes that the terminal -- whether it's a real terminal or just an on-screen console -- is broadly VT100 compatible.

The heyday of CP/M predates the VT100, really. If I weren't using a VT100-compatible terminal emulator, but a real serial terminal of earlier vintage, things would be a little more complicated. However, Linux has wide terminal support so, provided I use a supported terminal, probably all I need to do in Linux is to set the TERM environment variable to match the terminal I'm using. So, in fact, terminal compatibility isn't really a problem at all.

What definitely is a problem, however, is the lack of hardware flow control in the serial port. My Z180-based main board has full flow control in the console port, but no flow control in the second serial port. This, I'm told, is a limitation of the Z180.

I've been using Kermit for communications because it's documented as supporting software (XON/XOFF) flow control. This should be a viable alternative to hardware flow control but, in practice, it doesn't seem to work very well. If the Linux system sends a large amount of data to the CP/M system (and 'large' here depends on the baud rate), some characters get dropped. I suspect that the Linux system is so fast, compared to the CP/M system that, by the time the CP/M system sends its 'XOFF' to pause transmission, the Linux system has already sent a heap of data. Whatever the explanation, I can't get baud rates greater than 19200 to behave well. To be fair, it I were using a long serial connection between the two computers, or a telephone modem of 1980's vintage, I probably wouldn't be able to get speeds much faster than that anyway.

Closing remarks

I can't think of many good reasons to use a CP/M system as a front end to a Linux server -- especially when the CP/M system has its own Linux-based terminal. Still, it's good to know that ancient technologies can, to some extent, be used with modern ones.