I think I got it. This was a bitch to figure out, but in the end, it's actually quite simple.
I'll explain it the hard way though. Maybe this can serve as a sort of "tutorial" to some folks about how to approach such things.
- flashing 5.0.0 with the currently available kernel works
- flashing 5.1.0 does not always work, neither does 5.1.1.
- after some (lots) of initial panic, trial, and error, I came to the conclusion that this has to do with the kernels used. Indeed, with a 5.1.1 partition, and the 5.0.0 kernel, the system will at least try to boot, while it wouldn't do anything with the 5.1.0 or 5.1.1 kernels.
So, wtf? I decided to take a closer look at the kernels with a hex editor, and to make sense of the obfuscated getkernels.sh code (some like to call that "condensed"
Turns out there is the length of the image (4 bytes) at offset 0xc in every image, and after staring at the code for some time, I finally understood how getkernels.sh used that value to produce files of the corresponding size (rounded up to the next multiple of the block size (1024)). That all looked sort of correct, but the kernels weren't working...
Since the official update for 5.1.0 is available in binary form, and it contains kernel updates as well, I used kindletool to extract that. Simply extracting it, I found a file called "kernelinfo", containg information about one kernel that is flashed during the update. Poking around here and there, some more information appears:
- that particular kernel file is of size 5111808, but its header says 0x4dab40 (5090112). But taking a look at this kernel, this is yet another one, different from the 5.0.0 and the (extracted) 5.1.0 one. In fact, the update installs this kernel in stage 1 of the update, then patches it (using bspatch, if you're interested) during stage 2 of the update (which is contained in payload.bin and is itself an update that can be extracted).
- so I actually did that and patched the stage 1 kernel using the stage 2 patch, and sure enough, I got the same kernel as the getkernels.sh yielded - except that it was a larger file, and that it was actually booting.
Now that I had 3 kernels which were working (and 2 which weren't) I compared the working ones. They're all mostly binary gibberish of course, but at least... if all of those files are larger than what is stated in their header, then what actually IS at the offset indicated in the header? Turns out quite simple: there are 0x40 bytes of obviously meaningful content, then all the rest is filled with 0xFF bytes.
And what about that 0x40 (64)? Why would it state its own length "almost" correctly, but forgetting about those 64 bytes? Let's go back to the beginning of each file, and it suddenly makes sense: There is a 64-byte header, containing information about the name and the size. But the size concerns the payload, which comes after the header.
The grand and simple conclusion: getkernels.sh has to consider 64 more bytes (before the rounding), and all is well.
@geekmaster: would you please update the getkernels.sh script accordingly?
PS: Well, at least now I'm not afraid of mfgtool and fastboot anymore... at all! After all, I've been switching between all 4 modes (USB download, fastboot, diags, main) about a hundred times during the procedure