The BootLPT/86 project was created to allow booting of classic and vintage x86 systems through the parallel interface using a cross-over LapLink null printer cable. Originally inspired by Martin Řehák’s ROMOS project, it is defaultly provided as a ROM image for any PC-compatible systems, and can also serve as a fallback boot option, should all the other boot options fail. The BootLPT/86 project is available as a complete source code package, currently hosted on a GitHub repository, which can be downloaded or cloned by anyone.
The ROM was originally created while reviving a PC-compatible diskless workstation named EarthStation-I by Alloy Computer Products Inc., that I’ve obtained for a dime, in a near-mint and untouched state. This whole system was enclosed in a keyboard form factor, and as a workstation, it was only meant to be connected to an ARCNET network server, containing no disk drive or any other expansion provisions and allowing network boot only; either through Novell Netware, CBIS Network/OS or a custom network boot PROM. Since the machine also contained a serial and a parallel port, the inspiration was to reincarnate the thing without having some woefully obsolete ARCNET contraption up and running. After my initial success, I have also made a variant to be used in the IBM PC and compatibles, that allows parallel port boot as an alternative, if the floppy or hard drive boot options fail.
The inspiration came from RayeR’s ROMOS project that aimed to encompass a working FreeDOS boot image wholly contained inside a BIOS chip, and also as an alternative to the serial port boot of the XTIDE Universal BIOS, whose primary function is to support IDE hard drives in XT-class machines. The alternative serial port boot is – unfortunately, when compared to the classic unidirectional parallel port – abysmally slow at a default rate of 9600 bps, supported by both machines by default; and also you are not going to cram an operating system inside an 8kB ROM that was originally designed to be used as a BIOS expansion option. This led to the creation of a parallel port bootable interface named BootLPT/86, fully compatible with the x86 used even nowadays.
BootLPT in an 8kB EPROM, inside the original IBM 5150 PC as a BIOS expansion ROM
(through a makeshift 2364 to 2764 circuit board adapter)
To minimize the memory footprint, maximize the speed and make the compilation process a cakewalk, the whole of the ROM code is written in pure x86, 8088-compatible assembly language, using FASM. There are two main variants of the BootLPT/86 ROM code, the “vanilla” BootLPT.asm and BootLPT_5150.asm that followed afterwards. Both perform exactly the same function, but differ in the initialization routines.
- The original version is designed to be placed as a boot ROM inside e.g. a network card chip socket, or as an optional boot solution if provided by the platform (this is the case with the EarthStation), or even embedded directly inside the BIOS in a BIOS chip, as the code is only something over 2K in size, in order to be invoked when ready. Using the network card example, when the BIOS tries to invoke network boot, it is usually at the end of the POST, when everything is initialized and the computer is ready to be booted. The ROM waits for a keypress to continue with parallel port boot within a given timeframe, otherwise the boot process continues with the other boot devices, depending on the order.
- The “IBM 5150”-optimized version acts like a BIOS expansion ROM that is initialized during the POST. That is, before the computer is ready to be booted up. During its initialization, it keeps silent, as it modifies the INT 18h interrupt vector handler, and the machine continues with POST. At the end, the machine will try to boot from the floppy drive (or the hard drive) using INT 19h. If both options fail, the modified INT 18h interrupt vector asks to continue with parallel port boot and waits for a keypress within a couple of seconds. Otherwise, the machine ends up with the ROM BASIC interpreter, in case of an original IBM PC, or a “no boot device” error. This behavior can be, of course, modified to hook the INT 19h boot vector, so that the parallel port boot is offered first, while the rest of the boot devices offered afterwards. This is useful if you don’t want to use BootLPT/86 as a “fallback” option if you have other boot devices ready.
You don’t have to use this variant on an IBM 5150 PC only, if your client machine accepts custom BIOS expansion ROMs too, but you will need to modify the source code a little bit (hook the INT 19h vector instead of 18h, and also modify LPT1_ADDRESS). Compilation process is described later in the article.
To integrate the boot code inside a BIOS chip, so you don’t have to have access to a programmer or a flashing device, an actual programmable chip and a network card or somewhere to put it in, consult the ROMOS project that deals specifically with this approach. Of course the ROM will only function on an x86 system with a proper BIOS, and it won’t work with EFI firmware unless the legacy ROM boot option is enabled. I do not presume anyone has a parallel interface on a system like that… 🙂
BootLPT as a custom network boot PROM in an ‘EarthStation-I‘
(right next to a BIOS chip)
So how does it boot through the parallel interface? Well, the machine to be booted up acts as a client, while a “server” provides a boot disk image. This “server” can be a DOS machine or a Windows machine, connected with the client with a cross-over “LapLink” parallel cable. The server can be even Linux or Raspberry Pi/Arduino, if you implement it and make your own 4-bit LapLink cable to communicate with the GPIO. And after your client boots up, you no longer require the server to be running, as the disk image is in the memory of the client, thus fully self-sufficient.
Because the ROM code is dependant on the x86 BIOS routines which all only run in real mode, the maximum boot image size is capped to 64K due to real mode segmentation limits. An example 64K boot disk image is provided later in the article, that launches a limited FreeDOS 6.22 session when booting, and then switches to a full DOS 6.22 session over the same cable used for booting, using Interlnk and DOS from a hard disk on a server machine; it then can access all files on the server. This is not required, however – you can boot anything that fits in these constraints. See the ROMOS project for an example of other boot disk images.
An improvised EPROM eraser with a 6W UV-C tube (takes 40 seconds to erase completely)
Of course you are free to use electronically erasable PROMs!
Or try embeding the boot code in your BIOS chip if you’re courageous.
So how do you compile and use this? You need FASM to compile the boot code client; any suitable C or C++ compiler to build the server binary (a pre-built DOS binary with an example boot disk image is available), a null-printer “LapLink” parallel cable that you can make yourself, and some technical knowledge of your client machine.
Besides that, you will require up to 64K of free memory (funny, but this can be an issue in vintage systems) and knowledge of your memory map, so that the boot image does not collide with other software or hardware in your client, causing a crash. Sometimes all you need is just to experiment with this.
If you don’t go with the BIOS-modifying approach, discussed in the ROMOS project, you also require a suitable (E)EPROM that your hardware accepts and a flasher/programming device. With an EPROM, you also need to erase it with UV-C before programming, pictured above. The boot code is just over two kilobytes in size, so a 2764 (E)EPROM is more than enough, although – depending on where you put the ROM – you might need a conversion adapter; at least for an IBM PC, which only accepts 2364 ROMs, like in a Commodore, that are not that easy to find (finding a suitable programmer, either). In case of placing the ROM in a network card, use a compatible one that is specified next to the empty chip socket; usually one from the 27xx series. Watch out for any jumpers on the NIC, as the card may flatly ignore the presence of your ROM in a socket if not configured properly.
Warning: To use in the original IBM 5150 PC, make sure you do not have the very first (the oldest) mainboard/BIOS revision, which does not initialize any expansion ROMs at all, and supports a maximum of 64K of RAM only. Because of this, these machines also do not initialize VGA or even EGA cards properly.
The BootLPT.asm (or BootLPT_5150.asm) is quite self-explanatory, just pay attention to the exclamation marks (!!!), which need to be suited to your client system, especially ROM_SIZE, IMG_DISK_LOAD_SEG and the like. Afterwards, to compile, just call fasm BootLPT.asm . The source code is well documented. (I think.)
After a successful compile, as mentioned in the source code, you need to patch byte 0 at offset 5, so that the 8-bit checksum of the ROM image is exactly zero. Use the patcher utility which does this for you. Or – any good hex editor will compute the checksum for you; then subtract your checksum from 0x100 hexa and write your result value onto offset 5, so that the CRC of the whole file is zero. If the checksum is already zero, you don’t modify anything. After this, your ROM is ready for flashing – or put the binary whereever your CPU can execute it.
Note that if you don’t do the patching, and the checksum is nonzero, the BIOS will ignore your ROM image completely.
Compile the server application with a suitable C/C++ compiler, you can use Turbo C++ for the DOS server, Visual C++/Visual Studio for the Windows variant (requires the InpOut DLL), or experiment with a Linux or Raspberry target. Remember, the server does not have to be x86 at all, if you manage to wire up the 4-bit parallel data cable onto the GPIO or other pins.
And that’s about the size of it – Plug the ROM in, turn on the client and server, wait to be prompted and boot! This is how it should look like with a DOS server. An example disk image and DOS server follows just below:
Here is a ZIP image that contains a compiled DOS server binary (BOOTLPT.EXE), a batch file to run the server and INTERSVR afterwards, and a 64K bootdisk BOOTDISK.IMG to be fetched by the client.
This bootdisk image in itself contains FreeDOS, a kernel compatible with version 6.22 recompiled by me, without COUNTRY/NLSFUNC/locale capabilities, in order to cram it inside the bootable image. Then a patched version of INTERLNK to run on FreeDOS (patched to skip the DOS version check, or else the application locks up the system) and a mini version of COMMAND.COM, to be supplemented by a proper COMMAND.COM from the running DOS server machine. Afterwards, the client machine can use all the disks on the DOS server machine through INTERSVR running on the DOS server, as in the video. Use WinImage or any other disk image utility to make changes to the 64K bootable image, especially AUTOEXEC.BAT or FDCONFIG.SYS, as necessary. And of course, all of this is 8088-compatible.
WARNING! The FreeDOS kernel in BOOTDISK.IMG will most probably return botched COUNTRY/NLSFUNC/CHOICE or locale/timedate related results for all DOS API-related functions. As an example, every Yes/No question asked through DOS usually returns with Yes, so you need to use Ctrl+C or Control+Break as No, otherwise everything will be taken as Yes even if you type in “N” (be careful when formatting disks!) Date, time and codepage functionality might not work as usual, too. This also applies if you use a proper COMMAND.COM after booting the image. Other than that, you should be fine, or you can try other boot disk images from the ROMOS project (I reckon they do require a better system than an 8088, though).