« Back

FreeBSD on a 386

29 Sep 2024 - faintshadows

Does this count as a SepTANDY post??

There's a machine I have, that I've wanted to make a post about for years now. That machine is my Tandy 2500SX/25, a 386 PC. But all it does is run DOS! That's boring! How could I make this more interesting and worthy of a blog post?!

Enter, FreeBSD 2.0.5. A release from early 1995, I figured it would be good enough for use on the Tandy. I was going to go to 1.x but there were some pretty big performance upgrades going from 1.x to 2.x that I decided to push what I could get away with and aim for that.


But first, some backstory on this machine, how I got it, specs, etc.

This is actually not my only 2500SX, I techincally own two. The first one came from my aunt, who noticed I took great interest in it during a family reunion. During another visit she decided to let it go after checking to make sure there was nothing important left on it. So I took it back and it became the oldest PC I own. Not oldest computer, that goes to the TI99/4A. Having used it for a while I was really liking it, but it developed an issue. After being on for a bit, the video would start to slowly corrupt over time, bad VRAM for sure. Not to worry, I can get an ISA video card for it and be good. However, something posessed me to think maybe the power supply was failing. Not completely unwarranted, it is a pretty old machine after all. But me being a fair bit younger, and a lot more careless, saw that it had the same connectors as an AT power supply, and blindly hooked it up. And just like that, a random chip on the board quite literally caught fire. It was toast after that, and I felt awful. Terrifed of being asked how it was by my aunt, I panic bought another one of the same computer off ebay for a disgusting amount. But now I have two.

The second one arrived and it feels like it was used in a shop or some sort of industrial environment. It was filthy. But, most importantly, it worked. It even came with a few cards too, a Tandy official 2400bps modem, and a dual port serial card. The specs were identical though, both machines had:

Not great, not terrible. Especially for 1992, the 386 was getting pretty old at this point.

It ran DOS like a dream, the configuration I had when I got the first machine was DOS 5.0 and Windows 3.1, perfect for this configuration. It would hit the page file a bit under Windows, but it wasn't unusable.

Curiously, the second machine just… can't run Windows. I've never been able to figure it out. It'll run the installer fine, but once you get into Windows proper, the system just hangs. Ctrl+Alt+Del doesn't work kind of hang.

No big deal, I say, as I have other machines I can run Win3 on if I really must do so. It runs better under pure DOS anyways. But that doesn't stop me from trying to do other stuff with it.

Before I could do much more than DOS though, I had to figure out the RAM situation. This has 2MB of RAM physically soldered to the board, pretty ahead of the time. ;p Unlike some of these modern machines, there also exist RAM slots, how generous. 4 30-pin SIMM slots are present, and as the machine sits currently, there's 4x1MB sticks in there, bringing us to 6MB total RAM.

You'd think, though, hey 4MB SIMMs exist, can't you use those? Yesn't! On paper, and by paper I mean Radio Shack's actual docs for this machine, you can put up to 16MB in here, the onboard 2MB will just be ignored. So I ordered 4x4MB sticks, but they failed the initial memory test every time.. Even just putting 2 in there for a total of 10MB still did it. What gives?

I tried my best to look into this further, and using my group chat as my rubber duck, we collectively figured out that the chipset may be at fault here. There were 3 revisions of this chipset made, and only the latest supports 4MB SIMMs. But, I have that revision. Digging deeper into the datasheet for it, there's an interal register that should have a bit flipped to support 4MB SIMMs. The current theory is that there may be a bug in the BIOS or something that causes it to not set that bit, so while the memory routine can count up past 6MB, the memory tests always seem to fail just past 6MB. It's also possible there's a broken trace for an address line or something, but everything looked intact, and I don't have schematics to be able to trace out where all these address lines go.


So we're stuck with 6MB RAM. What can we do with that? Well, FreeBSD claims you can run it on any 386 or higher machine with 4MB of RAM. Though they don't recommend the 386sx specifically, and I have to imagine that's due to the pretty harsh limitations the SX has over the DX. No math co-processor for one, but you're stuck with 16MB of RAM max, and your data bus is only 16 bits, despite the internal architecture being 32. All memory accesses take twice as long.

That won't scare me away though, anything but DOS on this thing, please.


To make two weeks of pulling my hair out short, it's not trivial to install on this thing. I can't use a CD, both because installing one causes the POST to hang, and because FreeBSD 2.0.5 has zero (0) support for IDE/ATAPI CD drives. None whatsoever, you have to use SCSI. And I would, if I had a SCSI ISA card. It would have made this whole process easier.

So what took so long? Getting it to boot after installing. (Let me be honest, I didn't actually spend two weeks non stop with this thing, I did do other things with my life. But there were days were all I did was fight this thing.) I would go through the installation process, everything would check out, but once it got to booting off the hard drive, the kernel could not be found.

This was a combination of issues, most of them my own skill issues. The gist of what happened here was I had to upgrade the hard drive past the 85MB I had originally. It was just too small to do anything but the barest of minimums. The next smallest drive I had was a 1.2GB one, so that's what I went with. 1.2GB in a 386 is pretty wild, but especially so when the BIOS is one of many from this time that top out at 504MB. 1024 cylinders, 16 heads, 63 sectors. This drive does work in that configuration, DOS just sees it at 504MB. FreeBSD sees it as 1.2GB, it knows better.

The issue on my end was failing to do basic math. I made a 450MB DOS partition, and gave the rest of the disk to FreeBSD. And I followed roughly what their recommended partition sizes were, doubling some since I had the space to do so.

Those of you who can do mental math can figure something pretty important out. 450+64 is a bit more than 504MB. That puts the end of / at 514MB. I, having been staring at the same install process for like 6 hours at this point, could not figure that out. It took a week away from this to realize what I did wrong.

"Why do you need the DOS partition? I thought you didn't want DOS?" Good question, reader I just made up so I can explain more things. Installing from floppy is slow. Like, the glaciers move faster than this slow. Writing a full diskette on my desktop takes around 80 seconds. Reading that disk back in the FreeBSD installer took about 15 minutes. Per disk. The minimal-ish install I chose would take about 4-5 hours of just file copying.

Installing from a DOS partition takes about 20-30 minutes. From the start. Hell, even copying all the files to that DOS partition was so much faster than letting FreeBSD do it! In about 15 minutes I could have all 16 floppies copied over.

I figured I would give DOS a decent chunk so I could throw whatever on it later, and have a sick dual boot setup going on. I was too generous, and in it's current state, the split between DOS and BSD lies at 300MB.

Now that the entirety of / exists within 504MB, we're golden. It's installed and running.

So now what? Just what can you do with FreeBSD on a 386?

Both more, and less than you'd think, honestly. This thing is slow. Of course it is, it's a 25MHz 386SX. But it came as a sort of surprise since DOS has no issues running here, and even just messing around in a shell on BSD isn't that bad. But opening a manpage takes well over a minute on average. Nevertheless, I spent this long to get it working so I'm gonna make the best out of it and try to put myself in the shoes of someone who was trying out this BSD thing back in '95 on their 3 year old Tandy. I'm just cheating a little bit with the 1.2GB drive. Which to be fair, DID come out of a machine from 1995. Maybe 1995 me just had enough money to get a nice new hard drive but didn't want (or think I needed) a hardware upgrade.

For getting files on and off this, I've been using ZModem to my desktop. But ZModem isn't included as part of the base distribution. Enter the Ports Collection.

As a Gentoo user (btw), the ports style of obtaining software is more or less known to me, so this was whatever. But I had to get the files on there somehow. I tried making a DOS floppy with the files on it and copy it over, but that somehow created a looping directory structure and it was a mess. So I did the next best thing, throw a tarball on the diskette, copy it over via DOS, and then extract it under BSD. In retrospect I should've done that first, given how slow floppy accesses are under BSD.

I should note (since I think this will be pretty important later on) that due to some weirdness in how the 2.0.5 media I was using was made, I can't read any of the files from the ports collection on disc. They all have I/O errors. So I'm using the ports collection from the 2.1.0 media. Since I'm compiling, I don't think this will cause too many issues, but it's not like nothing changed between those two versions.

I didn't time how long it took to build ZModem, but I'd guess it was about 15 minutes. That's actually a hell of a lot faster than I thought it would. It helps that it's a pretty simple project, the whole archive was around 60k. I did compile ZSH, which took 45 minutes. Halfway through that I was thinking about how advanced ZSH is compared to C Shell, and that I already am struggling for memory enough, throwing in a fancy shell like ZSH would kill this thing.

File transfers over ZModem aren't the fastest thing, but they're pretty close to line speed. 38400 baud nets me about 3.5-4KB/s (that's bytes, not bits), which was in the ballpark of about 22000 baud on the lower end. One small issue, while I can run 38400, and even 115200 baud fine, a file transfer will quickly fill up my tty with buffer overflows. Now I had a feeling that the UART in this machine wasn't all that great, and looking further, dmesg claims the serial port is a 16450, not the 16550 you know and love. the 450 is a cheaper chip, and has smaller buffers and can't really go past 9600 baud. 9600 would make file transfers a chore, and I think figuring out how to split tarballs into 1.44MB chunks and copying those over via floppy would be faster. However, after some (limited) testing, it looks like 19200 is a good middle ground, the transfers are about half as fast (~1800B/s) but I copied over the entire ports tree (1.5MB compressed) and had no buffer overflows. More testing will be required, I'd like to get a checksumming tool on here somehow to verify all my files are coming across intact at faster speeds. ZModem has built in checksumming, but I'd like to be doubly sure.

Remember 2 paragraphs ago when I mentioned using 2.1.0's ports on 2.0.5? It's been a day since I wrote that line and now I'm already changing my mind and have upgraded to 2.1.7. Mostly just to save myself and not cause any issues down the line, just in case..

Enter, the Pentium machine. It has a working CD drive, so why not just throw the hard drive in there and copy everything over right off the CD. Ideally, I should just be using that machine for all the FreeBSD stuff since it's actually a hell of a lot faster, but that's no fun. It's not off the table though, just not the focus of this project.

FreeBSD 2.1.7 comes with a tool for DOS that prepares your system for a DOS partition install, and gives you a menu to select all your dists from. How neat is that? That's pretty neat. I selected all that I needed, and added some of the source dists, just so I can rebuild a kernel if need be. I can grab any more later on and just zmodem them across, but since I was already here with access to the CD-ROM.

The install process is mostly the same, though the post-install is also a lot better. They ask a bunch of questions, like if this machine will be on a network or if you want to be a server. They even let you go through the pre-built packages on the CD and let you grab stuff that way. Which I did, I grabbed a few programs I otherwise would've compiled. Small stuff like top and sudo, and unzip for any software that comes in a zip. I also grabbed Midnight Commander. I tried to get Nethack and vim, but the pre-built versions of those required X11 libraries that I didn't have, and did not want to get otherwise.

In retrospect (since this paragraph is about 6 hours later), I should've just found those libraries. Something's weird with the ports tree on this install, I had to do a lot of work just to get ZModem to install again.

Long story short, I thought to myself, I wonder if the reason I couldn't install a CD drive in this was because of that hard drive? So I tried it again and it worked! HOWEVER, there was a strange gotcha with this. Stable, that CD drive was not. And I don't think it is the drive either. The ATAPI support in FreeBSD at this time was pretty rough, definitely alpha-grade quality. The combination of that, plus the fact that I was using a CD drive from 2005 probably led to some weird issues ending up in failed file transfers and more silent corruption. It's a bit of a shame, I really would've liked to be able to use the CD directly.

But, we have ZModem now, so we're back where we were, but now on 2.1.7. I've copied over the ports tree via ZModem, after creating an archive of it on my desktop.

At this point I should spill the beans a little bit. I cheated. I used the Pentium to compile some software. In my defense, the drive crashed and I had to reinstall anyways (long story, don't worry about it). I could move files over at 115200bps! I'm wishing I picked this machine and not the 386, but I'm committed, I wrote this much of the blog post, it would be a shame to throw it all out.

What I won't compile on the Pentium though, the kernel. I on average have about 400-800k of free memory once the system boots and I log in. Of the 6MB total, that's not great. I've already trimmed down as much of the background processes as I can, so the next step is make the kernel itself smaller.

I configured the kernel with just what I had in this system, which thankfully was not a whole lot, most of the configuration file is just comments. And then it was time to make. Well, make depend first. Then make, finally make install.

The first two I timed the commands, and they took 13m10s and 1h37m respectively. I knew it was gonna be a long one, since even make depend instantly put me 3MB into swap space. During the main compilation, my second TTY with top running just froze up completely, I reckon the process got swapped out. My fault, I shouldn't have run top. It uses around 700K of RAM anyways, that's toooo much for this thing.

The resulting kernel image was 623520 bytes, the GENERIC is 1219920. That's almost half the size! But, does it boot? Of course not!

panic: Nobody wants to mount my root for me

How sad. So what did I mess up? To no surprise, it was a typo, or more accurately, me commenting out more than I thought I did. I seemingly told the kernel it doesn't need the Berkley Fast Filesystem driver, you know, the filesystem on the hard drive. It was 3AM, I was not all there when I wrote that config. Oh well. Good news, that was an easy fix. Bad news, I have to start over from scratch on the build process, so that's another two hours gone. To try to help the compilation speed and memory usage, I disabled all other TTYs so I only have the one console available. Each getty instance took around 400K with no user logged in, that's valuable RAM the compiler could use! Doing that shaved off 16 minutes! 1h21m.

Thankfully, that worked! So the kernel is about half as big as the GENERIC, how's the memory usage? I don't have a tool like free, best I got as of now is using top, and upon initial inspection, it looks about the same. But what does the kernel say at boot?

FreeBSD 2.1.7-RELEASE #0: Fri Aug 30 17:17:29 CDT 2024

root@tandy:/usr/src/sys/compile/TANDY

CPU: i386DX (386-class CPU)

real memory = 6684672 (6528K bytes)

avail memory = 5316608 (5192K bytes)

I have, at the time the kernel boots, 5192K free. The GENERIC's initial output was

FreeBSD 2.1.7-RELEASE #0: Wed Feb 19 23:08:10 1997

jkh@thingy.cdrom.com:/usr/src/sys/compile/GENERIC

CPU: i386DX (386-class CPU)

real memory = 6684672 (6528K bytes)

avail memory = 4771840 (4660K bytes)

I gained 532K by running my own kernel. Not too bad.

My next goal was to get NetHack running. It's the only application here that's at least somewhat recognizable or interesting, that doesn't also require a X server running. That's not happening on this machine.

Reading the docs for NetHack, it should build just fine without X, but if I try to run it through BSD Ports, it assumes I do want X. So I dug through the patchset they're applying, and changed what I could to get a TTY only install. Unfortunately, there was something else telling ports that this package wanted X, so I decided to build it out of tree.

I extracted the sources in my home, and followed the instructions given for configuration, and referenced the BSD patchset. I then built it, which took longer than the kernel at around 1h40m (I forgot to write down the time). It ran! But I had my boyfriend try it out as he's more familiar with the game than I am, and he noticed some weird issues. One, color wasn't working (though I figured that out later), and two, "far looking" wasn't working right.

"Far looking" just lets you move the cursor somewhere else on screen, and the game will tell you what that thing is. For whatever reason, it wouldn't show anything, just Done. Saving a game doesn't work right either, it fails to decompress on load.

I decided to try to install the packaged version again, and see if I can just install the libraries it wanted, but it wanted lX11.so, which as far as I can tell, is from actually installing X. So that's out.

At this point, I feel like I've exhausted what I can do with this machine. It's pretty disappointing for me as I imagine it is for you, reader. All this talk, all the re-installs, and all the time spent compiling code, and for what? I just proved the FreeBSD developers right, a 386 is not a suitable machine. Maybe if I could figure out the RAM issue and get 16MB, it may be worth revisiting again, but that CPU is really holding it back here, especially being a SX.

It's a shame, because what does run, however basic it may be, is actually pretty decently speedy. Not great, but for a tty only machine, it's pretty alright. Lynx can render the FreeBSD Handbook HTML files pretty quickly, and it doesn't feel like it's struggling at all with it.

I'm not entirely giving up on this, I'm going to leave the install intact, but I think it is time for me to move on to another project for now. If you, the reader, have any ideas, feel free to drop a line. But for now, thanks for reading!

~faint