FP3 custom rom development based on released source code

Actually, it was an answer to this error :


fastboot can do both, it can “create” a boot-image on the fly from specified kernel, ramdisk, dtd (if using header-version>=2) and commandline in this case output will look like this:

fastboot boot arch/arm64/boot/Image.gz --dtb dtimage --header-version 2

creating boot image…
creating boot image - 27367424 bytes
Sending ‘boot.img’ (26726 KB) OKAY [ 0.835s]
Booting FAILED (remote: ‘dtb not found’)
fastboot: error: Command failed

or one can create one’s own boot image using mkbootimage

mkbootimg --kernel ~/src/android_kernel_fairphone_sdm632/arch/arm64/boot/Image.gz --dt ~/src/android_kernel_fairphone_sdm632/dtimage -o boot.img
fastboot boot boot.img

Sending ‘boot.img’ (26726 KB) OKAY [ 0.878s]
Booting FAILED (remote: ‘dtb not found’)
fastboot: error: Command failed

I tried that both using individual dtb’s and compiled dtb’s using dtbtool, both with v2 and v3 dtb image version (I assume v1 is a flat single dtb) I also tried a flat concatenation of all dtb’s like the kernel make file creates.
So far I haven’t gotten past “dtb not found” – but if we had a working boot or recovery image from Fairphone (or offloaded from a phone somehow) we could analyze that to at least figure out which format the bootloader expects - and then figure out which dtb version we need

1 Like

lacking any working images for FP3, I looked at the TWRP image for FP2.
This boot image uses a combined dtb image using dtbtool in version 2
trying to boot from it kinda unsurprisingly results in a “dtb not found” error
@z3ntu , where did you get the parameters for fp3 as in:
--base 0x80000000 --second_offset 0x00f00000 --kernel_offset 0x00008000 --ramdisk_offset 0x01000000 --tags_offset 0x00000100 --pagesize 2048

the TWRP fp2 image uses different offsets. I have no clue how important/critical those are.

1 Like

You should rather compare images for other sdm632 devices (asus X01AD, motorola river, etc) than FP2 images

1 Like

These are the addresses on moto G7 (same chipset)


interestingly the twrp image for the moto G7 has the device tree concatenated old school to the kernel image (using a single device tree file) but this might be depending on the bootloader used
the descriptor info says:

model = "Qualcomm Technologies, Inc. SDM632 + PMI632 MTP S3";
compatible = "qcom,sdm632-mtp", "qcom,sdm632", "qcom,mtp";
qcom,msm-id = <0x15d 0x0>;
qcom,msm-name = "SDM632";
interrupt-parent = <0x1>;
qcom,board-id = <0x8 0x3>;
qcom,pmic-id = <0x10016 0x25 0x0 0x0>;
channel-id-map = [00];

that matches the entries in fairphones sdm632-mtp-s3.dtb

however trying to load that (twrp) image results in (you guessed it) “‘dtb not found’”

1 Like

just for fun I looked at (the TWRP image for) that one as well. It uses the same addresses as the motorola g7, but it has a whole bunch of dtb’s concatenated to the kernel image in binary, for a whole lot of chipsets (including the SDM632 with msm-id 0x15d and pmic-id = <0x10016 0x25 0x0 0x0> but without specifying and board-id)

so now we do indeed have all 3 variants seen in the wild :wink:

Edit: and of course: “dtb not found” :wink:

1 Like

I had a closer look at

its possible that fastboot ignores the device tree information in the boot image and instead looks for the images in the dtbo partition

fastboot getvar all

lists among others:

(bootloader) has-slot:dtbo: Yes
(bootloader) partition-type:dtbo_b:raw
(bootloader) partition-size:dtbo_b: 0x800000
(bootloader) partition-type:dtbo_a:raw
(bootloader) partition-size:dtbo_a: 0x800000

this could be a problem. Although the installed device trees would always fit the hardware, they might not fit the built kernel

the sources we have are for linux 4.9.112

but with the latest updates on the phone (2019-12-17) the stock android image is running linux 4.9.119 - incorrect - still on 4.9.112, must have been my eyes!

how hard is it to upgrade the kernel (assuming/hoping none of the fairphone specific patches got changed) ?

1 Like

I’m still on 4.9.112 for 2019-12-17…?

Linux localhost 4.9.112-perf+ #2 SMP PREEMPT Tue Dec 17 14:35:21 CST 2019 aarch64

But anyways, I don’t think the dtb has changed and it would definitely be “compatible”. And I think dtb != dtbo but that might be completely wrong, I don’t know what the dtbo partition is really used for.

1 Like

my bad, I could have sworn I saw a larger number. I just verified that, it is 4.9.112 on mine, too

this gets more and more annoying.


Apparently Android9 bootloaders must use a device tree overlay partition and overlay the contents to the regular device tree.

the rules are pretty elaborate. It’s thinkable that - even though we are supplying a correct and valid device tree with the kernel, the existing overlay in the overlay partition doesn’t find a symbol it wants and as such invalidates the dtb in question - leading to the error.

in a nutshell the overlay modifies a device tree. So qcom could provide a standard device tree for their SOC - and then Fairphone could put all their stuff in the overlays - enabling or disabling features as needed or changing some wiring. its basically an “override” - all described here: https://source.android.com/devices/architecture/dto/compile.html#verifying-DTO-in-p

now the thing is, as we saw fairphone patched all their changes into the original dts files, so I don’t know what exactly is going on here. Is everything in the overlays and the dtb is effectively unused? or are the overlays empty and everything is in the dtb? or is it some weird mix.

another thing is, when flashing an image into boot slot a or b, the bootloader would use the respective a or b overlay partition. but I have no clue what happens when you make a “try-run” with
fastboot boot
would it load no overlays? or the one from a? or from b? or is that simply no longer supported and simply always fails?

from the android docu:>

Figure 5. Typical runtime implementation for device tree overlay in bootloader.

  1. Load .dtb from storage into memory.
  2. Load .dtbo from storage into memory.
  3. Overlay .dtb with .dtbo to be a merged DT.
  4. Start kernel given the memory address of the merged DT.

so the bootloader does all this magic crap, and its up to the vendor how its implemented exactly.

edit: more interesting bg reading. apparently recovery images are not supposed to rely on the dtbo partition but include dtb and dtbo in the boot image (to prevent bricking if the device crashes after dtbo got written but before the image got updated)

edit: related kernel config flag:
if enabled, it adds a parameter to dtc adding a symbol needed for overlays to work. I’m trying if that helps


When you do a “fastboot boot” the image is loaded in memory then it boots on it. It’s not written anywhere (nor boot_a, nor boot_b, that’s done with “fastboot flash”)
It seems possible to flash only the kernel (https://source.android.com/devices/bootloader/partitions-images), but I don’t know if it uses the ramdisk and cmdline from the partition when we do a “fastboot boot Image.gz”

@corvuscorax : for the moto g7 play, it seems they had to deal with the dtbo partition.
(https://forum.xda-developers.com/g7-play/development/recovery-moto-g7-play-kernel-source-code-t3933680 , I didn’t look further)

1 Like

good links. some scary things there regarding the qcom bootloader. we’re going to have to be careful to not brick our phones :wink:

what I meant is:
with a regular boot sequence from slot A, the bootloader

  1. loads the boot image from boot partition A
  2. extracts the kernel, ramdisk, and dtb from that boot image (basically reads it all into RAM and reads the header where what sits)
  3. reads the dtbo from the dtbo partition A
  4. patches the dtb in memory to apply the changes to dtb described in the overlay
  5. extracts the kernel and starts it - feeding it the address of ramdisk and the (now patched) device tree inc. overlay.

now if you say "boot <myimage.img>

  1. fastboot will push a boot image to the phone into RAM
  2. bootloader reads out header for addresses of image, ramdisk, dtb
  3. <<< this is the question - does the bootloader read out a dtbo? if so which one? dtbo A, dtbo B, whichever is the current one?
  4. bootloader might or might not try to patch the bootimg supplied dtb device tree with whatever overlay info it got from the partition or not
  5. bootloader aborts with “error: no dtb found”
  6. instead of starting the kernel as in step 5 above :wink:

Too late :grin: (waiting for stock rom or a rooted phone)

If the bootloader read the dtbo partition, it is on the active slot (pretty sure, from the test I did, which bricked my phone…). You can know which one is active with “getvar all”, or change it with “–set-active=b”

Maybe we should contact one of the devs who’ve ported twrp to moto g7


I didn’t manage to compile overlay dtbo 's
It’s possible to start compilation by setting



export EXT_DTC=$( which dtc )

(assuming you have a system wide dtc installed which supports the -@ directive. apt-get device-tree-compiler does the trick

however the actual compilation hits a lot of syntax errors in the device description files. @z3ntu I have no idea if this is something easily fixable or a sign fairphone never compiled any overlays, I can’t tell.
If only fastboot had a “pull” option to inspect partitions :wink:

1 Like

Interesting find: Slot A was active. I set it to slot B and tried to boot.

I still cannot boot anything I give it with

fastboot boot boot.img

Same as before (dtb not found)

But the phone is unable to boot into android from slot B

It can boot into recovery and after trying to boot into android and failing for 3 times, it enters into a minimal recovery menu instead. (only options are “try again” and “Factory data reset”)

warning: this decreased a counter, and set an “unbootable” flag getvars all now reports:
(bootloader) slot-retry-count:b:0
(bootloader) slot-unbootable:b:Yes

as far as I understood this situation from the links above, this will prevent slot b from booting at all in the future (including “fastboot boot” commands) and including if a good image is later flashed into that slot.
I don’t know if there’s a way to reset that.

OK, this is harmless.
The bootloader behaves exactly as described in
if you force change the active slot with fastboot --set-active the “unbootable” flag is reset and the retry count is set back to 7

it still won’t boot though :wink:

it’s possible that manual boot overrides could be affected by an “unbootable” flag on the currently active slot, as suggested by ((sorry can#t find the link anymore))

1 Like

Actually, you can change its state :

~ % sudo fastboot getvar all
(bootloader) current-slot:a
(bootloader) slot-retry-count:b:0
(bootloader) slot-success:b:No
(bootloader) slot-active:b:No
(bootloader) slot-unbootable:b:Yes
(bootloader) slot-retry-count:a:1
(bootloader) slot-success:a:No
(bootloader) slot-active:a:Yes
(bootloader) slot-unbootable:a:No

~ % sudo fastboot --set-active=b
Setting current slot to 'b'                        OKAY [  0.023s]
Finished. Total time: 0.025s

~ % sudo fastboot reboot bootloader
Rebooting into bootloader                          OKAY [  0.002s]
Finished. Total time: 0.203s

~ % sudo fastboot getvar all
(bootloader) current-slot:b
(bootloader) slot-retry-count:b:7
(bootloader) slot-success:b:No
(bootloader) slot-active:b:Yes
(bootloader) slot-unbootable:b:No
(bootloader) slot-retry-count:a:1
(bootloader) slot-success:a:No
(bootloader) slot-active:a:No
(bootloader) slot-unbootable:a:No

But that’s very weird that you can’t boot from slot b. (I tried to flash system -it should be treble compatible-, without telling which slot… I guess the first time was on the slot b, and the 2nd -terrible- one on slot a. I had the same boot into recovery the first time. It looks like the slots are differents??)

1 Like

I don’t want to quote the whole post, but do I smell possible solution vectors here for the following? …

1 Like

I found some more info on the hardware:
The closest dts seems to be sdm632-mtp-s3.dts because a bugreport (adb bugreport something.zip) contains a full dmesg from boot:

<5>[    0.000000] Linux version 4.9.112-perf+ (build@15e77c5c4e08) (gcc version 4.9.x 20150123 (prerelease) (GCC) ) #2 SMP PREEMPT Tue Dec 17 14:35:21 CST 2019
<6>[    0.000000] Boot CPU: AArch64 Processor [51af8014]
<6>[    0.000000] Machine: Qualcomm Technologies, Inc. SDM632 PMI632 MTP S3


<6>[    0.287704] socinfo_print: v0.10, id=349, ver=1.0, raw_id=186, raw_ver=0, hw_plat=8, hw_plat_ver=65536
<6>[    0.287704]  accessory_chip=0, hw_plat_subtype=3, pmic_model=65558, pmic_die_revision=65536 foundry_id=2 serial_number=XXX
  • id=349 is {MSM_CPU_SDM632, "SDM632"} (from socinfo.c)
  • hw_plat=8 and hw_plat_subtype=3 might correspond to qcom,board-id = <8 3>;
  • pmic_model=65558 is pmic-id 0x010016
  • if the pmic_die_revision corresponds to the other entries in the pmic-id then there is no matching dts…

Actually, that kinda makes sense, from

The way an A/B update works is – assume working system is booted from slot A: (according to how I understand https://source.android.com/devices/tech/ota/ab/#post-installation )

  1. data of the OTA update is downloaded - and potentially streamed directly to the respective slot B partitions
  2. after writing to the partitions the new system partition is temporarily mounted and a post-install script is run which verifies some stuff
  3. after succesful update (with the old sys still running) the system is eventually rebooted
  4. the system now boots from slot B - using the NEW system
  5. the new system makes additional integrity checks - if they fail, phone boots back into working slot A
  6. (my guess) the old system in slot A is rendered non-operational
    (this could be implicit thanks to updated version numbers in the data partition – if that IS the case, then a device reset might actually render the old system bootable again)

#6 is testable :wink: I shall test that

#6 is indeed the case - after a factory reset, I was able to boot from slot b, and indeed the phone now says it has
Linux localhost 4.9.112-perf+ #2 SMP PREEMPT Fri Nov 15 01:22:55 CST 2019 aarch64
Build Number 8901.2.A.0101.20191115
and it says it has an update available

wiping /data again and booting from slot a I get
Linux localhost 4.9.112-perf+ #2 SMP PREEMPT Tue Dec 17 14:35:21 CST 2019 aarch64

so indeed both slots work - the non-active one should hold the previous to latest system update, and it will not boot unless you factory-reset / wipe data first.


There’s some more info which fields are used for what:

In the event that a given device tree is applicable to all hardware versions matching a given Platform Type / Subtype ID, the major/minior platform version fields in the board_id property shall both be specified as 0xff.


1 Like