32016 stand alone planetfall!

InfoTaskForce’87 running on a simple NS32016 emulator

What is it?

It sure may not look like much but it was an adventure getting here.

First, what is it? Well it’s the very simple NS32016 from here, with a few minor changes. I expanded the RAM from 256kb to a whopping 8MB. Then I added simple character I/O allowing me to print messages to the screen. Next looking at the toolchain page, I used my old Linux to Windows GCC 4 cross compiler to build the appropriate Canadian cross compiler to the NS3216.

Building the tools

A while back, I had built a cross compiler from Linux to Windows using GCC 4.1 as the basis as it was the last version that didn’t have massive external dependencies. NS32016 support was dropped some time in the late 3.x or early 4.x GCC so it means we need to go old anyways. I arbitrary picked GCC 2.8.1 for this build, while using the recommended Binutils 2.27

I cheated and just downloaded my existing linux-minw32.7z cross compiler as I didn’t feel like rebuilding everything again, although it is all in the Building a MIPS Compiler for Windows on a Linux VM! article. I also used an old Linux to Linux i586 32bit compiler (back from the OSKit build!) although you can use your hosts as well.

configuring Binutils is pretty simple like this:

./configure --prefix=/cross --target=ns32k-pc532-netbsd --host=i686-mingw32 --build=i586-linux

You can try omitting the –build portion, Debian GNU Linux 10 seemed okay with Gcc 8 as the default system compiler.

configuring GCC 2.8.1 was pretty similar:

./configure --target=ns32k-pc532-netbsd --prefix=/cross --disable-libssp --build=i586-linux --host=i686-mingw32

GCC 2.8.1 doesn’t quite know what we are doing so there is some flags we need to run off in auto-config.h namely

  • #define HAVE_BCMP 1
  • #define HAVE_BCOPY 1
  • #define HAVE_BZERO 1
  • #define HAVE_INDEX 1
  • #define HAVE_KILL 1
  • #define HAVE_RINDEX 1
  • #define HAVE_SYS_RESOURCE_H 1
  • #define HAVE_SYS_TIMES_H 1

You can just comment them out, or remove those lines all together.

When it came to building GCC, I did run into issues with GCC 7/8 trying to build GCC 2.8.1. I found it much easier to either have that Linux 4.1 compiler, or if you have access to Wine or WSL you can just run the Win32 binaries for the gen phases.

./configure --prefix=/cross --target=ns32k-pc532-netbsd --host=i686-mingw32
make CC=i686-mingw32-gcc xgcc cccp cc1 cc1obj

If you can run your own Win32 exe’s on Linux it’ll run just fine using the Linux to Windows GCC 4 cross. Otherwise you will need to either patch GCC or make your own GCC 4 hosted Linux to Linux cross compiler like this:

make CC=i686-mingw32-gcc HOST_CC=i586-linux-gcc xgcc cccp cc1 cc1obj

Hopefully that worked enough, and now you have your cross compiler. Now it’s time to build libgcc1.a

cp cccp cpp.exe
cp cc1 cc1.exe
cp xgcc xgcc.exe
cp ../binutils-2.27/gas/.libs/as-new.exe as.exe
cp ../binutils-2.27/binutils/.libs/ar.exe ar
cp ../binutils-2.27/binutils/.libs/ranlib.exe ranlib
make libgcc1.a TARGET_TOOLPREFIX="./" OLDCC=./xgcc.exe

Again you really want to be able to run the resulting programs on Linux but I guess you could script it out. Naturally if you wanted to just use Linux, it’d be easier to make that cross compiler directly, although I’m not sure how much of GCC 2.8.1 I want to fight, or just get GCC 4 running on Linux and use that to port.

crt0, somewhere for C to start

As mentioned a crt0.s is missing but there was enough inspiration to come up with this:

#NO_APP
gcc_compiled.:
.text
        .align 1
.globl _start
_start:
        enter [],0
#APP
#       setting the stack 256k under 8MB
        lprd sp,0x7c0000
        jsr _main
#NO_APP
L1:
        exit []
#       setting the stack 256k under 8MB
        lprd sp,0x7c0000
        bpt
        .align 1

#does nothing
.globl ___main
___main:
        ret 0

.globl _exit
_exit:
        bpt
        ret 0

I used a bit of the C example, and added some hooks that GCC was expecting namely a __main call that is made from main before it does anything (a place to init memory perhaps?), a place to catch an explicit exit call, along with setting the stack of course.

Patching InfoTaskForce without malloc / disk access

It’s not going to win any awards, but it was really great to get it to run a simple program written in GCC. Looking for something more fun, I took the old InfoTaskForce interpreter from ’87, and dug up my modification to run on cisco routers, and cooked up this version, that adds enough of printf from Linux, a bogus malloc that just allocates from a fixed memory array (otherwise you have to actually know about your platform), and a fun trick with later binutils where you can import a binary file directly as an object!

Neat!

Since I don’t have any file I/O being able to have the game data in RAM is crucial. I tried to tweak it so you could build the same working thing on Windows (maybe others?).

So for anyone who wants to look at the standalone adventure Win32 hosted tools are here, although the emulator should be somewhat portable.

GCC 2.5.8 failure on 32bit ARM

This is really nothing more than a placeholder for me… Unless someone else knows the answer, then it’s really ‘how not to cross compile GCC’.

First I’m using the EMX’ified version of GCC from my MinGW to EMX cross. It didn’t require that much massaging to get it to build, the usual unzip as ascii to convert text, and in no time I can build cc1.


root@pinepro:/src/emx/src/gcc-2.5.8# file cc1
cc1: ELF 32-bit LSB pie executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=42c0c8de7175edade7614dc92d5d13e4421e0e6f, with debug_info, not stripped

and it crashes in what has to be a 2020 most unfortunte name

Reading symbols from cc1...done.
(gdb) r
Starting program: /src/emx/src/gcc-2.5.8/cc1 

Program received signal SIGSEGV, Segmentation fault.
0x004f6b84 in rtx_cost (x=<error reading variable: Cannot access memory at address 0xff7efff0>, 
    outer_code=<error reading variable: Cannot access memory at address 0xff7effec>) at cse.c:667
667     {
(gdb) 

Yes, it really crashes in rtx_cost. Good thing there isn’t a super popular card from Nvidia that is currently being short squeezed by crypto miners right now called the RTX where everyone is looking for a good price. 😐

I had then been thinking perhaps it’s because I’m using GCC 8.3.0, maybe it’s introducing some new and exciting bug? So I cross compiled GCC 4.1.2 as follows:

./configure --target=armeb-linux --host=armeb-linux --build=armeb-linux

Keeping in mind that my knowledge of ARM is pretty much nill, especially on Linux. The compile went mostly okay, just have to remember the gnu inline macro’s as needed from back in the day (-fgnu89-inline) and while it builds, it is insisting on using collect2 which of course is screwing things up. And of course I don’t want it as my system compiler. As a hack I found system gcc 8 can link things fine as I didn’t want to spend all day messing with GCC/collect2

I copied xgcc, cc1 and cpp from 4.1.2 into a /412 directory, and rebuilt 2.5.8 with the following shell:

make CC="/412/xgcc -B/412 -g -O0  -I. \
-I./config \
-I/usr/lib/gcc/arm-linux-gnueabihf/8/include \
-I/usr/local/include \
-I/usr/lib/gcc/arm-linux-gnueabihf/8/include-fixed \
-I/usr/include/arm-linux-gnueabihf \
-I/usr/include" cc1

As you can see the cross wasn’t picking up the right include paths, so I just cheated, and dumped them from 8, and just copied them into this script. I re-ran the build and had 2 issues,

/412/xgcc -B/412 -g -O0  -I. -I./config -I/usr/lib/gcc/arm-linux-gnueabihf/8/include -I/usr/local/include -I/usr/lib/gcc/arm-linux-gnueabihf/8/include-fixed -I/usr/include/arm-linux-gnueabihf -I/usr/include -c  -DIN_GCC   -g -std=gnu89     -I. -I. -I./config local-al.c

....

/tmp/ccMguyhs.s: Assembler messages:
/tmp/ccMguyhs.s:5001: Error: selected processor does not support `fltd f1,r3' in ARM mode
/tmp/ccMguyhs.s:5025: Error: selected processor does not support `fltd f0,r3' in ARM mode
/tmp/ccMguyhs.s:5026: Error: selected processor does not support `dvfd f1,f1,f0' in ARM mode
/tmp/ccMguyhs.s:5027: Error: selected processor does not support `ldfd f0,.L489' in ARM mode
/tmp/ccMguyhs.s:5028: Error: selected processor does not support `mufd f0,f1,f0' in ARM mode

and so on. Also failing was global.c Again the same weird instruction/asm mix being triggered. Other than those two, cc1 will build, but unsurprisingly:

Reading symbols from cc1...done.
(gdb) r
Starting program: /src/emx/src/gcc-2.5.8/cc1 

Program received signal SIGSEGV, Segmentation fault.
0x004f6b84 in rtx_cost (x=<error reading variable: Cannot access memory at address 0xff7efff0>, 
    outer_code=<error reading variable: Cannot access memory at address 0xff7effec>) at cse.c:667
667     {
(gdb) 

Well, at least it’s consistent?

Or a fun way to kill a couple hours.

**EDIT I went ahead and looked in the 4.1 source for ARM stuff..

root@pinepro:/src/gcc-4.1.2# grep arm config*|grep linux
grep: config: Is a directory
configure:  arm*-*-linux-gnueabi)
configure.in:  arm*-*-linux-gnueabi)

it didn’t like the gnueabihf stuff one bit.

I tried to rebuild as linux-gnueabi

./configure --target=arm-linux-gnueabi --host=arm-linux-gnueabi --build=arm-linux-gnueabi

make LANGUAGES=c HOST_CFLAGS='-fgnu89-inline' CFLAGS='-fgnu89-inline'

And then re-built GCC 2.5.8 with the same error, but slightly further into the program:

Starting program: /src/emx/src/gcc-2.5.8/cc1

Program received signal SIGSEGV, Segmentation fault.
0x004f2a20 in rtx_cost (x=0x41, outer_code=PLUS) at cse.c:679
679       code = GET_CODE (x);
(gdb) bt
#0  0x004f2a20 in rtx_cost (x=0x41, outer_code=PLUS) at cse.c:679
#1  0x004f2e20 in rtx_cost (x=0x60c3f8, outer_code=SET) at cse.c:736
#2  0x004ac2dc in init_expmed () at expmed.c:87
#3  0x0045ae28 in compile_file (name=0x5c96ec "stdin") at toplev.c:1648
#4  0x0045f6fc in main (argc=1, argv=0xfffefd04, envp=0xfffefd0c) at toplev.c:3569
(gdb)

The positive thing is that there was no weird register errors while compiling, and it built 100% normally…? “arm-linux-gnueabihf” almost seems right, specs needs fixing to point to “/lib/ld-linux-armhf.so.3” instead of “/lib/ld-linux.so.3” along with the linker target.

Cockatrice III 0.5a update

Here’s to US!

Well this is a ‘small’ update, but with a big change, the audio is for the most part working great now thanks to this fix from rakslice. Namely changing SDL to MSB:

desired.format = AUDIO_S16MSB;

And another MinGW tweak, and yeah it’s GREAT!

Even stuff like RealAudio work now! I’ll add some self hosted video later as it’d just get struck from anything public.

Also since the RealAudio player is timebombed for installing, I added some lazy offset to remove however many billions of ticks from the clock letting you jump in some random point in the past when it won’t care.

I guess the final if any justification for a bump would be rebuilding with GCC 8.1.0 on MinGW. I somehow butchered the slirp.h to make it too MinGW’ish so it won’t clean build on Linux or OS X, but I have re-butchered a private branch and it works.. I just need to merge and clean but I’m not in the mood at the moment.

I could be crazy but it “feels” faster.

At any rate, I found that System 7 is more agreeable to running Return to Zork, just use some toast image mounter from within MacOS, and it’ll run!

Also there is some ULONGLONG weirdness going on, so I had to backout Peter’s changes for larger disks. No doubt some standard type thing change in GCC 8.

You can download binaries/source from Sourceforge.

Download Cockatrice III
Download Cockatrice III

Annoyance with the MIPS linker: relocation overflows

gcc disasm.o audio.o configuration.o dialog.o file.o hostcall.o keymap.o main.o memAlloc.o misc.o screen.o screenConvert.o sdlgui.o shortcut.o scalebit.o input.o fe2.o ../fe2.part1.o ../fe2.part2.o -L/usr/lib/mips64el-linux-gnuabi64 -lSDL -o ../frontier

/usr/bin/ld: ../fe2.part1.o: in function <code>load_binfile': fe2.s.c:(.text+0x180): relocation truncated to fit: R_MIPS_CALL16 against</code>fopen@@GLIBC_2.2'
/usr/bin/ld: fe2.s.c:(.text+0x19c): relocation truncated to fit: R_MIPS_CALL16 against <code>fseek@@GLIBC_2.0' /usr/bin/ld: fe2.s.c:(.text+0x1a8): relocation truncated to fit: R_MIPS_CALL16 against</code>ftell@@GLIBC_2.0'
/usr/bin/ld: fe2.s.c:(.text+0x1c0): relocation truncated to fit: R_MIPS_CALL16 against <code>fseek@@GLIBC_2.0' /usr/bin/ld: fe2.s.c:(.text+0x1e4): relocation truncated to fit: R_MIPS_CALL16 against</code>fread@@GLIBC_2.0'
/usr/bin/ld: fe2.s.c:(.text+0x1f0): relocation truncated to fit: R_MIPS_CALL16 against <code>fclose@@GLIBC_2.2' /usr/bin/ld: fe2.s.c:(.text+0x280): relocation truncated to fit: R_MIPS_GOT_DISP against</code>stderr@@GLIBC_2.0'
/usr/bin/ld: fe2.s.c:(.text+0x284): relocation truncated to fit: R_MIPS_CALL16 against <code>fprintf@@GLIBC_2.0' /usr/bin/ld: fe2.s.c:(.text+0x290): relocation truncated to fit: R_MIPS_CALL16 against</code>exit@@GLIBC_2.0'
/usr/bin/ld: fe2.s.c:(.text+0x2b4): relocation truncated to fit: R_MIPS_CALL16 against `__assert_fail@@GLIBC_2.0'
/usr/bin/ld: fe2.s.c:(.text+0x2c4): additional relocation overflows omitted from the output
collect2: error: ld returned 1 exit status
make[1]: *** [Makefile:18: ../frontier] Error 1

I’d never heard or seen this before, and yeah it’s some MIPS’isim.

Apparently it’s something called a “global offset table” which of course has a 64k entery limit which can cause an overflow if you are doing something crazy like running a disassembler and having tens of thousands of instructions.

Looking at the GCC MIPS options page, there is hope, one can opt for a more iniffecient and larger table with the simple option of -mxgot

FrontVM-2 20061120

And now I can link frontvm.

Building OSKit

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.

Couldn’t reserve space for Cygwin’s heap

I have this old toolchain that relies on MSYS 1.0 from 20+ years ago. It’s great. I know others always love the newer, but I’m happy with this one.

Well this morning I wanted to rebuild some Qemu 0.90 thing and I got this fun error trying to run configure:

      0 [main] us 0 init_cheap: VirtualAlloc pointer is null, Win32 error 487
AllocationBase 0x0, BaseAddress 0x71110000, RegionSize 0x440000, State 0x10000
d:\mingw\msys\bin\bash.exe: *** Couldn't reserve space for cygwin's heap, Win32 error 0

What the heck?! MSYS uses cygwin? I guess I should have known. So the solution is to ‘rebase’ the DLL, as it tries to take a static ‘grab’ at some memory block, because…. I guess subsystems or loaded DLL’s suck?

I rebooted and got the same error.

So obviously it’s a lot more involved.

So looking the rebase I have is part of the Platform SDK. Maybe there are others.

D:\MinGW\msys\bin>"D:\MinGW\include\directx\Microsoft Visual Studio 8\VC\PlatformSDK\Bin\rebase" -b 0x50000000 msys-1.0.dll

REBASE: Total Size of mapping 0x0000000000110000
REBASE: Range 0x0000000050000000 -0x0000000050110000

And now I can run stuff again. YAY.

I’m sure this has been covered time and time again, but you know it’s mostly to remind me in another 20 years.

Patching GCC 4.1.2 to build under GCC 8

What started as a spriling out of control build of SLiRP for User Model Linux (UML) I had so many issues with GCC 8, I figured I’d try v4 where I recall it building easily. Well that was. Fun.

Anywas I’m using Linux (Debian 10.5), and the build tools currently has me running GCC 8.3.0. Anyways a straight build introduces this fun:

../.././gcc/toplev.c: At top level:
../.././gcc/toplev.c:524:1: error: redefinition of ‘floor_log2’
 floor_log2 (unsigned HOST_WIDE_INT x)
 ^~~~~~~~~~
In file included from ../.././gcc/toplev.c:59:
../.././gcc/toplev.h:175:1: note: previous definition of ‘floor_log2’ was here
 floor_log2 (unsigned HOST_WIDE_INT x)
 ^~~~~~~~~~
../.././gcc/toplev.c:559:1: error: redefinition of ‘exact_log2’
 exact_log2 (unsigned HOST_WIDE_INT x)
 ^~~~~~~~~~
In file included from ../.././gcc/toplev.c:59:
../.././gcc/toplev.h:181:1: note: previous definition of ‘exact_log2’ was here
 exact_log2 (unsigned HOST_WIDE_INT x)
 ^~~~~~~~~~
make[2]: *** [Makefile:2064: toplev.o] Error 1
make[2]: Leaving directory '/home/jsteve/src/gcc-4.1.2/host-x86_64-unknown-linux-gnu/gcc'
make[1]: *** [Makefile:3905: all-gcc] Error 2
make[1]: Leaving directory '/home/jsteve/src/gcc-4.1.2'

Ugh isn’t this fun. Well it turns out it’s largely from the confusion from how GCC now handles inline functions.

I’ve uploaded the patch here. It’s not great, I know but I got a working C compiler out of it, however I had to manually place xgcc/cc1/cpp from gcc-4.1.2/host-x86_64-unknown-linux-gnu/gcc

Naturally YMMV as always.

I did see further hints on this ‘gist‘ that also boils down to using GCC in 1989 mode for inlines:

gcc -fgnu89-inline

And also this ‘stack exchange‘ that mentions that toplev also has issues with the same inline issues. Naturally if you just define inline to nothing you’ll end up with two floor_log2 and exact_log2’s from libiberty. And both are different. Fun times ahead!

As for slirp, well I took the version from the Debian source project, and manually applied all the patches and I ended up not only having to manually create some missing headers, but after getting it to build it’d just crash immediately. Bummer.

I rebuilt it as a 32bit exe, and wow it ran just fine. Go figure. For anyone crazy enough to want to build it on it’s own, this patch take slirp-1.0.16 to a ’17’ with all the current Debian patches, and my sad patch, was what I did to get it to compile with GCC 4. Note you will want to save aside the ‘.p files’ which are the headers, as the configure will remove them and either save them as empty files, or files that don’t work. … Well at least they didn’t work for me!

The whole thing started as a ‘oh wow Linux is now in 5.1.0 release’ and I figured the easiest way to check it out was to use UML. I found this page with a quick ‘how to build and roll’ your own UML’s, although the SLiRP config is a bit off in the host, as it should be 10.0.2.15 for the UML kernel.

The new killer feature is UML can mount a directory as a filesystem so you don’t have to mess around like crazy to make disk images. It makes the experience more docker like, which I enjoy.

./linux root=/dev/root rootfstype=hostfs rootflags=/home/jsteve/linux/linux-5.1.17/uml-demo2 rw mem=64M init=/bin/sh

So no I end up running this in the VM to kick off the required mounts and networking.

mount -t proc proc proc/
mount -t sysfs sys sys/
ifconfig eth0 10.0.2.15 netmask 255.255.255.0 broadcast 10.0.2.255
route add default gw 10.0.2.2
ping -c 2 10.0.2.2

Oh one thing worth pointing out is that 5.1.16 breaks 32bit compiles, you have to build 5.1.17 to get a 32bit kernel.

I should touch more on building UML but I’ve already sat on this for a week, and I’m too busy moving (yet again) to a smaller island. Hopefully a more peaceful one.

PowerPC Solaris on the RS/6000

The following is a guest post by PA8600/PA-RISC! Thanks for doing this incredible writeup about an ultra rare Unix!

One of the weirdest times in computing was during the mid-90s, when the major RISC
vendors all had their own plans to dominate the consumer market and eventually wipe out
Intel. This was a time that led to overpriced non-x86 systems that intended to wipe out the
PC, Windows NT being ported to non-x86 platforms, PC style hardware paired with RISC
CPUs, Apple putting the processor line from IBM servers into Macs, and Silicon Graphics
designing a game console for Nintendo. While their attempts worked wonders in the
embedded field for MIPS and the AIM alliance, quite a few of these attempts at breaking into
the mainstream were total flops.

Despite this, there were some weird products released during this period that most only assumed existed in tech magazine ads and reviews. One such product was Solaris for PowerPC. Now Solaris has existed on Intel platforms for ages and the Illumos fork has some interesting ports including a DEC Alpha port, but a forgotten official port exists for the PowerPC CPU architecture. Unlike OS/2, it’s complete and has a networking stack. It’s also perhaps one of the weirdest OSes on the PowerPC platform.

  • It’s a little-endian 32-bit PowerPC Unix and possibly the only one running in 32 bit mode. Windows NT and OS/2 (IIRC) were the other 32-bit PowerPC little-endian OSes and Linux is a 64 bit little endian OS.
  • It’s a limited access release, yet feels as polished as a released product.
  • It has a working networking stack.
  • Unlike AIX, it was designed to run on a variety of hardware with room to expand if more PPC hardware was sold. You can throw in a random 3com ISA NIC for example and it will in fact work with it.
  • It shares several things with Solaris for Intel including the installer.

I’m going to demonstrate perhaps the weirdest complete PowerPC OS on fitting hardware: the IBM RS/6000 7020 40p, also known as the Power Series 440 (6015) and by its codename “Sandalfoot”. The system is a PowerPC 601 based machine, featuring the PCI and ISA buses in an LPX style case. This is also one of the few machines that can run it. All screen captures are from a VGA2USB card as emulators cannot run anything but AIX.

What you need to run Solaris PPC

To run Solaris, the system requirements are just like that of Windows NT for PowerPC. You need a PReP machine (PowerPC Reference Platform, not to be confused with the HIV prevention pill or PrEP according to Wikipedia). Now finding a PReP machine is perhaps the hardest part of setting up Solaris for PowerPC and to understand why you need to know a bit about the history of the PowerPC platform.

One of the biggest problems with PowerPC hardware to this day has been the sheer inconsistency of how each machine boots. While Alpha machines had SRM/ARC and SPARC machines had OpenBoot, each vendor had their own way of booting a PowerPC machine despite rolling out standards.

There were essentially two different camps building PowerPC machines, IBM and Apple. IBM’s plans for universal PowerPC machines consisted of industry standard, low cost machines built around a PowerPC CPU, chipset, and lots of supporting components lifted from the PC platform along with PCI and ISA. The CHRP and PReP standards were essentially PCs with PowerPC processors in them. IBM’s plan was that you were going to replace your PC with a PowerPC machine someday. This was cemented by the fact that Windows NT was ported to the PowerPC platform, that OS/2 had an ill-fated port, and that a handful of third party Windows NT PPC machines were sold.

Apple on the other hand wanted to build Macs with PowerPC CPUs. Older Power Macs featured no PCI slots or Open Firmware, only NuBus slots carried over from classic 68k Macs. In fact much of the boot and OS code was emulated 68k code. Later on Apple would lift bits and pieces of things they enjoyed from the PowerPC standards such as Open Firmware, PCI, and even PS/2 and VGA ports on the clones. Apple’s plan was to replace the PC with the Mac, and Mac clones featured Apple style hardware on LPX motherboards. While the PCI clones featured Open Firmware, this version was designed to load the Macintosh Toolbox from ROM while “futureproofing” them by adding in the ability to boot something like Mac OS X/Rhapsody or BeOS.

Despite these similarities Macs were their own computers and were nothing like the IBM systems internally, aside from sharing the same CPU and maybe Open Firmware later on. But even Macs with Open Firmware were incapable of booting from hard disks formatted for IBM systems and vice versa. This is a common problem with installing PowerPC Linux as many installers do not check which machine they’re run on. Furthermore unlike modern day Intel Macs, PPC Macs were designed to only boot operating systems specifically written for them. They were incapable of running any OS solely written for the IBM machines.

The confusion between PPC machines has also caused a forum question to pop up, “how can I install PowerPC Windows on my Mac?” Even today the new OpenPower/PowerNV machines use a different bootloader than IBM’s hardware and completely lack Open Firmware.

Anyhow IBM built several different generations of PowerPC UNIX machines under several brand names including RS/6000, pSeries, and Power. Nearly all of them (aside from the Linux models) will run AIX, and later ones will run IBM i as well. Not just any PowerPC IBM hardware will run the OSes designed for PReP hardware however.

To run these old PReP OSes you’re looking at a very specific set of machines from the 1994-95 period, many with no characteristic diagnostic display most RS/6000 machines have. To run PowerPC Solaris much of the same applies here. You need a RS/6000 40p, or 7248 43p (not the later 140 and 150 with the display). The rare PPC Thinkpads and Personal Computer Power Series machines will run Solaris as well. It’s also compatible with the PowerStack machines from Motorola and one BetaArchive user had luck running it on a VME board. These machines are hard to find and unemulated as of writing, though the firmware files exist for the 40p at least and some efforts have been made in QEMU.

Mine features a PowerPC 601 CPU, 192mb of RAM (the max), a Weitek P9100 video card (branded as the IBM S15 IIRC), and a non-IBM 3com NIC. The 3com NIC has issues with the system as during boot if the NIC is connected to the network the system will refuse to boot fully and will either freeze or BSOD (in NT). The NIC is also not supported on AIX as well, and will eventually need to be replaced.

Curiously, not only is the IBM 40p/7020/6015 not listed in the HCL but the NIC it uses is. It’s well known that the Sandalfoot systems were used for early PReP OS development and it makes sense. Unlike the RS/6000 model 250, the 40p features PCI and ISA busses along with the same 601 CPU early PowerPC machines had. 

Installation

To install PowerPC Solaris, you first need to make a boot floppy. This isn’t uncommon with PReP operating systems. PowerPC Windows NT also requires a boot floppy for the ARC loader. The difference here is that there are two boot floppies; one for Motorola machines and one for IBM machines. Even on PowerPC this wasn’t terribly unusual, both the Moto Powerstack and Apple Network Server computers required custom AIX install media as well and Windows NT had specific HALs for each PPC machine.

On the Motorola PowerStack machines you need the same firmware used to install AIX instead of the ARC firmware for NT. On the IBM machines it’s vastly easier, you just need to make the floppy and shove it in. You then press the power switch and you’ll end up dumped to an Open Firmware prompt. As these IBM machines did not have Open Firmware, the bootloader loads Open Firmware from the floppy or hard disk every time you boot the machine. Keep in mind even the system management services are floppy loaded on these machines.

You then run into the first big hurdle to installing the OS, “disk” and “net” are mapped to very specific devices and if the SCSI IDs of these are different it will not boot. If the CD drive is not at ID 3 and the HDD is not at ID 6 the commands will not work. You will need to set an environment variable and tell it to boot from these disks manually for the first install.

Booting the OS is similar to booting it on a Sun, but the installer resembles that of the Intel version. The first thing that happens is you wait for the slow 2 speed CD drive to load the OS as the screen turns Open Firmware white. You will need to set the terminal type, and then then video and mouse input before X will load. The video options are limited to the S3 864/928, the Weitek P9000 and P9100, and Moto’s Cirrus Logic GD5434. Notice how the Power Series 440 (6015)/RS6k 7020 40p is referred to by its codename “Sandalfoot”.

Once you enter this in Solaris will boot load X it does on a Sun or Intel box, and the installer will be exactly the same. This phase is very uneventful as the slow CD drive copies files to the hard disk. I didn’t take a lot of screenshots of this part because you can get the same experience with QEMU or an old SPARCStation. You set the network info, you partition the HDD, you choose what you want, and you sit back as it installs.

Then you’ll be dropped at the Open Firmware bootloader and you’ll enter the right commands to make it boot if “boot disk” doesn’t automatically boot the OS.

The installation is not complete however. The next step is to swap CDs and install the GUI. A default install will drop you at a command line, with the second disk you can install OpenWindows and CDE and get a full working desktop. Login, switch CDs, change to the correct directory, and run the installer.

Once this is done, simply type in reboot and once you login you’ll be at a desktop that looks exactly like a Solaris 2.5.1 install on any other platform with one difference. There is literally zero third party software, and for years there was literally zero way of making software for it. You’re stuck with a stock OS and whatever utilities Solaris 2.5.1 came with. You’ll want to use OpenWindows as well, CDE is vastly slower on the 601 CPU (but not as slow as AIX 4.3 for example). The platform directory also tells you what IBM machines it can run on, and all the RS/6000s are titled PPS. The 6015 is the 40p, the 6040 and 6042 are the ThinkPad models 830 and 850, the 6050/70 are the Personal Computer Power Series variants of the 7248 43p, and the PowerStacks are pretty self-explanatory.

The Compiler Problem (and solutions)

For the longest time Solaris for PowerPC was neglected among those who happened to own a PReP machine for one reason: it lacked a compiler. A compiler is perhaps the most important part of any operating system as it allows one to write code for it. As was the case with UNIX operating systems from the time, the compiler was sold separately. With any UNIX that was widely distributed this wasn’t too much of an issue, as GCC or other third party compilers existed for the platform. Furthermore most compilers for these commercial UNIX operating systems ended up dumped online.

Solaris for PowerPC lacked both of these for ages due to the obscurity and rarity of the port. But in 2018 Tenox dug up the official compiler, yet this remained unnoticed for a while. This led to someone else experimenting with cross compilation on Solaris, and managing to compile PowerPC Solaris software. They then released a port of GCC for Solaris 2.5.1 for PowerPC while posting instructions on how to compile it.

To use GCC for Solaris, you need to unzip the compiler, add it to the path, and then symlink a few files that GCC ends up looking for. This is discussed in the BetaArchive thread about this, but I’ll quote it here.

$ ls -l /opt/ppc-gcc/lib/gcc-lib/powerpcle-sun-solaris2/2.95/
total 13224
-rwxr-xr-x   1 bin      bin      5157747 Feb 16 10:30 cc1
-rwxr-xr-x   1 bin      bin       404074 Feb 16 10:30 collect2
-rwxr-xr-x   1 bin      bin       453525 Feb 16 10:30 cpp
-rw-r--r--   1 bin      bin         1932 Feb 16 10:30 ecrti.o
-rw-r--r--   1 bin      bin         1749 Feb 16 10:30 ecrtn.o
drwxr-xr-x   3 bin      bin         1024 Feb 16 10:29 include
-rw-r--r--   1 bin      bin       673012 Feb 16 10:30 libgcc.a
drwxr-xr-x   2 bin      bin          512 Feb 16 10:30 nof
-rw-r--r--   1 bin      bin         4212 Feb 16 10:30 scrt0.o
-rw-r--r--   1 bin      bin         1360 Feb 16 10:30 scrti.o
-rw-r--r--   1 bin      bin         1104 Feb 16 10:30 scrtn.o
-rw-r--r--   1 bin      bin         7868 Feb 16 10:30 specs
lrwxrwxrwx   1 root     other         24 Feb 22 21:35 values-Xa.o -> /usr/ccs/lib/values-Xa.o
lrwxrwxrwx   1 root     other         24 Feb 22 21:36 values-Xc.o -> /usr/ccs/lib/values-Xc.o
lrwxrwxrwx   1 root     other         24 Feb 22 21:36 values-Xs.o -> /usr/ccs/lib/values-Xs.o
lrwxrwxrwx   1 root     other         24 Feb 22 21:36 values-Xt.o -> /usr/ccs/lib/values-Xt.o
lrwxrwxrwx   1 root     other         26 Feb 22 21:37 values-xpg4.o -> /usr/ccs/lib/values-xpg4.o
$

Once you do this, you can now compile C code at least with GCC. This means that Solaris for the PowerPC platform now is a usable operating system, aside from the fact it has no precompiled software whatsoever. Even Windows NT for PowerPC has more software for it. Software can now be compiled using GCC or the original compiler, and cross compiled with GCC on a non-PPC box. Using the cross compiler lets you compile more basics for compiling PPC Solaris code as well such as make. In this screenshot you can also see me compiling a basic “endian test” code example to demonstrate the little endianness of the PowerPC port.

The only problem is that there’s going to be little interest until someone makes a PReP machine emulator. PReP hardware is very hard to come by on the used market these days and while in the early 2000s it might have been easy to find something like a specific RS6k, but judging by the eBay listings there were a lot more MCA, CHRP, and even later PReP models (like the 43p-140) than there are early PReP machines in circulation. QEMU can emulate the 40p somewhat, but right now its 40p emulation is less like an actual 40p and more like something to please AIX. It definitely has the novelty of being a “little-endian PowerPC Unix” however.

GCC moved to git!

After all that flap about having moved GCC into GIT I thought it would be worth checking out, you know digging for interesting old artifacts.

I found the ‘start’ back over here on github:

Sadly the ‘initial revisions’ only contain a few files, far from the contents of the ’87 archive.

Pitty.

Not that I would envy anyone crazy enough to do such a thing, I was just hoping someone else would have done a better job than I did.

GCC from ’87 on the 68000

Years ago I found the ‘first’ released version of GCC, and had built it for the VAX. And things were… fun.

While digging around on bitsavers for new and interesting things, I saw some newer stuff from MIT, and stumbled into the GNU directory and rediscovered the early GNU software depot.

And I re-built the early GCC to target the 68000 which I’d imagine primarily was for the SUN target.

simple program

Using a simple program I can run it through the pre-processor, and the compiler to get the following assembly:

assembly from ’87 GCC

Then it’s a matter of running it through the cross assembler, uuencoding it, and sending it to the target.

I used the cross assembler from the AtariST cross ‘project’, to get an object file. I fired up MachTen, pasted my object file to the VM, and uudecoded the object.

And yeah, much to my surprise the object file linked fine, and I got my native EXE.

It’s not much of a cross toolkit, and honestly it’s kind of useless… but I thought it was maybe worth a bare paragraph to show the other available target available for the 1987 release of GCC.

Also on the MIT archive is TRIX, the MIT Unix work alike that almost became the GNU Kernel, until Mach stole their hearts, and basically lead them on a wild goosechase.

I haven’t bothered uploading binaries or patches or anything yet, I don’t know if people are interesting in such a fringe thing……