68kMLA Classic Interface

This is a version of the 68kMLA forums for viewing on your favorite old mac. Visitors on modern platforms may prefer the main site.

Click here to select a new forum.
Tux Box - Linux layer for Mac OS 9
Posted by: beta_train on 2026-09-03 11:51:02
AI disclosure: Claude Code was used as a member of the development team for this project.

TuxBoxPBG4.png

This project spun out of some work I was doing with Claude on the System 7.1 leaked source code. I originally was trying to synthesize the missing pieces of source code, get it booting, and then port it over to PPC. I eventually got it booting in an emulator, but halfway through I was wondering how hard it would be to port over busybox and have like a "MachTen" style environment, but for Linux!

Turns out, not that hard (with a healthy token budget and an uncomplaining "dev"). Tux Box is a Mac OS 9 application that loads an ordinary statically-linked PowerPC Linux ELF, lets the CPU run its instructions directly, and services its system calls out of the Toolbox. There's no emulation involved, BusyBox believes it's on Linux, Mac OS believes it's running one well-behaved app, and both are right. The gate is the interesting part: on a PowerPC Mac `sc` belongs to the NanoKernel and there's no documented exception kind for what it raises, so guests are built with musl's syscall stub patched to trap with `tw` instead. That arrives as `kTrapException`, which an ordinary application can catch via InstallExceptionHandler. Guests are static PIE and get relocated into whatever block NewPtr hands back, since an app can't map memory where it pleases.

The screenshots are BusyBox ash (with a prompt, history, tab completion, cd and working pipelines), MicroPython 1.25 in 330 KB, and a little fetch script. The app's own folder is the guest's / over HFS, and /Volumes opens onto the real disks, so grep and find reach actual Mac files. Networking goes through Open Transport with TCP, UDP and DNS, so wget works, plus HTTPS via mbedTLS linked into the guest.

I don't know if anyone else will find this useful or not, and I haven't bisected the app & code out of my messy working directory for original System 7.1 playground. But I hope to have this on GitHub later this week/weekend.

EDIT: Spelling
Posted by: Nixontheknight on 2026-09-04 13:15:06
this would be interesting to try on my iMac G3 DV and my iMac G4. Does it support Classic or do I have to boot into OS 9?
Posted by: beta_train on 2026-09-05 08:42:48
this would be interesting to try on my iMac G3 DV and my iMac G4. Does it support Classic or do I have to boot into OS 9?
I haven't tried Classic yet, but from my understanding Classic doesn't run the NanoKernel. Mach owns the exceptions and Classic virtualizes what is underneath. That's the layer that makes this work. For reference, it works with qemu and DingusPPC but fails with Sheepshaver. I'd be very interested to see the `TUXBOX.TXT` log for either a successful run or a failure under Classic
Posted by: Nixontheknight on 2026-09-07 16:28:08
So where can I download this?
Posted by: lauland1 on 2026-09-08 13:35:08
Classic has a "pseudo-kernel" which gets exceptions first in the xnu kernel. It can pass things down to anything at the MacOS X level it may want to. I don't know how much of the NanoKernel's work it takes over or replaces, but the copy of the NanoKernel in the Classic Mac OS ROM probably includes hooks. I can see that the pseudo-kernel will handle some threads, possibly instead of of letting the NanoKernel do so. (Looking in the xnu source code for 10.4 or so).


If you're lucky, the trap will go to the pseudo kernel, be reflected back up to MacOS 9, as it won't handle or swallow it, and it will "just work". If you aren't, the pseudo kernel will flag the trap you are trying to use as an error and handle it as a machine exception and probably crash Classic.

Let us know when you release the code, I'd be happy to build it and try it in Classic. (And maybe help get it working if it doesn't "just work").
Posted by: ryancnelson on 2026-09-13 14:22:51
wow, we're apparently on the same wavelength. about the same time you started having ai dig into the linux kernel , inspired by MachTen, (and macMinix) i was doing the same thing, but for netbsd. Codex took me down a "let's implement a libc" route and started implementing syscalls one at a time, with rigorous tests. build targets are currently Retro68 for macos7 , solaris 9 on sparc sun4m , and the host on arm64 linux.

work so far: https://github.com/ryancnelson/bsdinacan
Posted by: beta_train on 2026-09-14 06:18:27
Sorry for the late reply, I ended up getting a nasty cold that took me out last week and then I didn't really want to tie my GitHub to this old childhood account (I joined 68kmla 18 years ago now, holy smokes), so I made a new worktree.ca account to host the code

The release & binaries: https://worktree.ca/beta_train/TuxBox/releases
Code repository: https://worktree.ca/beta_train/TuxBox

@ryancnelson I'll check out your bsdinacan after work today, it looks very interesting!
Posted by: beta_train on 2026-09-14 08:12:55
@ryancnelson Curiosity got me unable to focus on work and I asked Claude to do a comparison of the two and make a sharable page: https://claude.ai/code/artifact/6ff9f164-d519-41b7-b502-81593f356650

I still plan on doing a full deep dive myself this evening though ๐Ÿ™‚
Posted by: lauland1 on 2026-09-14 08:49:18
wow, we're apparently on the same wavelength. about the same time you started having ai dig into the linux kernel , inspired by MachTen, (and macMinix) i was doing the same thing, but for netbsd. Codex took me down a "let's implement a libc" route and started implementing syscalls one at a time, with rigorous tests. build targets are currently Retro68 for macos7 , solaris 9 on sparc sun4m , and the host on arm64 linux.

work so far: https://github.com/ryancnelson/bsdinacan
I've been looking at the source code for xnu and every other kernel I could get my hand on. MacMach (very rare, a historical anomaly and not well documented or known) was heavily license encumbered (so died on the vine), but its code shows an interesting way to run System 7 on top of another kernel...not unlike A/UX, but very different in implementation.

I've looked at MachTen also, and haven't determined if it does its system calls like Tux Box or not (they may just be shared libs in the same address space). A/UX does, with traps, so Mac toolbox apps can call down to the kernel. In theory, because of the "pseudo kernel", tasks in Classic could do something similar, especially preemptive threads. As I said before, if they can, then the Tux Box traps might "just work" in Classic.

I took a deep dive into the kernel change Apple did from "Rhapsody" to MacOS X DP1, which was the first "xnu" as we know it. I compared the sources of the Rhapsody kernel, xnu and MkLinux's Mach.

I did this because I was into MkLinux when it came out, so, obviously, when MacOS X did it rocked my world.

----

Because I had tracked the developer "previews" of MacOS X as it came out back in the day, I knew visually it looked like the early boot time code from mklinux had been reused for xnu. (white text on black background "COLOUR CONSLE", etc). I suspected that is what apple did.

Reading the code proved that was the case to a certain extent. They repurposed the Mach from MkLinux, but took the concepts (and a lot of the code it turns out ) from the Rhapsody kernel, so the huge BSD layer was put back in. All IO was stripped from the BSD and Mach kenerel level, and "iokit" as we know it was born, running at a lower level, part of Mach, so far far more efficient than the way MkLinux worked.

Large parts of XNU were taken wholesale from MkLinux, the other parts from Rhapsody, but the io subsytem and driver level were compleytely new. That (and falling back to the in-kernel BSD) was how Apple solved "the Mach problem" that hung up every other Mach implementation up to that point.

----

This makes the approach you're taking with Tux Box very interesting to me. It is a yet another, brand new, solution to the "unix-on-or-under-macos" that Apple and others have tried (and to a large extent failed). This is a very clever good idea. A bit like A/UX, but "upside down", as you are still relying on the MacOS 9 kernel for the plumbing. It's closer to the MachTen idea, but since it is linux, far more compelling.
Posted by: ryancnelson on 2026-09-15 19:26:44
i just gotta say, this is fun as HELL. glad i stumbled upon this thread.
Posted by: lauland1 on 2026-09-16 07:05:43
I took a look at the code. I think multiprocessing services to leverage multiple real tasks and threads may deserve some looking into. They can't call the toolbox, and may be limited on some file and memory api's, but "headless" they should work nicely. (As long as they don't cause things that would write to the screen).

It would take a major amount of architecting, but prebuilt debian binaries would be extremely nice (obviously). The main problem is the address space they expect/assume. Instead you are using PIC and that sort of thing, and having to build the linux binaries to run on this that way. It's limited, for sure, but amazing for making use of such a limited app heap based memory subsystem in such a resourceful (ha) way. (Very similar to how MachTen does).

That was a very clever way to get OT working!

----

One interesting, although not very useful as few people use it, thing that would be possible would be to support prebuilt MachTen binaries with a shim. They are PEF files, so would need a loader, I think, and would just need system calls translated for the most part.

I don't think it would be possible to run a re-built qemu on this, as it probably tortures memory subsystems, but, if you could...

----

I'm itching to build X11 for this. It might work, but is likely to have some networking issues. For the server, you could just run a standard MacOS X11.

----

One could imagine "add os" such as cpu emulation subsystems to open the door very wide to supporting some very foreign binaries, couldn't one?

Anything that assumed a unix style memory map, ala loading around page zero, would be out without the same sort of architeching that would get debian binaries to run. But...if you are emulating a cpu, you might as well emulate the memory map.

----

Another thing that could be done, but would be mostly useless, would be to support an api compatible with A/UX. That way, we'd have something that almost looked like the cryptozoological A/UX 4, even if it woulnd't really be (its binaries, if any even exist, would need a unix style memory map).
Posted by: beta_train on 2026-09-17 05:49:47
Quick update, and thanks to @lauland1 for the push on Debian binaries! That comment sent this in a direction I'd written off. The original research had ruled out stock binaries because old PowerPC Linux executables insist on loading at $10000000, which an application can't get from the NanoKernel. But Debian has built position-independent executables by default for years now, and Debian Ports still carries a live powerpc port so that wall had quietly disappeared. Two real obstacles were left. Stock binaries make syscalls with sc, which belongs to the NanoKernel (I tested it, and from an app it neither faults nor reaches the exception handler, it just returns โˆ’4). And glibc reads the CPU version register, which is privileged. Since Tux Box loads the image itself, it now rewrites every sc to tw on the way in (same instruction width), and emulates the version-register read. With that plus a real mmap, Debian's own ld.so and glibc 2.43 run unmodified. A small script fetches packages with all their libraries from Debian Ports, and I've got a bunch staged: bash, gawk, sed, tar, gzip, perl, lua, jq, make, find, diff, and fastfetch, which cheerfully reports a 768 MB machine on an HFS disk.

The other big change is that processes are actually concurrent now thanks to your cannedBSD @ryancnelson ! fork returns to the parent and blocked processes get switched out, so yes | head and four-stage pipelines work. It's cooperative scheduling on top of snapshotting each process's memory, since an app still can't have separate address spaces. Running stock GNU tools turned out to be a much harsher test than BusyBox ever was, and flushed out bugs BusyBox never touched like a pipe claiming to be an empty file, for one. Honest caveats: all of this is verified under QEMU only, I haven't had the time to go down and test this on real hardware yet. The last thing confirmed on my TiBook was the original release, and memory-copying on context switches is exactly what I expect to behave differently on real hardware. Threads, signal handlers, and interactive network tools like nc aren't there yet. @lauland1 , your Multiprocessing Services idea is still on my list. The open question is whether the trap gate even fires inside an MP task.


gnutar.png
fastfetch.png
Posted by: beta_train on 2026-09-17 06:07:23
I forgot to add that the updated concurrent guests & Debian binary work has been merged into master branch, and a new release is available at: https://worktree.ca/beta_train/TuxBox/releases
Posted by: lauland1 on 2026-09-17 08:24:47
That is awesome news, and very promising! (Thank you Debian gods, for still doing PIC!)

I'd missed that you were copying process memory...a solution equally elegant and hacky to the serious problem of making a single heap non-protected address space look unixy. Very clever.

----

It think multiprocessing (preemptive) tasks should be able to do traps, but have never tried it. Since they can't call the toolbox, they're hard to use (for anything) except for background math, etc.

Cooperative multitasking is what is it, but, even using just the thread manager, has surprised me in its usefulness. I added threads to SDL2 to get audio working, expecting them to get stuck stalling waiting on each other (somewhere mysterious and hard to find...), but, somehow it "just worked". They likely will still stall, without care in their usage, but turned out shockingly better than expected. (It's humorous to watch them round robin, in order, compared to real preemptive threads on other os's).

Since linux task threads (cooperative) would have no idea to call GetNextEvent or similarly give each other cpu time, it'd be difficult to use them, theoretically, in tux box. A hack to give threads time in the system call dispatcher would be something that might work. Otherwise, you could (to a point) rely on the console's event loop, so threads wouldn't starve, assuming there was sufficient stdio going to it. (That is not likely to turn out in practice, given that most threads are used for background things).

----

Don't feel bad about qemu use, proof of concepts are needed before real code can fly. And emulators are terribly useful when code is in active ongoing development.
Posted by: adespoton on 2026-09-17 08:57:46
@beta_train, have you tried using https://www.emaculation.com/forum/viewtopic.php?p=82484 yet? AppleBridge seems like a really good fit for your development workflow; you can have Claude work on the host, but instrument an emulated guest OR spin up actual hardware and have it interact with that from a modern system. It means you can keep your context and dev environment intact on a modern system while building and testing on legacy hardware.
Posted by: beta_train on 2026-09-17 11:48:20
@beta_train, have you tried using https://www.emaculation.com/forum/viewtopic.php?p=82484 yet? AppleBridge seems like a really good fit for your development workflow; you can have Claude work on the host, but instrument an emulated guest OR spin up actual hardware and have it interact with that from a modern system. It means you can keep your context and dev environment intact on a modern system while building and testing on legacy hardware.
I haven't tried it yet but this is very interesting! Thank you for linking it, it sounds like it would make debugging way less expensive for me right now haha. Claude likes to write a lot of tests that print out to a file, and then read those test results in. A very token hungry workflow, even with some "token saving" skills applied. Claude built a Mac OS 9 test environment itself using a qemu disk and the one of the restore isos that are floating around. But if I could have Claude use my TiBook directly for testing that would be *chef's kiss*

I've been burning some tokens today to test out the emulation route, that is regular Debian binaries compiled for other architectures (68k and i386 using Musashi and tiny386) interpreted in an emulator and run on Tux Box directly. 68k was almost free due to endianness but i386 is coming along nicely too. Might have something to show by tomorrow hopefully.

EDIT: Spelling
Posted by: beta_train on 2026-09-18 16:04:00
xeyes.png
This is getting quite fun! i386 and m68k binary emulation has now been released, and the above screenshot is some work I am doing getting X11 working
Posted by: nil on 2026-09-18 16:22:41
just curious, can you debug mac apps from this with gdb or similar?
Posted by: beta_train on 2026-09-18 16:27:49
just curious, can you debug mac apps from this with gdb or similar?
Not really, no. A couple of reasons:

- No ptrace. gdb works on Linux by attaching to a process with ptrace, and Tux Box doesn't implement it. It also has no real signals beyond Command-period, and gdb relies on those too. You could probably get Debian's gdb to start, but it couldn't attach to or step anything

- Mac apps aren't Linux processes. Tux Box runs Linux binaries inside one Mac application, answering their system calls from the Toolbox. Other Mac apps are CFM/PEF code running under Mac OS 9's own Process Manager. The Linux side can't see them as processes at all, and gdb doesn't understand PEF.

Under emulation, qemu's own gdb stub (-s) can debug the whole emulated Mac at the machine level, which is how you'd poke at Mac OS itself.
Posted by: lauland1 on 2026-09-18 16:38:29
wh00t!
1