I had previously dismissed the idea of replacing the proprietary bootloader on the Galaxy S3/Note 2 boards with an open-source one as impossible, or very tricky. Nonetheless, here we are...
Booting on Exynos 4412 - a quick overview
The Exynos 4412, like many SoCs, starts booting on an internal ROM - some places call it a "Mask ROM", but the Exynos jargon is "iROM". The iROM has a few responsibilities:
- Check if the system is performing a warm reset (like waking from suspend)
- If it is, boot directly to an address written to a special place in the on-chip SRAM.
- If it's not, check the "operating mode" pins to figure out where to boot from: eMMC, SDMMC, or NAND. If the selected boot mode isn't found, it will fall back to either SDMMC (i.e. the SD card), or some magic, undocumented USB download mode.
- Load the next stage bootloader, called "BL1", from the chosen boot mode - and cryptographically verify it against values fused into the SoC (you can read more about exactly what it does on this nice blog post)
- Jump into the BL1 if the signature check passes.
- Loop forever if it doesn't.
The BL1 then loads the next stage bootloader - creatively called BL2 - from the boot device, and (optionally) signature checks this. Note the "optionally" part - this will come in handy later :-).
Since the BL1 is signed by Samsung, it can be used on any Exynos 4412 produced. Of course, on consumer devices like the S3 the BL1 signature checks the next stage bootloader - and so a free software replacement for the bootloader is impossible without signing keys. Fortunately (for us), there are boards like the ODROID-U3 and the Insignal Origen Quad board that shipped with BL1s that don't signature check the next stage. So: replacing the bootloader has gone from "totally impossible because of signature checking" to "feasible, but probably involving a lot of bricked devices along the way".
Now, personally, I'm not a fan of bricking things - especially not my toys! So it would be great if there was a way to make the iROM load BL1 from an SD card, rather than from the eMMC.
Conveniently, as it turns out, there is!
Although, admittedly it's not actually that convenient. Leaked Samsung service documents describe booting off the SD card in order to recover the device. All that's required is to disassemble it, and short a resistor. Disassembly is surprisingly trivial: iFixit has a selection of pretty good guides for replacing things components - so I used the motherboard replacement guide. I did not, however, swap motherboards.
I suspect that I'd make a poor doctor: after opening up my patient, my next thought was "now what?".
What's it meant to do anyway?
So, after BL1 loads BL2, what then? Unfortunately, it's not as simple as "load and boot Linux". The BL2 is responsible for initialising DRAM and bringing the CPU up to a faster clock speed. On boot, the Exynos 4412 runs at runs at 400MHz. The BL2 reinitialises this to 800MHz, and then reconfigures all the other clocks in the system (UART, DRAM mainly) to make stuff work. If you're after the gory details, there are some pretty diagrams of the relationship between clocks in section 5.4 of the user manual. There's also the DRAM init, which, honestly, is quite boring to set up. In fact, because there's two DRAM controllers, it's actually twice as boring!
Anyway, after initialising the DRAM and the clocks, the BL2 can - at last! - load the final stage of bootloader into DRAM. So all that's left is to... write a BL2?
Fortunately, others have been here before me. Dominik Marszk had, many years ago, used the U-Boot release for the Origen Quad and Odroid X to get U-boot up and running on the Galaxy Camera - which, despite the wacky camera on the back - is pretty similar to an S3 on the inside. Unfortunately, this particular U-Boot release is approaching eight years old. Unlike wine, it appears that software does not improve with age. So, after a patch to fix the build on GCC versions that have been released since after the dinosaurs went extinct, we have an image which can be flashed onto an SD card. Then, it's just a matter of some careful tweezering of a tiny resistor, some slightly worrying sparking, and some careful manoeuvring of the battery before we have... a booting board! Arguably, it doesn't do much: but it is a start. Obviously, an eight-year-old vendor fork of any software project is less than ideal for day-to-day use. So next: mainline U-Boot!
I won't go into detail regarding everything I did, however, you can see the general cycle of despair at "why is it not working", and then relief at "oh, it is working!" in the commit log for my U-Boot fork. The basic steps ended up being:
- directly pull the eight-year-old U-Boot RAM and clock initialisation files.
- Check that the BL2 works at least well enough to write stuff out to UART.
- Try and get it to load the next stage from the SD card. Spend multiple days writing debugging code to narrow down the issue. Ultimately, it turned out that none of the debugging code was useful.
- Fix it after a wild guess - these seem to be quite useful in embedded development, especially without JTAG!
- Celebrate for a bit!
- Port all that assembly to C.
- Realise that the board will reboot after about eight seconds. Spend another day or two totally stumped, hoping that it's solar radiation, or maybe just the phase of the moon.
- Wait, what else takes about eight seconds to reset a phone? Holding the power button down! Huh...
- Well, that was easy.
And there we have it:
U-Boot 2018.03-i9300-00030-ge2e74ecf4d-dirty (Apr 30 2018 - 22:45:36 +1000) CPU: Exynos4412 @ 800 MHz Model: Samsung GT-I9300 based on Exynos4412 Board: Samsung GT-I9300 based on Exynos4412 DRAM: 1 GiB Howdy! MMC: In: serial@13820000 Out: serial@13820000 Err: serial@13820000 Net: No ethernet found. =>
Next up on U-Boot adventures: adding USB support, installing U-Boot on the eMMC, and booting Linux...