Building a Linux GPU Driver for the M4 Mac Mini in One Month | Coderz Club

Building a Linux GPU Driver for the M4 Mac Mini in One Month I Came, I Prompted, I Left Part 2: Building a GPU Driver From Scratch in One MonthPrevious blog post: https://codyho.dev/blog/hypervisor-m

Building a Linux GPU Driver for the M4 Mac Mini in One Month I Came, I Prompted, I Left Part 2: Building a GPU Driver From Scratch in One MonthPrevious blog post: https://codyho.dev/blog/hypervisor-m

By Coderz Club · 2026-09-16 · Tags: coding

Building a Linux GPU Driver for the M4 Mac Mini in One Month

I Came, I Prompted, I Left Part 2: Building a GPU Driver From Scratch in One MonthPrevious blog post: https://codyho.dev/blog/hypervisor-macbook-neo/What We DidTL;DR: Niklas and I built a fully OpenGL ES 3.0 compliant GPU driver for the M4 Mac Mini and MacBook Neo in about a month, a process which normally takes years. Here is Chrome and Firefox running WebGL on the M4 Mac Mini with working compositing:Most importantly, the driver is fast enough to run Minecraft at 200fps:Building this driver involved reverse engineering the AGX s (Apple s name for the GPU) incredibly complicated firmware ABI and user-space components. This was all done in a transparent, verifiably clean room manner using well established techniques. The code is not yet ready for end users, but we are looking to get it to end users as soon as possible.How We Did ItPreviously, I built a hypervisor to reverse engineer macOS. Now the goal became to actually do something useful with it, and what better target than writing a GPU driver. The GPU is effectively a requirement for any modern system, otherwise everything needs to be CPU rendered which is orders of magnitude slower and less power efficient. Our goal was to implement conformant OpenGL (and soon, Vulkan) drivers for the M4 Mac Mini and MacBook Neo.Normally, building a GPU driver is an endeavor that takes years; our goal was to do it in days. It turns out that days was overly optimistic, but weeks is still a massive improvement. In those weeks we have:Reverse engineered the M4, A18 Pro, and (mostly) M5 user space using only live probing, discovering hardware-supported features and instructions not emitted by Apple s driverBuilt a fully working user-space driver, including a new custom IR/shader compiler, command stream builder, and many more componentsReverse engineered, from scratch, the full AGX firmware ABI using traces from the hypervisor I previously builtImplemented a full Linux kernel driver for said firmware ABIThroughout this process, we have not looked at any Apple binaries, only hardware traces (from our hypervisor) and shaders we built ourselves. For user-space graphics RE, we were careful to treat any required Apple blobs as opaque objects. We had a friend write documentation on these blobs 1 so we could write a clean room implementation ourselves (which was mostly built by just blindly trying stuff until it worked). We have published all of our experiments so that anyone can verify the provenance of our work (see the twin agx-re repos under Deliverables).This blog post is divided into two parts, user and kernel space. This mirrors the split in all modern GPU drivers: the kernel is responsible for interfacing with the firmware, allocating buffers, and managing scheduling, while the actual contents of those buffers and what is being scheduled are opaque. User space is responsible for actually understanding how the GPU works and filling those buffers with stuff.Kernel SpaceOn Apple Silicon, the kernel driver does not interface directly with the hardware. Instead, it talks to the GPU firmware running a custom RTOS called RTKit. That means that the first step to a kernel driver is not talking to hardware, it s figuring out the firmware ABI.The firmware ABI was by far the most annoying part of this project, because rather than doing the sane thing of coming up with a reasonable ABI with nice interfaces, Apple essentially took a regular kernel driver, cut it in half, and then put half of it in the AGX and called it firmware, with the other half of the kernel driver communicating using shared structs in memory. Many of these structs have firmware owned fields (which we must never modify and which we must learn from reverse engineering) interleaved with host controlled fields. For an idea of how complicated the ABI is, this is what the shared memory tree looks like on the M1/M2:Asahi Lina famously figured all of this out over grueling 12-hour days to build the M1/M2 kernel driver, an amazing technical accomplishment. Unfortunately, the A18 Pro firmware ABI (I started my RE work on the MacBook Neo and later pivoted to the M4 Mac Mini) is significantly more complicated than the already very complicated M1 firmware ABI:What the F@!#, Apple. Note how the A18 has:1.5x as many structstwice as many pointersa significantly more complicated process for submitting workThere are many other issues that add friction to the RE process 2. I did have some documentation on the firmware ABI, but it was highly incomplete and honestly was not very useful 3.My approach was simple and based on the approach used to successfully reverse engineer the M1/M2 machines: watch what macOS did, replay it, then try to do it ourselves, which is made possible by the hypervisor.When I described this approach to the LLM, it took replay extremely literally: the first thing it did was wait for the first firmware visible event (these are called kicks ), then sa

View this page on Coderz Club