Kernel Architecture¶
Amix runs a monolithic AT&T System V Release 4 (SVR4) kernel ✅. Stock Amix has no loadable modules (one third-party exception, below): every driver is statically linked into the kernel, and adding hardware means relinking the kernel image and rebooting ✅. The kernel ships not as full source but as a set of compiled object libraries under /usr/sys, which you relink into the running kernel (/unix) ✅. The one source file you always edit is kernel.c (the device switch and interrupt tables) ✅.
This page covers the kernel's shape: how it is built and relinked, the switch-table model at a high level, the 68030 MMU/HAT memory layer, the SVR4 networking stack (STREAMS/TLI/sockets), and the system-management surface (sysadm, init/inittab/run levels, virtual consoles). For the full device-driver programming model — cdevsw/bdevsw field layouts, entry-point naming, the worked par.c example — see the device-driver model. For the exact relink-and-install commands, see building and installing the kernel.
Monolithic, statically linked¶
Everything that talks to hardware lives in one kernel binary ✅:
- No dynamically loadable kernel modules. SVR4 elsewhere grew
modload-style facilities, but on stock Amix drivers are compiled in. To gain (or remove) a driver you editkernel.c, relink, and reboot ✅. - Drivers are statically linked. Each driver contributes object code (its
.o, often with source) that gets linked into the kernel image ✅. - Keep the old
/unix. Because a bad driver can make the kernel unbootable, the standard procedure is to keep the previous/unix(or a known-good boot partition) as a fallback before installing a new one ✅.
This is the same picture the Ditto driver paper describes for 1990, and the modern community driver repos confirm it still holds for 2.1 ✅.
Loadable modules: none in stock Amix¶
Stock Amix 2.1 and every kernel the 1.0 release ships are monolithic: nothing can be loaded into a running kernel, and every page on this site that adds a driver assumes that model ✅.
Two loadable-module efforts exist outside the stock system:
- The ashnazag project (kdedon; one SVR4 kernel for 68k Mac, Atari and Amiga) built a
loadable-module core (DLM) into its own kernels 🟡. Its earlier commits are GPL-2.0; from
2026-10-14 the DLM core is MIT-licensed ✅ (
amigaux/amixkernel/dlm/core/upstream.pin). - The amigaux 1.1 release is building loadable modules for Amix itself, on both CPU lines, with its own boot loader and a patch queue on that MIT core. It runs in emulation and on real 68060 hardware but is not released (2026-10-29) ✅. See loadable kernel modules.
Until 1.1 ships, the static model on this page and on the driver pages is the one that applies.
The kernel as object libraries in /usr/sys¶
Amix does not ship a complete kernel source tree. Instead ✅:
- The kernel is delivered as pre-compiled object libraries in
/usr/sys. Some.ofiles arrive with source; others are object-only ✅. - You relink these objects (plus any driver objects you add) to produce a new kernel image, then install it as
/unix✅. - The configuration file
kernel.cis provided in source — it is the table that wires drivers into the kernel (see below) ✅.
The build directory layout and makefiles live under /usr/sys (e.g. amiga/driver/, amiga/console/, master.d/). The mechanical recipe — make in /usr/sys, copy the image to /stand, make bootpart, reboot — is documented on the kernel-build page, so it is not repeated here.
Kernel image name: rdbunix vs relocunix¶
The relinked kernel image has been called by two names over the system's life 🟡:
| Era | Image name | Source |
|---|---|---|
| 1990 (Ditto paper) | rdbunix |
Ditto paper ✅ |
| 2.1 / modern repos | relocunix |
community repos ✅ |
Treat this as a historical rename of the same artifact; verify which name your version uses before scripting around it 🟡. On a 2.1 system the modern repos build relocunix, copy it to /stand, then run make bootpart KERNEL=relocunix to write the boot partition ✅.
kernel.c and the switch tables (high level)¶
The kernel is table-driven. kernel.c (under master.d/) holds the tables that map hardware and system events to driver code ✅:
cdevsw[]— the character-device switch, indexed by major number. Each slot is astruct cdevswof entry-point function pointers (open,close,read,write,ioctl, …) ✅.bdevsw[]— the block-device switch, also indexed by major number; its core entry point isstrategy()✅.int2_tbl[]— level-2 autovector interrupt handlers (e.g.parintr,a2090intr,a2091intr); a level-6 table exists too ✅.init_tbl[](also seen asio_init[]) — one-shot boot-time init functions (e.g.parinit,coinit) ✅.
The kernel knows a device only by its major (which driver) and minor (which sub-device) number — never by the /dev name ✅. Adding a driver therefore means adding extern declarations plus a switch-table slot (and, if the device interrupts or needs boot init, an interrupt/init-table entry) in kernel.c, then relinking ✅.
That is deliberately the shape of the model here. The exact struct cdevsw/struct bdevsw field lists, the nodev/notty/nostr/nullflag stub conventions, the driver-tag naming rule, and real major numbers (e.g. SCSI disk block major 18, parallel char major 21) all live on the device-driver model page ✅.
Note: the full original master.d/kernel.c has not been publicly archived; the table schema above is reconstructed from the Ditto paper plus the modern driver repos 🔴 (for the table shape; the individual slots used by shipped/added drivers are ✅ where a repo or the paper cites them).
68030 MMU and the HAT layer¶
Amix uses the full 68030 MMU through SVR4's HAT (Hardware Address Translation) layer ✅ — the machine-dependent code that maps virtual addresses to physical pages and isolates user from kernel space. A real MMU is mandatory: a 68000, or an MMU-less 68EC020/68EC030, cannot run Amix ✅. The stock kernel also requires a 68881/68882 FPU (it has no soft-float) ✅; the 040/060 port kernels run the FPU-less 68LC060 with a software FPU — see the FPE lane ✅.
Evidence the HAT layer is live in the shipped kernel: the install bootstrap on amix_21_boot.adf contains the SVR4 HAT panic string hat_vtokp_prot: user addr in kernel space ✅ (from amix_21_boot.adf analysis via tools/inspect-adf.sh).
Two hard memory facts follow from this layer ✅:
- A limit on total describable RAM — ≈64 MB on the stock 68030 kernel's fixed arena, ≈128 MB on the 4 KB-page 040/060 kernels — past which the kernel fails silently ✅; see the RAM ceiling. A 16 MB symptom on the stock kernel is real, but it comes from loader placement, not a RAM ceiling; see hardware and quirks §57.
- AutoConfig'd Zorro III boards lie outside the identity map. The low 1 GB is identity-mapped and AutoConfig puts Zorro III boards at
0x40000000and above, so a stock driver can dereference a Zorro II board'sautocon()address directly but not a Zorro III one; a driver that maps the board withsptalloc()reaches Zorro III ✅ — the stock drivers are Zorro II only. (This bullet used to say the layer cannot address Zorro III space and that the limit could not be community-fixed; corrected, see the Zorro III correction.)
The processor cutoff is set by this same MMU dependency: the stock kernel predates the 68040 MMU, so stock Amix has no 68040/68060 support, and an A4000 cannot officially run stock Amix ✅. The public 68040/68060 port relinks the stock kernel for both CPUs, and the amigaux 1.0 release ships 68060 kernels for an A3000, A4000 or A4000T with a Z3660 ✅. For the full hardware envelope see hardware and requirements; for why these limits bite in practice see quirks; for the current 040/060 situation see Amix on 68040 and 68060.
The kmem allocator — what a driver can assume ✅¶
The layout of the kernel heap allocator was recovered by full disassembly of kmem_alloc/kmem_free/kmem_allocbpool/sptalloc/segkmem_alloc/page_get in the shipped kernel ✅. It is worth knowing for any driver-debugging, and one property of it is a load-bearing DMA hazard:
| Request size | Served from | Alignment / physical layout |
|---|---|---|
| ≤ 256 B | small buddy pool (classes 16..256) | pools carved from 4096-aligned 8-page regions |
| 257 .. 4096 B | big buddy pool (classes 512..4096) | same 4096-aligned 8-page regions |
| > 4096 B | sptalloc whole pages (VA = pfn << 11 on the stock 030 kernel; pfn << 12 on the 040/060 kernels) |
page-aligned, but physically SCATTERED |
kmem_allocreturns ≥ 16-aligned pointers. A "returned" pointer that is0 mod 2048but not8 mod 16relative to its wrapper cannot have come from the allocator — a handy alignment argument when a theory needs disproving. ✅kmem_freewrites[next][prev]freelist links into a freed chunk's first 8 bytes, so use-after-free / wild-free corruption characteristically shows pointer-shaped values at a block's head. ✅- The DMA hazard (the important one): a
> 4096-byte allocation is virtually contiguous but physically scattered —segkmem_allocpops arbitrary frames offpage_freelistand maps them at consecutive virtual addresses with no physical adjacency. Sovtop()on such a buffer is valid for exactly one page (NBPP = 2048on the stock 030 kernel; 4096 on the 040/060 kernels), and any single DMA transfer that crosses a page boundary lands its tail in a different, unrelated physical frame. This is the mechanism behind the cdfs wild-write corruption; the driver-side rule (page-align every DMA target, guard(va & (NBPP-1)) + nbyte > NBPP) is on the driver model → DMA-alignment contract. ✅
When the allocator is empty¶
Measured in emulation on the amigaux 1.1 module kernels of both lines (A4000 + Z3660, 32 MB,
multi-user), with the allocator drained by KM_NOSLEEP pieces and given back by a timeout 20 s
later:
- A small
KM_SLEEPrequest sleeps like a large one ✅. Onekmem_alloc(4096, KM_SLEEP)(the big buddy pool's top class) returned only when the release ran, 1201–1202 ticks later, on 3 of 4 runs across both lines. - It can miss its wakeup ✅ (seen once in four runs; the mechanism 🔴, not found). On one 68030 run the release freed 1 478 208 bytes and the request slept on. It returned 57 149 ticks (about 16 minutes) later, only when a second drain-and-free cycle freed memory again.
- New processes wait too 🟡. With the allocator drained, a shell's next command (a
forkandexec) did not run until the release, every time. This is inferred from the timing; the sleeping call was not identified.
So code that runs in a user's process asks KM_NOSLEEP and returns ENOMEM; a sleep may last long
after memory is back. How small the allocator is on a 32 MB box is on
the loadable-modules page.
- How much a large request can get. Requests above a page come out of the fixed 4 MiB kernel map that page[] and the u-areas share, so a box with more RAM has less room: after multi-user the largest single KM_NOSLEEP request was 256 KiB on a 128 MB 040/060 kernel and 512 KiB on a 64 MB 030 kernel, and a KM_SLEEP request above that never returns ✅ (emulator). The full table is on loadable kernel modules → kernel memory.
SVR4 networking: STREAMS, TLI, sockets¶
Networking is built on the standard SVR4 stack ✅:
- STREAMS is the underlying I/O framework for the TCP/IP and network drivers ✅. STREAMS drivers are a distinct third driver class (a character driver carrying a
streamtab) — used for networking; see the device-driver model and the Hydra STREAMS/DLPI driver case study ✅. - TLI (Transport Layer Interface) and BSD sockets are both available as programming APIs over that stack ✅.
- The kernel is POSIX.1-conformant ✅.
At the user level the native Ethernet device is aen0 (the A2065 LANCE driver) ✅. Static IP only (no DHCP) 🟡; DNS is off by default (resolves via /etc/hosts) and must be enabled explicitly 🟡. The networking specifics — enabling DNS, default routes, NFS, SLIP — are covered on the networking page, not here.
System management surface¶
Amix exposes the usual SVR4 administration model ✅:
sysadmis the menu-driven admin tool; Amix also shipsamixadm, a menu of the same steps Commodore's first-bootsystem.setupasks (nodename, domain, date and time, system-account passwords, a user, X11, xdm, Netnews) ✅.init+/etc/inittab+ run levels govern system state and what starts at each level ✅. Shutting down to reboot isshutdown -i6(run level 6) ✅; a kernel install is followed by exactly that ✅.- Virtual consoles are switched with Alt+F1 … Alt+F8 ✅.
- Packaging uses the SVR4 tools
pkgadd/pkgmk/pkgtrans(pluspkgproto) ✅. The Amix-specificamixpkgwrapper is widely reported as flaky/"broken" 🟡, yet the installer itself drives package installation through it, e.g.amixpkg -i -m -d -r /mnt -y standard✅. See the toolchain page for packaging detail.
One userland gotcha worth flagging at the kernel/system level: Amix's /bin/sh is pre-POSIX — no $(...) command substitution, no grep -q ✅. This bites kernel-rebuild scripts and is documented on quirks.
See also¶
- How it works — overview — where the kernel sits in the whole system.
- The device-driver model —
cdevsw/bdevswinternals, major/minor numbers, entry-point naming. - Building and installing the kernel — the exact relink,
make bootpart, and reboot recipe. - Hardware and requirements — MMU/FPU/RAM/Zorro envelope.
- Quirks — the RAM limits, no-Zorro-III, pre-POSIX
/bin/sh, and friends. - Glossary — HAT, STREAMS, TLI, run level, major/minor.
Sources¶
sources/research-brief.md§4 (Kernel architecture) and §5 (Device-driver model, high level), with §2 (hardware limits) and §11 (networking/userland) for cross-references.- Ditto, Writing Amix Device Drivers, 1990 European Amiga Developer's Conference (the driver paper) — kernel as object libraries in
/usr/sys,kernel.cswitch tables,rdbuniximage, add-a-driver procedure. amix_21_boot.adfanalysis viatools/inspect-adf.sh— embeddedhat_vtokp_prot: user addr in kernel spaceHAT/MMU panic string.amix_21_root.adfanalysis viatools/inspect-adf.sh— installer use ofamixpkg -i -m -d -r /mnt -y standardandshutdown -i6.- Modern community driver repos confirming the 2.1 build/relink model and the
relocuniximage name:github.com/asokero/va2000-amix,github.com/isoriano1968/hydra-amix. - AT&T SVR4 DDI/DKI Reference Manual and STREAMS Programmer's Guide (the standard SVR4 substrate cited by the Ditto paper).
- The 040/060 scope of the CPU, FPU and page-size facts:
asokero/amix-040-060-portinclude-modelb/sys/immu.h(NBPP4096,PNUMSHFT12) ✅; the 040/060 status page (the port, the 68LC060 software-FPU lane) ✅; the amigaux.org downloads page (the 1.0 68060 media for an A3000, A4000 or A4000T with a Z3660) ✅. - The kmem-allocator map (buddy pools /
sptallocwhole-page scatter;vtop()valid for one page; freelist links in a freed chunk's first 8 bytes) — full disassembly ofkmem_alloc/kmem_free/kmem_allocbpool/sptalloc/segkmem_alloc/page_getin the shipped kernel, and the DMA-scatter corruption reproduced on a real A4000 + Z3660, from the amix-cdfs port @31e8c3b(NBPP = 2048persys/immu.h). ✅ See the driver model DMA-alignment contract. - The empty-allocator behaviour (first-party record, 2026-11-01) ✅ (🟡/🔴 where tagged): the amix
kernel/dlmlow-memory runs,amigaux/amixkernel/dlm/tests/bench/lowmem/(kmsleep) andkernel/dlm/tests/bench/README.md("Low memory at first use",53624e5, onmaster). - The loadable-module facts (2026-10-29):
amigaux/amixkernel/dlm/README.md,kernel/dlm/core/upstream.pin(kdedon's DLM core, MIT from upstreamb736c59, 2026-10-14; earlier commits GPL-2.0) ✅; the ashnazag project itself, https://github.com/kdedon/ashnazag 🟡 (not reproduced here).