Way back in the late 90’s from the University of Utah there was this fantastic project that promised to bring Operating System construction to mere mortals but taking existing PC operating systems, Linux, NetBSD, FreeBSD and break them down to their best components, and then interlink them using COM allowing you to glue the best parts together like lego.
And the project was called OSKit.
It was fantastic for something unknown at the time for creating so called ‘bare metal programs’ that didn’t have a real operating system, but rather could use operating features like LIBC, or the EXT2 filesystem. It was almost that level of ‘MS-DOS’ like feeling from protected mode, but being able to take more stuff with you.
Take the following humble program, hello.c:
#include <stdio.h>
#include <oskit/clientos.h>
#include <oskit/startup.h>
#include <oskit/version.h>
int main()
{
#ifndef KNIT
oskit_clientos_init();
#endif
#ifdef GPROF
start_fs_bmod();
start_gprof();
#endif
oskit_print_version();
printf("Hello, World\n");
return 0;
}
Compiling this, and linking it is pretty straightfoward:
i586-linux-gcc -c -o hello.o -DOSKIT -MD -DHAVE_CONFIG_H -DOSKIT_X86 -DOSKIT_X86_PC -DINDIRECT_OSENV=1 -I. -I../../examples/x86 -I../../examples/x86/more -I../../examples/x86/shared -I- -I../../oskit/c -I../../examples/x86/shared -I../.. -I../.. -nostdinc -Wall -O2 -g hello.c
i586-linux-ld -Ttext 100000 -L../../lib \
-o hello ../../lib/multiboot.o hello.o \
-loskit_clientos -loskit_kern -loskit_lmm \
-loskit_c ../../lib/crtn.o
And of course transforming the ELF into a multiboot executable that GRUB can load:
/oskit/bin/mkmbimage hello
And now you are ready to boot, on say Qemu?
I was kind of surprised it never really took off, maybe it was too far ahead of it’s time. The most notable project I’ve seen that used it was OSKit-Mach, although they later on abandoned OSKit.. I’m not sure why but I would suspect the lack of updates post 2002 would have something to do with it.
Building this was… Interesting as I recall this being somewhat difficult, and I know I’ve probably made it more difficult, but I thought it would be ‘fun’ using the tools of the time. And 1999 has us at Debian 2.2r0. Which thankfully is on archive.org and is a mere 3 CD-ROMS for the i386 binaries. Installing that into VMWare wasn’t so difficult, and swapping CD images around I was able to get enough installed to start building things. For those of you who don’t want to install Debian, here is my pre-compiled Linux on Linux toolchain: i586-linux2.tar.gz. It’s i386 on i386, so you will need to be able to run i386 ELF exe’s. For OS X users that haven’t installed Catalina, you can try OSX-Linux-2.00-i586-gcc2723.tar.gz
I should point out, that although things have to be patched around for older versions of OSKit, 20020317 does build fine using GCC 2.95.2 (20000220) from Debian 2.2r0. So if you want to build in a VM, then you really don’t need any of this. But I’m strange, and I have my WSL2 Debian 10 to think about. So the easiest way to build GCC 2.x is with GCC 2.x so why not start in Debian?
First let’s prep our destination directory, and populate it like a good little cross compiler:
rm -rf /usr/local/i586-linux2
mkdir -p /usr/local/i586-linux2/i586-linux/include
(cd /usr/include;tar -cf - .)|(cd /usr/local/i586-linux2/i586-linux/include;tar -xf -)
mkdir -p /usr/local/i586-linux2/lib/gcc-lib/i586-linux/2.7.2.3/
cp /usr/lib/crt*.o /usr/local/i586-linux2/lib/gcc-lib/i586-linux/2.7.2.3/
mkdir -p /usr/local/i586-linux2/i586-linux/lib
cp /usr/lib/*.a /usr/local/i586-linux2/i586-linux/lib
With that out of the way, we can build the ‘patched’ binutils that was on the old OSKit archive, I used this binutils-990818-patched.tar.gz
./configure --target=i586-linux --prefix=/usr/local/i586-linux2
make install
Next I’m going to build GCC 2.7.2.3 as OSKit mentions to use 2.7 and I figured why not the last of the line? It seemed like a good idea to me.
./configure --target=i586-linux --prefix=/usr/local/i586-linux2
make LANGUAGES=c libgcc1.a
make LANGUAGES=c
make LANGUAGES=c install
Building is a little weird, as I build the libgcc1.a first, then ONLY the C language, then install that. OSKit is written in C, and I didn’t feel like even looking at dependencies for C++/ObjectiveC
Unix person, I’m not a great one, so a quick hack to get the new GCC onto the path:
PATH=/usr/local/i586-linux2/bin:/usr/local/i586-linux2/lib/gcc-lib/i586-linux/2.7.2.3:$PATH
export PATH
And now I can build stuff!… I then tar’d if up and copied it to my WSL instance, and now I can cross compile fine (a big plus of WSL2 is that you can install the 32bit support, and run old EXE’s! Take that Apple!)
Next up is OSKit, I’m using the last version from 2002, oskit-20020317.tar.gz.
Now it’s worth noting that a few things need to be edited, the ‘OSKit on UNIX’ thing won’t build cleanly and I didn’t investigate as Qemu is a thing now. So disable it in the modules.x86.pc file. Then run configure like this:
sh configure --host=i586-linux --prefix=/oskit --build=i586-linux --enable-modulefile=modules.x86.pc
Despite using the host, build or target setting it doesn’t pick up prefix of our cross compiler, so you have to manually edit Makeconf
Be sure to change the tool exports to look like this:
export CC = i586-linux-gcc
export LD = i586-linux-ld
export STRIP = i586-linux-strip
export AR = i586-linux-ar
export RANLIB = i586-linux-ranlib
export OBJCOPY = i586-linux-objcopy
export NM = i586-linux-nm
And finally remove -fno-strict-aliasing from OSKIT_FFLAGS, and now you can build!
The bonus is that it’ll build well under a minute on a modern machine.
As mentioned above you should now be able to take the hello world example kernel, and transform it to a multiboot, and boot it via grub.
Again this was such an exciting project I’d hate for it to just suddenly die in absolute obscurity. Maybe it’ll inspire others to try “assisted bare metal” programs, there was a DooM OS, among others in the era.