← All Series
Python
7 parts · ~150 min total
March 25, 2026 · 15 min read
MerakiMR18PythonJTAGOpenWrtOpenOCDdeep-dive
The boring infrastructure that makes everything else possible
I got my mind on my money and my money on my mind
Every previous post in this series focused on the dramatic stuff—cache coherency nightmares, hand-encoded MIPS assembly, twenty-minute UART transfers. But none of that works without the plumbing. The mr18_flash.py script has about 300 lines of infrastructure code that handles three things: talking to a bench power supply, talking to OpenOCD over telnet, and managing the OpenOCD process itself. It’s not glamorous. It’s the kind of code you write at 1am because you’re tired of manually typing commands into four different terminals. Let’s walk through it.
Read more →
March 25, 2026 · 29 min read
MerakiMR18PythonJTAGOpenWrtEJTAGdeep-dive
Catching a CPU in the dark with a 1.5 second flashlight
I been up for a long time, I ain’t get no sleep for it
Post 3 gave the high-level overview of the timing attack—power on, wait 1.5 seconds, halt the CPU before Cisco’s kernel murders the JTAG interface. This post rips open mr18_flash.py and walks through every halt strategy and the main retry loop in detail. None of this is elegant. It’s the kind of code you write at 2am when you’ve already power-cycled an access point forty times and you’re starting to take it personally.
Read more →
March 25, 2026 · 21 min read
MerakiMR18PythonJTAGOpenWrtcachedeep-dive
What load_and_run() actually does (phases 0-2)
I been through the fire and the rain, and I came out the other side
Posts 3 and 4 gave the high-level overview of the load pipeline—flush, load, flush again, verify, launch. This deep-dive series rips open the actual Python and walks through the code. We’re starting with phases 0 through 2 of load_and_run(), which covers everything up to but not including the XOR verification passes.
Read more →
March 25, 2026 · 31 min read
MerakiMR18PythonJTAGOpenWrtMIPSdeep-dive
CPU-executed XOR verification
Trust none of what you hear and less of what you see / I had to verify the data runnin through the memory
Post 10 covered phases 0 through 2—flush, load, flush again. At that point we have 6.9 MB of initramfs sitting in DRAM, and now we need to answer a simple question: is it correct? This post covers phase 3, the XOR verification pipeline, including the approach that didn’t work and the one that does.
Read more →
March 25, 2026 · 15 min read
MerakiMR18PythonJTAGOpenWrtUARTdeep-dive
Launching the kernel and catching failsafe on the way down
Started from the bottom now we here, started from the bottom now my whole team here
Post 10 ended with a verified binary in clean DRAM. Post 5 gave the high-level failsafe saga. This post covers the actual code: the launch trampoline, the regression that taught me to stop touching the CPU, and two competing strategies for triggering failsafe mode.
Read more →
March 25, 2026 · 13 min read
MerakiMR18PythonOpenWrttelnetdeep-dive
Network setup and sysupgrade
Started from the bottom now we here, started from the bottom now my whole team here
Twelve posts deep. Cache flushes, MIPS trampolines, XOR verification, UART monitoring, failsafe timing. This post covers the last mile—once the kernel is booted and failsafe is confirmed, how do we talk to the device over the network and flash the permanent sysupgrade image? No more PRACC, no more cache paranoia. Just TCP/IP and a couple of file transfers.
Read more →
March 25, 2026 · 27 min read
MerakiMR18PythonUARTOpenWrtdeep-dive
Hex-encoding 7 million bytes because the PHY won’t cooperate
Slow grind, patience on the line / twenty minutes on the wire just to make it mine
Post 6 described the hex-over-UART transfer protocol at a high level—hex-encode every byte, pipe it through an awk decoder on the MR18, pray nothing goes wrong for 20 minutes straight. This post rips open send_binary.py and uart_transfer.py and walks through the actual Python. Two scripts, two transfer sizes, same dumb protocol, very different engineering challenges.
Read more →