Rebuilding Darwin from source: Part 1 Qemu

Back in the old old..

7 years ago!

It’s hard to believe it’s been 7 years ago since I reproduced Ncommander‘s adventure in building the Mach kernel from Darwin 0.1 sources that had been found years ago. At one point we’d managed to build enough of Darwin to do a dump/restore onto a new disk image, and have a mostly built Darwin system save for a hand full of files.

Time goes on by, and memories fade, and I thought it’d be worth going over the adventure, yet again. Just as it was true back then, I thought I’d reproduce the same setup that I’d been using back then. Qemu was a new and exciting thing back then, and

the Disk driver is VERY picky and honestly ancient Qemu is a pretty solid option to emulate NeXTSTEP/OPENSTEP/Rhapsody with some patches to both 0.8 & 0.9 by Michael Engel, which change a nested interrupt and add support for a busmouse, as the PS/2 mouse doesn’t work for some unknown reason. I know many are scared of old Qemu, but the disk support is pretty solid and the CPU recompilation is very fast, so having to rely on MinGW v3 isn’t so terrible.

While I had hid away a lot of these resources on archive.org, I thought it was best to just go back to the oldest post I had where I had painfully documented how to compile Qemu and get it working with NeXTSTEP, back on BSDnexus. I’m so glad I took the time so long ago to not only write it down, and add screenshots, but also tag the version numbers. Software drift, especially free software can be so difficult to pin down, and it’s nice to be able to return to a known good value. I went ahead and placed the recreated toolchain over on archive.org.

Rhapsody is a weird OS, in that NeXT had kind of given up on the OS market after their NeXT RISC Workstation had basically died with the 88k, and even their early abandoned PowerPC 601 aka MC98000/98601 port. Apple had left a few of the changelogs, in the source code. It’s very interesting stuff! I guess to go off on my own tangent NeXT was just too early, the cube with it’s Unix & magnetic optical media and great audio DSP capabilities was just too ahead of the curve. What the cube couldn’t pull off in 1988, the iMac and OS X sure did in 2001.

I also added UDP support to this Qemu so I could use the HecnetNT bridge trick giving me the ability to telnet/ftp into the VM greatly reducing my pain. Back in the day I had used NFS and the network slirp redirection. But I like having direct access so much more!

Rhapsody throws up yet another fun ‘road block’ in that the mouse buttons map backwards for some reason. It’s a trivial fix in the source code, but I made it a runtime option in case I needed or wanted to run NeXTSTEP. And it was a good thing, as I did need to find the NXLock.h file for building one part of Darwin.

When building Darwin, I started with the last x86 version of NeXTSTEP that was availble, and that was Apple ”Rhapsody” / Titan1U x86 Developer Release 2 from WinWorld. My thinking at the time and still is that the closer you can get your build to whatever they were using as ‘current’ the easier this will be.

Rhapsody can support an 8GB disk, so let’s go with that. This always has an issue with people that try much larger, and just fail, so for my sake and yours let’s just go with 8.

qemu-img.exe create -f vmdk rhapsody.vmdk 8G

And to simply start off the installer:

qemu -L pc-bios -m 128 ^
-k en-us ^
-rhapsodymouse ^
-hda rhapsody.vmdk ^
-cdrom rhapsody_dr2_x86.iso ^
-fda rhapsody_dr2_x86_InstallationFloppy.img ^
-boot a

You may be wondering, why only use 128MB of RAM? Well there is a bug in the shipping Rhapsody kernel that prevents booting on machines with more than 192? MB of RAM. Naturally, once we are to the point of building our own kernels this won’t be a problem but for now we are limited.

The bootloader will give us a few seconds to do anything fancy, I just hit -v so I always have the verbose boot.

From here it’s just a few options to go thru the installer

And a disk change is required

CONTROL+ALT+2 will bring up the monitor prompt, where we can change the disk

CONTROL+ALT+1 will return us to the console. Now we have to go through all the SCSI cards, and kind of compatible IDE cards

Further..

Further still…

And how select the Primary/Secondary(DUAL) EIDE/ATAPI Device Controller (v5.01)

We only need the one driver, so we’re good to go!

Continuing onwards will now start the kernel, along with a change to graphical mode. Just like a NeXT!

Now we can confirm again we want to install

As you can see there is our hard disk!

In the future we don’t need to dual boot so, just give it the entire disk.

A few more 1’s and we are finally installing!

Trust me it’s fast on Qemu!

And just like that, we’ve completed the first part of the install.

You can use CONTROL+ALT+2 to toggle back to the monitor and type in

eject fda

to eject the floppy, then it’s CONTROL+ALT+1 to return to the display and have it reboot. Qemu won’t try to boot to the hard disk, and with no disk in the drive, it’ll hang at the BIOS. Now is a good time to close Qemu and backup the hard disk. Mostly because I hate repeating this stuff.

To try to make this a bit easier I’ve made a floppy disk with the NE2000 driver and updated kernel in one place where they can be injected via single user mode. A simple enough config file:

qemu -L pc-bios -m 128 ^
-k en-us ^
-rhapsodymouse ^
-hda rhapsody.vmdk ^
-cdrom rhapsody_dr2_x86.iso ^
-fda nic.flp ^
-boot c

Type in -s for SINGLE USER MODE. This is where a lot of Unix problems got solved in the old days

It’s a little tricky as this does involve typing. As instructed we need to check the hard disk prior to mounting it read/write

run the commands:

fsck -y /dev/rhd0a
mount -w /

Now we can mount the floppy disk

mkdir /mnt
mount /dev/fd0a /mnt
ls /mnt

I’ve included both the kernel & NE2000 driver in one file, and JUST the NE2000 driver in the other. For my sake I use the first one, update.tar.gz as I wanted to use the newer kernel ASAP. tar -zxvf didn’t want to run, so I did a rather awkward version to achieve the same thing.

cat /mnt/update.tar.gz | gzip -dc | tar -xvf -

With the files in place, you can now shut down the system with a simple

shutdown -h now

Once more again, I’d shut down the emulator, and backup the hard disk. If anything goes wrong you can restore your backups at any phase, at least saving some time!

Next is the graphical install. In this case I use the hecnet bridge to give full access, you can setup with the slirp driver with a simple “-net user” but it doesn’t matter at the moment Since I opted for the newer kernel, I can take advantage of the 512MB RAM.

qemu -L pc-bios -m 512 ^
-k en-us ^
-rhapsodymouse ^
-hda rhapsody.vmdk ^
-cdrom rhapsody_dr2_x86.iso ^
-fda rhapsody_dr2_x86_InstallationFloppy.img ^
-net nic,model=ne2k_pci,vlan=5 ^
-net socket,udp=0.0.0.0:5001,remote=127.0.0.1:5000 ^
-boot c ^

Booting Rhapsody

Now we have to setup the hardware. It should be somewhat straight forward, first we start with the monitor. The mouse should be working although I find that I have to move slowly. Sorry it tracks weird on real hardware too.

The Cirrus Logic GD5446 should be detected automatically, I just go with the default 1MB

Next under the mice, select the PS/2 mouse and remove it

This leaves us with the Bus Mouse driver.

Under the network tab, the NE2000 should be automatically detected.

On the last tab, I make a habit of removing the Parallel port freeing IRQ 7, in case I wanted it for something else.

Back to the summary, we now have Cirrus Logic video, NE2k networking, with no SCSI, no Audio.

With the config saved, now we can just install as is. I un-installed Japanese, but it doesn’t matter. You absolutely need the Development Tools, so may as well go with eveything.

The installation only takes a few minutes and we are ready to reboot

The kernel will now shut down.

Once more again this is a great time to make another backup of the hard disk. At this point this is a great backup to save, as we’ve installed the OS, and selected drivers, in the next reboot we’ll be personalizing the operating system.

We can re-run the last config once the disk has been saved. We’ll be greeted with a message that the Server isn’t responding. Answer YES to continue without networking.

From here we are in the Setup Assistant, taking a nod from MacOS 8

I use USA keyboards. The best keyboards! I touch type so I don’t have to deal with weird layouts.

Specify for a LAN connection

There is no DHCP support so specify a manual IP address.

The default stuff is just wrong.

On my LAN this is good enough. DONT add a router. It’ll just confuse it.

We don’t have or want NetInfo. This would be the server to give out IP addresses, and authentication. We don’t need it!

Leave the DNS servers blank

You can setup any location, it doesn’t matter.

Likewise, with NTP, turn it off.

We will then get the option to set the date/time manually. The default time is far too old and it’ll break stuff.

Next up is user accounts.

I always make local accounts.

Come up with some creative name

and a password

I don’t have it doing any automatic login. You can if you want, it’s all up to you, this one doesn’t matter.

Next is an Administrator password

And now we can apply our changes.

It takes seconds!

And now we’ere done. You may want yet another backup as this is tedious!

With the final configured backup in hand, now we can boot back one more time, and now we’re in SVGA mode!

Rhapsody DR2 Login Screen

Logging in as root will give me the desktop

Desktop

And there we are, all installed.

For anyone brave enough to have read all of this, but wants the quick and easy version, it’s up on archive.org!

In part two I’ll pick up with the source CD-ROM I’ve prepared, so we can start compiling Darwin!

Missing link for Basilisk I found

Actually I held onto this, as I wanted to do something crazy for that Marchintosh thing but life got in the way it fell by the wayside, and well now it’s September, and I already have a Qemu instance running A/UX so my ‘at best’ hope of Basilisk II with MMU emulation is all but moot.

Captain, oh Captain!

While it may look like 2 very old emulators, which they are, the interesting thing here is that this old version of Basilisk that only has Macintosh Classic emulation is using the 68000 emulation core from UAE 0.6.8. It took a lot of downloading stuff, a lot of other nonsense, but I eventually found it, and was able to diff around to find the changes made were rather inconsequential, there by letting me rebuild UAE back on top of Basilisk.

My plan had been to either use far newer UAE cpu core, say from Previous as it has working MMU support, or Musashi.

I was building hard coded for TDM GCC 5.1.0 on MinGW. It doesn’t matter anymore but I threw it up on github since that is where all the cool kids are.

https://github.com/neozeed/basilisk-uae-merge

It’s absolutely pointless I guess, but maybe someone will find it interesting.

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

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.

MinGW and missing DLL’s

UGH

Stuff like this drives me crazy.  Once upon a time everything was statically linked, there were no DLL’s, and all exe’s had a lot of the same code in them, and people realized that the majority of a hard disk could literally contain the same thing over and over.  Not to mention that if you were to fix some bug in say, LIBC you would have to re-compile everything.  So we entered the brave new world of dynamic linking where we now live in the proverbial DLL hell, that although we did save space, we have things where slight variations in the same DLL can break things in unforeseen ways.  People have tried various things such as weak linking, Side by side assemblies, Frameworks, and all kinds of things to try to keep things together.

Honestly it’s just easier to go back, and statically link things, and just re-build as needed.

common culprits of MinGW based stuff always include:

  • libwinpthread-1.dll
  • libgcc_s_dw2-1.dll
  • libstdc++-6.dll

ugh.

The hard one is the pthread library.  If you try to link it statically it’ll try to link everything else statically and not every DLL can link statically (SDL* keep reading).  But GCC / Binutils does have the option to turn various features on and off through the link string

-static-libstdc++ -static-libgcc -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic

As you can see, everything after “-Wl,-Bstatic” will be linked statically, while everything after “-Wl,-Bdynamic” will go back to being dynamically linked.

Ok, that is great but what about SDL, you may ask.  Well sure it’s a DLL, but even DLL’s come from somewhere.  Download the source, build it yourself and you can directly link the objects that make up the DLL.  In version 1.2.15 they live in the .libs directory.

SDL-1.2.15\build\.libs\*.o

And on Windows, if you get weird errors like:

SDL_dx5events.o: In function `DX5_DInputInit’:
SDL-1.2.15/./src/video/windx5/SDL_dx5events.c:183: undefined reference to `IID_IDirectInputDevice2A’

Just add the -ldxguid library and you can link this too.  I’m sure once upon a time people may not have had DirectX 5 or higher, but this isn’t 1997.

And please at least test your programs with no path, so that way you are aware of what is needed for re-distribution.

set path=.
D:\dosbox-code-0-4068\dosbox\trunk\src>dosbox.exe

DOSBox SVN

It gets so old when people never test.  And people freak out trying to download DLL’s from weird sites, and you know that never ends well.

Oh yeah, and a static version of DOSBox is 4MB.

4,033,550 dosbox.exe

I know that was massive a long long time ago, but today?

Porting Catacomb3D to MS-DOS (DJGPP v1/GO32).

Catacomb 3-D for GO32

No really, it’s Catacomb 3-D: The Descent.  First ported to 32-bit SDL by NotStiller.  Me being the person I am, I fixed a slight bug regarding binary files on Windows, and MS-DOS, then cleaned up some of the C++ syntax (yuck!) making it far more C89 friendly.  And of course, hot off the heels of DooM for GO32 DPMI, I was able to get it to build and run using GCC 1.39 and GO32.

I know most people really won’t care, but I found it kind of interesting.  I should try to see if it’ll run on actual hardware, just as a comparison of tightly optimized Borland C++ / Assembly vs 100% pure C on DJGPP.  The best tech of 1991 for sure!

At current I just put the source up, you can git it here.

26th anniversary of Linux!

As the joke goes:

Happy 25th birthday, Linux! Here’s your f-ing cake, go ahead and compile it yourself.

So it’s always a fun time for me to push my old project Ancient Linux on Windows.  And what makes this so special?  Well it’s a cross compiler for the ancient Linux kernels, along with source to the kernels so you can easily edit, compile and run early Linux from Windows!

As always the kernels I have built and done super basic testing on are:

  • linux-0.10
  • linux-0.11
  • linux-0.12
  • linux-0.95c+
  • linux-0.96c
  • linux-0.97.6
  • linux-0.98.6

All of these are a.out kernels, like things were back in the old days.  You can edit stuff in notepad if you so wish, or any other editor.  A MSYS environment is included, so you can just type in ‘make’ and a kernel can be built, and it also can be tested in the included Qemu.  I’ve updated a few things, first with better environment variables, and only tested on Windows 10.  Although building a standalone linux EXE still requires a bit of work, it isn’t my goal here as this whole thing is instead geared around building kernels from source.  I included bison in this build, so more of GCC is generated on the host.  Not that I think it matters too much, although it ended up being an issue doing DooM on GCC 1.39.

So for people who want to relive the good old bad days of Linux, and want to do so from the comfort of Windows, this is your chance!


Download Ancient Linux on Windows
Download Ancient Linux on Windows

WSAPoll & MinGW

For some reason if you try to use WSAPoll, you’ll get this fine error on linking:

poll.c:(.text+0x26): undefined reference to `WSAPoll’

Yeah.

Turns out that it’s basically missing from the includes.  Thanks to this hint, just simply add this into your source/header after pulling in winsock2.h and it’ll link.

typedef struct pollfd {
SOCKET fd;
SHORT events;
SHORT revents;
} WSAPOLLFD, *PWSAPOLLFD, FAR *LPWSAPOLLFD;
WINSOCK_API_LINKAGE int WSAAPI WSAPoll(LPWSAPOLLFD fdArray, ULONG fds, INT timeout);

And now you can happily compile and link.

Just for you, lucky Spanish user, GCC 3.0.4 for Windows NT (MinGW)

From Spain!

I cannot understand why you want this, or why I’m even going to do it.  At this point in GCC history the winnt-3.5 target had been dumped in favour of going all in with Cygwin.  So yeah, this does not either clearly configure, or compile.  But a little bit of mashing files, and I have it at least compiling some assembly that can be translated into an object file that a later version of MinGW can actually compile.

All I’ve built is the gcc driver, the cpp pre-processor, and the cc1 aka C backend.

D:\proj\gcc-3.0.4\gcc>xgcc -c -v hi.c
Using builtin specs.
Configured with:
Thread model: single
gcc version 3.0.4
cc1 -lang-c -v -iprefix ../lib/gcc-lib/i386-winnt35/3.0.4/ -D__GNUC__=3 -D__GNUC_MINOR__=0 -D__GNUC_PATCHLEVEL__=4 -Dunix -DWIN32 -D_WIN32 -DWINNT -D_M_IX86=300 -D_X86_=1 -D__STDC__=0 -DALMOST_STDC -D_MSC_VER=800 -D__stdcall=__attribute__((__stdcall__)) -D__cdecl=__attribute__((__cdecl__)) -D_cdecl=__attribute__((__cdecl__)) -D__unix__ -D__WIN32__ -D_WIN32 -D__WINNT__ -D_M_IX86=300 -D_X86_=1 -D__STDC__=0 -D__ALMOST_STDC__ -D_MSC_VER=800 -D__stdcall=__attribute__((__stdcall__)) -D__cdecl=__attribute__((__cdecl__)) -D__cdecl__=__attribute__((__cdecl__)) -D__unix -D__WIN32 -D__WINNT -D__ALMOST_STDC -D__cdecl=__attribute__((__cdecl__)) -Asystem=unix -Asystem=winnt -D__NO_INLINE__ -D__STDC_HOSTED__=1 -Acpu=i386 -Amachine=i386 -Di386 -D__i386 -D__i386__ -D__tune_i386__ hi.c -quiet -dumpbase hi.c -version -o C:\Users\jason\AppData\Local\Temp\ccpflisr.s
GNU CPP version 3.0.4 (cpplib) (80386, BSD syntax)
GNU C version 3.0.4 (i386-winnt35)
compiled by GNU C version 5.1.0.
ignoring nonexistent directory "../lib/gcc-lib/i386-winnt35/3.0.4/include"
ignoring nonexistent directory "../lib/gcc-lib/i386-winnt35/3.0.4/../../../../i386-winnt35/include"
ignoring nonexistent directory "D:/pcem/building/MinGW/msys/1.0/local/include"
ignoring nonexistent directory "NONE/include"
ignoring nonexistent directory "D:/pcem/building/MinGW/msys/1.0/local/lib/gcc-lib/i386-winnt35/3.0.4/include"
ignoring nonexistent directory "D:/pcem/building/MinGW/msys/1.0/local/lib/gcc-lib/i386-winnt35/3.0.4/../../../../i386-winnt35/include"
ignoring nonexistent directory "/usr/include"
#include "..." search starts here:
End of search list.
: warning: "__STDC__" redefined
: warning: this is the location of the previous definition
: warning: "__STDC__" redefined
: warning: this is the location of the previous definition
hi.c: In function `main':
hi.c:3: warning: return type of `main' is not `int'
as --traditional-format -o hi.o C:\Users\jason\AppData\Local\Temp\ccpflisr.s

D:\proj\gcc-3.0.4\gcc>gcc hi.o -o hi

D:\proj\gcc-3.0.4\gcc>hi
Hello from GCC 3.0.4

So there you go, mysterious internet user!  Download my source dump with binaries in the tree because I’m lazy.

gcc-3.0.4-MinGW.7z

N64 cross GCC / Binutils for Win32

Building GCC & Binutils for the Nintendo 64

I had a request to help get a GCC+Binutils running as native win32 exe’s something comperable to the ancient ‘ultra’ N64 toolchain done by Kyoto Microcomputer (resume pdf).  One interesting thing about their toolchain is that they used a common object format for MS-DOS, DOS/V and MS-DOS on the PC-98 format, along with Win32.  However the Win32 runtime doesn’t like Win64 environments.  On Win64 the exew32 driver just complains:

Can’t allocate memory (Error Code=487)

However the stubs in all the exe’s reference exegcc98 exegccv DOS extender’s along with a exegcc.  However googling around yields nothing.

Running on a x86 version of Windows, however the tools run and report gcc 2.7.2 release 1.2 and the binutils version is simply 2.6 with BFD version 2.6.  So going with this, and the request to keep it 1997 vintage I went ahead with Gcc 2.7.2.3 and Binutils 2.8.1 as they are the end of the line in both trains of code.

To configure is really a snap, as both support the Windows NT platform directly

sh configure --host=i386-winnt3.5 --target=mips-elf

I guess I should add that I build with TDM GCC 5.1, and I use the incredibly ancient MSYS-1.0.11-rc-1.  But it’s enough to bootstrap and build with!  Since my GCC is much newer, I did have to finagle some things.  Here is a quick list of my notes on what I had changed, and some justification.

Binutils 2.8.1 notes:

include/fopen-same.h

make sure this uses MS-DOS rb wb type constraints!

libiberty/xmalloc.c

There is no sbrk on my MinGW32 … so comment out all the sbrk stuff.

bfd/targmatch.sed

My sed LOVES UNIX style text files, so this one shouldn’t be in MS-DOS CRLF format.

binutils/objcopy.c

mkdir only accepts the path on Win32.  Also there is now chown.

Gcc 2.7.2.3 notes:

c-gperf.h

‘__inline’ for is_reserved_word needs to be commented out.

config/mips/mips.h

Set like the following for both ASM_FINAL_SPEC to prevent the t-mips from trying to be run.

#define ASM_FINAL_SPEC “\
+%{pipe:-}”

config/winnt/xm-winnt.h

OBJECT_SUFFIX “.o”

Just because we are on Windows NT, doesn’t mean we want an .obj object suffix.

gcc.c

__spawnv : __spawnvp work better as _spawnv : _spawnvp

obstack.h

*((void **)__o->next_free)++ = ((void *)datum);

confuses newer compilers, with this error message:

obstack.h:341:32: error: lvalue required as increment operand

replace it with with:

*(__o->next_free)++ = ((void *)datum);

So at the end I have a cross compiler, and I can generate object files, and link files that the final tool MILD can then use and produce N64 ROM images.  It’s not a 100% solution, as I don’t see any mention of MILD being GNU, however the compiler and binutils is running on Windows 10 x64!

GCC cross compiling to the N64 target

GCC cross compiling to the N64 target

I built a few demos and tested with the 1964 emulator.

And there you have it.  For anyone who cares, you can download the toolchain + source here: winnt3.5_i386-mips_elf-gcc-2.7.2.3_binutils-2.8.1.7z