Skip to content

The Story

Vendor lock-in isn’t just a cloud problem. It’s a hardware problem too.

Here in Tangier, Morocco, there are warehouses filled with computers Europe has already written off. Machines with 2 to 8 GB of RAM and 64 to 256 GB SSDs, sold by the pallet for almost nothing after being discarded by companies upgrading their fleets.

The hardware wasn’t broken. The software had simply moved on. The OS kept nagging users to upgrade, only to tell them afterward that their computer was too old to run the upgrade. That’s software gaslighting hardware into becoming e-waste.

So I started buying it.

The story really starts exactly one year ago, just after my birthday. Here in Tangier, one warehouse in particular had thousands of Mac minis. Totally functional. 4GB, 8GB, 16GB of RAM, or no RAM, or no disk, or a small power supply that just needed one capacitor changed, or dirty, or sometimes brand new, still sealed. All shipped out of Europe to make room for a new fleet of AI-powered machines.

We have hundreds of stores like this in Morocco, but this one was different: the hardware looked pristine. Apple builds good hardware. But the vendor told me it was headed to a recycler to be scrapped for metal, because “nobody can use them today.”

That’s bullshit. I know people still running SGI machines in the T2SDE Linux Discord.

I asked him: what if I become the recycler?

He warned me: you’ll lose money. Most of this hardware only runs old Windows or macOS, because there are no drivers for anything current.

At the time I believed drivers were just a Google search away. I told him to hold off, went home, and asked Claude and GPT: I have 100 Mac minis, what can I do with them?

Both hallucinated the standard Reddit-brain answers: build a cluster, learn Kubernetes, make a NAS. Everything you hear from someone who discovered AI last weekend.

Then I had the “smart” idea: install FreeBSD on them. FreeBSD runs Netflix and Sony’s infrastructure, so it must have all the drivers. Right?

Turns out FreeBSD was the worst OS to attempt this with, followed closely by DragonFly BSD. I felt like the protagonist in one of those American movies who walks into an armory full of weapons and picks the knife. That was me, except instead of a knife, I picked a pencil.

Week one, I read ebrandi’s FDD-book. Then I bought FreeBSD Device Drivers by Joseph Kong, published 2012, still relevant today.

I started small: the kind of contribution any monkey could submit. A typo. Outdated documentation. Nothing that would wake up a maintainer in a bad mood and earn a 🖕.

I also pulled every datasheet I could find, most of them on GitHub, to understand the architecture. The newer ones are written in English, technically, but not an English I understand. So I went digging into the past instead. Old hardware is simpler. To get through a hundred layers of modern complexity, I needed to start at the start.

I’d already built a few drivers from the books before this, but I had no idea how to actually submit one upstream. So I made myself a training exercise: pick an existing driver, delete it, and try to rebuild it from memory without looking at the original code. I couldn’t lean on AI for this either, since it’ll just hand you working code. All it was allowed to do was answer questions, not write the answer for me.

My first victim was a comment: /* XXX magic number */, sitting in the ASMC driver, the one that talks to the Apple System Management Controller. Witchcraft. Something that needed exorcising from the codebase.

The SMC held a fixed count of 256 keys in that code, no explanation for the number, just the magic-number warning next to it. So I wrote a simple loop to read the real count and dump every key. Online, people warn that sending the wrong data to the SMC can brick the machine permanently. I didn’t care. Those computers were headed for the aluminum smelter to become new Mac minis anyway. Worth the risk.

I got 297 keys back on that Mac Mini 5,1. I didn’t understand half of them. Apple names them in its usual enigmatic style. But it’s 2026, people reverse-engineered most of those keys years ago, so I didn’t have to guess much.

That patch, reviewed by markj and adrian, committed by Adrian Chadd, was the first commit I ever landed upstream.

Two days later came commit number two, and this one wasn’t an exercise. The Mac Mini’s fan was loud, and I needed a way to shut it up.

Digging through asmcvar.h, I found the FS! SMC key already defined in the driver, a 16-bit bitmask where each bit controls one fan, 0 for automatic thermal control, 1 for manual. It was just sitting there, unused, never exposed to anyone.

So I exposed it. I added a sysctl per fan, dev.asmc.0.fan.N.manual, that flips a fan into manual mode. Once a fan is in manual mode, it runs at whatever speed you set with dev.asmc.0.fan.N.targetspeed instead of whatever the SMC decides on its own. The trick is doing it as a read-modify-write on the bitmask, so setting one fan to manual doesn’t touch the others.

Reviewed by adrian and markj again, Differential Revision D54437. Two commits in, and I already had a quieter Mac Mini to show for it.

A few commits later came my first fix in a WiFi card: mtw(4), the driver for the MediaTek MT7601U USB adapter.

The bug was a warm reboot problem. Cold boot, the adapter worked fine. Reboot without cutting power, and it wouldn’t come back. The only fix was to physically unplug and replug the USB adapter, or fully power cycle the machine. A warm reboot doesn’t power-cycle USB devices, so the MT7601U just sat there in whatever state it was in from the previous session. Its firmware still thought it was ready, so it ignored every initialization command from the OS and the driver sat there timing out waiting for the MCU. The network still technically worked, you could ping 1.1.1.1, but it crawled, and debug mode was flooded with thousands of error lines.

This was the first driver bug where I couldn’t just read the code and see the fix. I converted the state machine to Ruby, drew a diagram of it, found where the logic broke down for the stale-state case, fixed it on paper, then wrote the actual C code from that diagram.

The fix does USB re-enumeration on attach to force the device back to a known state, detects when the MCU thinks it’s already ready from a previous session and forces a reset before loading firmware again, and pads out the timeouts: firmware load goes from 3 seconds to 10, and the MCU ready poll goes from 100 attempts to 300 with longer delays between them. The higher numbers were a guess. A lower value might work just as well, I didn’t have the patience to bisect it.

Tested it across multiple warm reboots on a MacBook Pro (late 2015) and a Mac Mini, both with the MT7601U adapter. The failure only showed up when the adapter sat behind an always-powered USB hub port on a monitor. The laptop’s own ports don’t stay powered through a reboot, so it never hit the bug on its own.

This is the commit where the ASMC driver’s design started to feel ridiculous to me.

I was adding support for the MacBookPro11,5, the mid-2015 15-inch model with the AMD Radeon R9 M370X GPU. It looks nearly identical to its sibling, the MacBookPro11,4. But testing showed it was missing several SMC keys the 11,4 has (IBLC, ICMC, IC2C), so it needed its own model-specific sensor table entirely: 41 temperature sensors, each with its own key identifier, display name, and description, all hardcoded by hand.

That’s when it hit me. Every single MacBook model needs its own entry in this driver, one at a time, by hand, no matter how close it is to the model sitting right next to it on the shelf. Two laptops that look identical from the outside, and the driver still has to be told about every sensor difference between them individually.

Apple hardware doesn’t trust Windows. On dual GPU Macs, the ones with an Intel integrated GPU alongside an AMD or NVIDIA discrete one, the firmware disables everything that could cause chaos unless it recognizes the OS asking as Darwin over ACPI. Anyone else gets treated as untrusted, and the iGPU stays hidden.

Before this patch, FreeBSD was treated as untrusted. Both GPUs sat there enabled at full power, all the time, because the firmware never handed over the information needed to manage them properly. The machine worked, but it burned through battery running two GPUs when it only ever needed one.

Linux had already solved this years earlier, in drivers/acpi/osi.c: detect Apple hardware, turn off all the Windows OSI strings it normally announces, and explicitly install the Darwin OSI handler instead. So the firmware asks “who’s asking,” and the OS just says “Darwin,” and the firmware believes it.

I brought the same trick to acpi(4) on FreeBSD. It detects Apple hardware through the SMBIOS vendor string, strips the Windows OSI announcements, and installs the Darwin OSI handler in their place. Once the firmware believes it’s talking to Darwin, it exposes the iGPU too, and now you can disable the dGPU entirely and run on the iGPU alone, the same battery life trick macOS has had the whole time. It’s gated behind a tunable, hw.acpi.apple_darwin_osi, on by default, so anyone who wants the old untrusted behavior back can flip it to 0.

Nothing about the hardware changed. I just taught the OS to steal an identity, and the firmware handed over hardware it had been sitting on the whole time.

This was the last patch of this kind I ever wanted to submit: MacPro3,1 temperature sensor support, the Early 2008 Mac Pro, tested and verified with Sonicblue7.

78 lines added across two files. Nine of them were the actual model entry. The other 69 were three macros defining 42 temperature sensors each, ambient, CPU cores, memory risers, hard drives, northbridge, power supplies, VRM, one identifier, one name, one description, repeated 42 times, for a machine that shipped in 2008.

The diff looked ridiculous, and it wasn’t hard to review, it just took time. adrian had to read through 42 near-identical entries to confirm none of them were wrong, for the third or fourth model in a row. That’s not a good use of a reviewer’s afternoon, and it wasn’t going to get better on the next Mac Pro, or the one after that. Every model, forever, one commit at a time.

This one was interesting for two reasons. A Panasonic FZ-Y1, a rugged Toughbook with a 4K display, was headed for the trash pile just like everything else. And its BIOS was lying to it.

On these machines, the embedded controller latches the wireless RF_KILL line on shutdown or suspend once the battery drops below a certain level. So the laptop boots up, or wakes from sleep, and wireless comes up hard-blocked, as if a physical switch had been flipped, when nothing was ever wrong with the radio at all. The firmware convinced itself the wireless should stay off, and never told anyone why.

The fix calls the WLSW.SHRF ACPI method during attach and resume, which deasserts the RF_KILL GPIO through an SMI call and clears the false block. Tested on the FZ-Y1 with its Intel Wireless 7265 card, wireless came back on every boot and every resume, no switch flipping required.

That machine didn’t stop at the OS fix. Looking into that firmware further, it hadn’t even been patched for known critical vulnerabilities, Panasonic had simply stopped maintaining it. So I went further and coreboot’d it myself later, ripping out the proprietary firmware that had been lying to it, and neglecting it, the whole time.

Three months in, I finally had enough confidence to upstream an interface that could destroy the SMC if you fed it the wrong bytes. Nobody watching seemed to notice what it actually meant: that FreeBSD was quietly on its way to full Apple hardware support.

It’s a raw SMC key read/write interface, four sysctls under dev.asmc.0.raw.*: key to pick which four-character SMC key you’re talking to, value to read or write it as a hex string, len for the key’s length, auto-detected but overridable, and type to see what kind of value it is, ui8, flt, whatever Apple decided on. Under the hood it uses SMC command 0x13 to ask the controller for a key’s metadata before touching it, so it can figure out length and type on its own instead of guessing.

This is the tool that made the earlier exploring possible instead of theoretical. It’s how I found that the AUPO key turns on Wake-on-LAN from a fully powered-off S5 state, and it’s how all 297 keys on the Mac Mini 5,1 finally got mapped, one by one, safely enough not to brick the board doing it.

By this point I’d refactored something like 40% of the ASMC driver, but always inside someone else’s file, someone else’s original authorship. This one, appleir, was the first driver with my full name on it.

It started as a straightforward port. Linux already had a driver for the Apple IR receiver, hid-appleir.c, built on protocol reverse-engineering that James McKenzie and others had done years earlier on Apple’s proprietary 5-byte Apple Remote HID reports. I figured I’d bring the same thing to FreeBSD and be done with it.

Then I bought a fake Apple remote to test with. It didn’t speak Apple’s protocol at all. It spoke NEC, the generic infrared protocol used by more or less every cheap universal remote on the planet, a fixed 4-byte format with a simple checksum.

So instead of just porting the Apple side, the driver grew to decode both: the real Apple Remote’s proprietary format, key down, repeat, low battery, the works, and the generic NEC protocol with its own default keymap for whatever knockoff remote you point at it. Either one comes out through evdev as standard KEY_* codes, and raw HID access stays open at /dev/hidraw0 if you want to remap it yourself. Tested on a Mac Mini 2011.

I wrote a tiny script afterward to receive a webhook and recompile FreeBSD automatically, just so testing the next round of remotes wouldn’t mean sitting there waiting on a full rebuild by hand.

I wanted a real answer to a simple question: how much power was this machine actually drawing. The SMC already had the numbers, it just never told anyone.

This one adds automatic detection for the SMC’s undocumented voltage, current, power, and ambient light sensors, four new sysctl trees under dev.asmc.0.voltage.*, current.*, power.*, and ambient.*. It scans every SMC key at attach and sorts sensors by their prefix: VC, VD, VG, VP, VI for voltage, a whole set of I prefixes for current, another set of P prefixes for power, ALV and ALS for ambient light. It handles eight different fixed-point SMC data types and converts everything down to consistent milli-units.

Tested against a Mac Mini 5,1 (2011) with a real multimeter on the leads, not just trusting the numbers. 54 sensors turned up, all verified.

This is where the frustration from every model needing its own entry finally paid off.

I sat down with Claude and GPT to research the models still missing support, and had them web-search and compile the full list of SMC key prefixes across Apple’s entire Intel Mac lineup. Doing the math on what it would take to keep going the old way, one hardcoded table per model, the diff came out to about 10,000 lines. I knew nobody reviewing patches for FreeBSD would let that slide. This is FreeBSD, not macOS, and even macOS itself doesn’t have documented support for all of these sensors on all of these models.

The pattern was right there. Apple is consistent with its own naming: the same voltage, current, power, and light prefixes I’d just wired up for the power-sensor commit show up across every model, always in the same shape. There was no need to hardcode a table per machine, the keys themselves already say what the hardware supports.

So I ripped the tables out and replaced them with universal probing: scan the SMC keys at attach time, detect capabilities by what’s actually present, and build the sensor list from reality instead of a hand-maintained list. That deleted roughly 474 lines out of asmc.c and 778 lines out of asmcvar.h, over 1,200 lines of boilerplate gone. Tested across a MacBook Pro (2007, 2014, 2015), a MacBook Air (2015, 2017), an iMac (2011, 2013), and a Mac mini (2011). One driver, every Intel Mac, no more per-model entries ever again.

Getting a T2 Mac’s NVMe drive recognized at all needed its own set of quirks. The Apple T2’s ANS2 storage controller doesn’t play by the standard rules: 128-byte submission queue entries instead of the usual size, one MSI vector and one IO queue, admin and IO queues sharing a single CID table with an offset to keep them from colliding, no async event support, and IDENTIFY commands above a certain CNS value have to be rejected outright or the firmware gets confused.

Without this quirk, a T2 machine’s NVMe controller just doesn’t show up. No boot drive, nothing.

The fix worked. It also, in testing, managed to panic the T1 chipset instead, a different Apple coprocessor from a different Mac generation that had nothing to do with any of this. Two similar-looking in-house Apple chips, and getting one right nearly took down the other.

Storage sorted, next was the T2 chip itself. apple_bce is the Buffer Copy Engine driver, and it doesn’t do anything visible on its own. It’s the middleman: an ARM coprocessor sitting between FreeBSD and Apple’s own internal peripherals, speaking a private dialect over a mailbox protocol and DMA rings that Apple never documented anywhere.

This driver just opens the line: mailbox handshake, queue setup, firmware keepalive. Nothing talks over it yet, but nothing else on the T2, VHCI, audio, any of it, can talk to the chip without this existing first. Tested on a MacBookPro16,2 (A2251) and a Mac mini 8,1 (A1993).

With BCE open as a transport, the next piece was VHCI, a virtual USB host controller built on top of it.

On a T2 Mac, the internal keyboard, trackpad, and Touch Bar aren’t real USB devices. They’re virtual devices multiplexed over the T2’s own private channel. Without a VHCI driver, none of that shows up to the OS at all, and the only option is an external keyboard and mouse. Apple will sell you a replacement top case with a working keyboard and trackpad for $499, on a laptop that cost $200 out of the same warehouse pile as everything else in this story.

VHCI does the port discovery, device enumeration, control and interrupt and bulk endpoint support, firmware event handling, and suspend and resume, all riding on top of BCE’s mailbox. Plug in nothing extra, and the internal keyboard, trackpad, and Touch Bar just work.

In the months since, I’ve bought over 5,000 discarded computers. Not to build a datacenter, but to understand them, resurrect them, and mostly donate them.

That project became ChaosBSD.

In six months, ChaosBSD has landed 87 upstream commits into FreeBSD. Not an AI-inflated number, real commits. Some touched drivers that hadn’t been changed in 24 years. Ironically, once I started buying up old hardware at scale, SSD and RAM prices (even DDR2) went through the roof. 😄

Drivers aren’t like most other subsystems. Frameworks get rewritten, filesystems get replaced, APIs evolve, but silicon doesn’t get updates. A driver is either correct, incomplete, or it never gets merged. Once it’s upstream, it often stays there for decades.

A year before any of this, AWS deleted my 10-year-old account over a disputed $100 bill. That day I learned something uncomfortable: unless you’re a customer capable of causing a PR disaster, your monthly bill doesn’t buy you much leverage, and you shouldn’t trust a single cloud provider with a decade of your work. ChaosBSD is my answer to the same problem, applied to hardware.

None of this was ever just about my machines. Every driver went upstream, so every FreeBSD user benefits, not just me. If you have an Intel Mac, you can put FreeBSD 16 or DragonflyBSD on it today, and it’ll feel snappier than the original OS.

Commit #87 was about FireWire, and it didn’t start with me. A friend with about $100,000 worth of professional audio hardware reached out and asked if I had any hardware to sell him with FireWire on it.

I asked why he wanted FireWire specifically. He said he’d bought $100k of audio gear over the years and had no intention of throwing any of it away. USB cables kept dying on him too, constantly. Importers care about price, not build quality, so nobody’s stocking a gold-plated USB cable, they buy whatever’s cheapest and it fails accordingly. FireWire cables from that era were built for professional audio and video work, gold-plated connectors included, so the ones still floating around held up. His microphone needs 48V phantom power too, standard for condenser mics, and that comes from the audio interface itself, not the data bus. USB was never going to supply anything close to that anyway. It came down to USB simply being the cheaper, less reliable option for everything else around it.

Most people think FireWire died when USB got popular. It didn’t. It’s still running professional audio interfaces, DV camcorders, and industrial and scientific cameras: equipment that keeps doing its job every day. Audio gear doesn’t need an upgrade if it still works correctly. That’s where I tested it too: users still running old versions of macOS that don’t even have an updated SSH client, because the hardware they depend on has no reason to move on.

Together with Adrian Chadd, we dusted off the FireWire stack, rediscovered how it worked, cleaned it up, and refactored years of accumulated code. Then we didn’t stop there: we added three new drivers:

  • fwcam: FireWire webcams
  • fwisound: Apple FireWire audio interfaces
  • fwdv: DV camcorders, including many classic Sony, Canon, Panasonic, and JVC models

That means FreeBSD can now talk directly to equipment plenty of operating systems have quietly abandoned.

Someone on Reddit used it to digitize 50 tapes of their childhood. I used it to join a Zoom call with the FreeBSD wifi group.

ChaosBSD isn’t a recommendation. It’s a diagnosis for people who find themselves asking the same questions I did: what happens to hardware that isn’t broken, just obsolete? And who takes responsibility for keeping it alive?

But most of you aren’t here to resurrect a warehouse full of dead machines. You’re here because your actual machine needs an operating system, and you want to make an informed choice. The story above is why ChaosBSD exists, but it’s not why most people land on this site.

The other five operating systems mentioned here, Linux, FreeBSD, OpenBSD, NetBSD, and DragonFly BSD, are all real, production-ready choices. Each one is correct. Each one is wrong, depending on what you ask it to do. Your hardware, your patience, your paranoia, and your skills all matter.

Take the interrogation. Answer honestly. It knows when you lie.

Start the interrogation