After a long battle with toolchains, head.S, and a serial driver, Mackerel-30 now boots Linux kernel 6.17 (the latest release at the time of writing) and hands control over to an interactive Toybox shell. A minimal system for sure, but a fully functional, standalone, and modern Linux installation on an almost 40 year-old CPU. I'm feeling pretty good about this accomplishment. Here's a rough outline of how I got here.
The first hurdle is setting up a toolchain. Unlike with Mackerel-08 and Mackerel-10, I didn't have the advantage of a complete build system with precompiled toolchain like the one provided by uClinux. Every piece had to be put together manually. I settled on using crosstools-ng to assist in the toolchain setup. Like the Linux kernel itself, crosstools-ng still supports the m68k architecture. It took a lot of trial and error (and many objdumps), but I settled on a toolchain consisting of gcc 15, binutils 2.45, and musl as the C library. The most painful part of this step was figuring out the right combination of crosstools config settings and CFLAGs to get a binary that contained only 68030-supported instructions and no FPU instructions (my FPU is still disabled).
With a functioning toolchain, I could compile the kernel. I started working my way through early kernel boot code, methodically placing putc calls all over the head.S assembly file. I spent what felt like too much time trying to coerce Linux to work with my memory map until I gave up and adjusted the address decoding on the CPLD to align with the Linux m68k expectations, removing the SRAM chip entirely and remapping the 128 MB of DRAM to 0x00000000-0x7FFFFFFF. The MMU was set up to pass these physical addresses to the same virtual addresses. Mackerel-30 had finally reached start_kernel().
Optimistically, the hard part was now over - the kernel was booting and I had output coming through the early console. I had to write a proper serial driver for the XR68C681 DUART, move the timer interrupt duty to the CPLD, and debug a few minor issues, but before too long, Mackerel-30 was making the jump to userspace. This event was anticlimactic as there wasn't one.
There are a million options when it comes to building a userspace and it's where a lot of the fun of building a Linux system happens. With a modern kernel, MMU support, and working console I/O, the possibilities are endless, but it's best to start simple. I chose a barebones root filesystem populated almost exclusively by a single Toybox binary and a few symlinks. Toybox can act as the init system as well as the interactive shell with a handful of useful commands. I used cpio to pack this barebones filesystem into an initramfs and bundled it with the kernel image. Mackerel-30 is now a complete Linux system:
$ hostname
mackerel
$ uname -a
Linux mackerel 6.17.1-multi-00013-g4a905c110481-dirty #5 Thu Oct 16 18:39:30 EDT 2025 m68k Toybox
$ cat /proc/cpuinfo
CPU: 68030
MMU: 68030
FPU: none(soft float)
Clocking: 8.1MHz
BogoMips: 2.04
Calibration: 10240 loops
$ free -h
total used free shared buffers
Mem: 123M 4.1M 119M 736K 0
-/+ buffers/cache: 4.1M 119M
Swap: 0 0 0
$ mount
rootfs on / type rootfs (rw,size=62652k,nr_inodes=15663)
devtmpfs on /dev type devtmpfs (rw,relatime,size=62652k,nr_inodes=15663,mode=755)
proc on /proc type proc (rw,relatime)
sysfs on /sys type sysfs (rw,relatime)
Next up is a lot of cleanup. There were definite corners cut in the bring-up process and now is a good time to revisit some of the dirtier hacks before I forget everything and move on.
On the top of the todo list is an IDE driver. I implemented a crude PIO-based driver on Mackerel-10 and that's working well enough, but it relies on an older driver interface. I think there are more modern examples to explore on Mackerel-30. Either way, permanent storage unlocks a lot of functionality and gives me the option to boot from a real drive instead of a temporary RAM-based filesystem.
I'd also like to finish bringing up the FPU. I have one installed on the board, but I am running into a panic every time I try to use one of the FPU instructions. I didn't spend a ton of time debugging this and I'm not sure if it's my address decoding or my software causing the problems, but it would be cool to move away from emulated floating point code.
I'm having a blast with this project and I love the fact that this ancient processor is running the same kernel as my modern Linux desktop.
Colin Maykish
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
Well, I'm glad you got it working. Sorry to hear about the troubles with memory mapping but if you aren't too burnt buy it, perhaps you can revisit it. I did find someone who worked on a similar project which was able to remap memory as needed: https://www.aslak.net/index.php/2022/01/11/porting-linux-to-the-68030-based-maxi030/
If nothing else, maybe you can contact the author to see if they could point you in the right direction.
Are you sure? yes | no
I've actually been following Aslak's blog for a while. It's always nice to have a known working example for comparison, especially one with a Git repo. His MAXI030 project as well as the KISS-68030 project have both been excellent sources of information.
Originally, I had my DRAM mapped at 0x80000000. Looking back on it now, I think my issue with the board bringup was trying to change the `_start` address in the kernel's linker script. The early kernel code should be position independent until the MMU kicks in and then it can be mapped wherever it needs to be. I could probably go back and remap my DRAM knowing now how it's supposed to work, but there's not a lot of practical difference to my setup having it at 0x0000 versus up higher anyway.
Are you sure? yes | no