A big difference with ACPI, however, is that the kernel cannot query the Device Tree from the hardware because… well, the Device Tree is external to the hardware. The kernel expects the Device Tree to “exist in memory” either because the kernel image embeds the Device Tree for the target board or because the boot loader loads the Device Tree from disk and passes it to the kernel.
This is actually the same as ACPI: ACPI tables also live in memory, they have nothing to do with hardware and are loaded by firmware or some bootloader. In fact some firmwares provide both ACPI and FDT.
The only practical difference is that amd64 systems are generally assumed to come with firmware that provides ACPI, while for embedded arm64/etc systems the situation is less standardized and you might have the firmware providing ACPI, providing FDT just like it might ACPI, or provide nothing and then the FDT blobs come from the kernel or some user-supplied boot component.
But the ACPI tables are generally not loaded by the OS boot loader, right? They are “there” and you never have to fiddle with their loading process. Are they put in place by the EFI? How did this work with legacy BIOS systems? (I don’t know the answers.)
If your system doesn’t provide UEFI/ACPI natively and you’re adding it in via a separate boot stage (such as UEFI on Raspberry Pis, which is loaded from the SD card), or you are replacing its Flash firmware entirely (coreboot), or you are dealing with a VM where the firmware is just a file on disk (for example, KVM with OVMF UEFI) then yes, you’d fiddle with the ACPI tables just like you would FDTs. Although probably only directly if you’re compiling the firmware yourself, otherwise they usually come bundled into the binary.
The tables are loaded by EFI or BIOS firmware. On BIOS systems you actually have to search memory for a magic signature to find them. UEFI+ACPI just gives you a pointer to the root table the same way UEFI+FDT gives you a pointer to the FDT.
FDTs can also be already put in place by system firmware, however the reason it’s much more common to fiddle with them and ship them with the OS is that they tend to be a lot more tightly coupled to the OS. They aren’t abstract mostly-standardized descriptions of the system, they’re more like config files for Linux drivers. Like, even Android vendors these days do use FDT – with a truckload of completely custom nodes that mainline Linux (let alone a BSD) would have no idea what to do with.
FDTs are actually supposed to be standardized and backwards/forwards compatible. OpenBSD uses the same FDTs as Linux to boot on Macs, for example. The “standard” is the DT documentation in the Linux tree, which is pretty tightly controlled.
The reason why they aren’t in practice is vendors ship Linux forks with non-upstream changes, and then all those additions aren’t subject to the compatibility requirements or standardized so it becomes tightly coupled to those kernels.
Thankyou for explaining the differences in detail. I’ve always seen device trees as scary.
Now in practice: how portable are device trees between different OSs and distros? I believe a lot of Linux SBCs still have custom code burned into them as well as a DTB?
The upstream device tree spec is supposed to be cross-compatible. For example, on Macs with the Asahi m1n1 bootloader, Linux and OpenBSD both use the same FDTs. Even though not all of the DT additions are upstream yet, the team tries to keep them reasonable and upstreamable so there’s no need to break compatibility.
The problem is most SBCs are running downstream vendor fork kernels with completely uncontrolled and unreviewed FDT additions (sometimes really badly designed ones), and then those aren’t standard or kept compatible with anything else.
Basically, if you are running upstream kernels, then the FDTs are compatible regardless of your distro. If you are running downstream kernels then it depends on how well or not that downstream kernel upholds FDT compat requirements and how well their additions are designed.
As far as I know a big difference in function between ACPI and DT is that ACPI supports hotplugging… so if you swap a hard drive or plug in a new USB(?) device, the ACPI interface notices it, adds/updates entries for it and tells the kernel that something changed. Am I correct here, or can Device Tree do something like that as well?
Right? :) I’ve thought about it and, actually, a publisher recently approached me to “write a book on something”. I do have ideas, but… when I research how much they take vs. how much I’d take… well, it’s really, really hard to justify the effort considering how little free time I have.
This has happened to me too. My limited experience is that if a publisher approaches you to “write a book on something” then they’re usually a fairly scummy publisher. :-/
It’s more of a conversion tool than a compiler. But apparently it auto-detects the input format based on the magic number (falling back to the file name), and then automatically does (de)compliation if you don’t specify the output format. Very DWIM and convenient.
This is actually the same as ACPI: ACPI tables also live in memory, they have nothing to do with hardware and are loaded by firmware or some bootloader. In fact some firmwares provide both ACPI and FDT.
The only practical difference is that amd64 systems are generally assumed to come with firmware that provides ACPI, while for embedded arm64/etc systems the situation is less standardized and you might have the firmware providing ACPI, providing FDT just like it might ACPI, or provide nothing and then the FDT blobs come from the kernel or some user-supplied boot component.
But the ACPI tables are generally not loaded by the OS boot loader, right? They are “there” and you never have to fiddle with their loading process. Are they put in place by the EFI? How did this work with legacy BIOS systems? (I don’t know the answers.)
If your system doesn’t provide UEFI/ACPI natively and you’re adding it in via a separate boot stage (such as UEFI on Raspberry Pis, which is loaded from the SD card), or you are replacing its Flash firmware entirely (coreboot), or you are dealing with a VM where the firmware is just a file on disk (for example, KVM with OVMF UEFI) then yes, you’d fiddle with the ACPI tables just like you would FDTs. Although probably only directly if you’re compiling the firmware yourself, otherwise they usually come bundled into the binary.
The tables are loaded by EFI or BIOS firmware. On BIOS systems you actually have to search memory for a magic signature to find them. UEFI+ACPI just gives you a pointer to the root table the same way UEFI+FDT gives you a pointer to the FDT.
Yes, they are put in place by system firmware.
FDTs can also be already put in place by system firmware, however the reason it’s much more common to fiddle with them and ship them with the OS is that they tend to be a lot more tightly coupled to the OS. They aren’t abstract mostly-standardized descriptions of the system, they’re more like config files for Linux drivers. Like, even Android vendors these days do use FDT – with a truckload of completely custom nodes that mainline Linux (let alone a BSD) would have no idea what to do with.
FDTs are actually supposed to be standardized and backwards/forwards compatible. OpenBSD uses the same FDTs as Linux to boot on Macs, for example. The “standard” is the DT documentation in the Linux tree, which is pretty tightly controlled.
The reason why they aren’t in practice is vendors ship Linux forks with non-upstream changes, and then all those additions aren’t subject to the compatibility requirements or standardized so it becomes tightly coupled to those kernels.
Thankyou for explaining the differences in detail. I’ve always seen device trees as scary.
Now in practice: how portable are device trees between different OSs and distros? I believe a lot of Linux SBCs still have custom code burned into them as well as a DTB?
The upstream device tree spec is supposed to be cross-compatible. For example, on Macs with the Asahi m1n1 bootloader, Linux and OpenBSD both use the same FDTs. Even though not all of the DT additions are upstream yet, the team tries to keep them reasonable and upstreamable so there’s no need to break compatibility.
The problem is most SBCs are running downstream vendor fork kernels with completely uncontrolled and unreviewed FDT additions (sometimes really badly designed ones), and then those aren’t standard or kept compatible with anything else.
Basically, if you are running upstream kernels, then the FDTs are compatible regardless of your distro. If you are running downstream kernels then it depends on how well or not that downstream kernel upholds FDT compat requirements and how well their additions are designed.
As far as I know a big difference in function between ACPI and DT is that ACPI supports hotplugging… so if you swap a hard drive or plug in a new USB(?) device, the ACPI interface notices it, adds/updates entries for it and tells the kernel that something changed. Am I correct here, or can Device Tree do something like that as well?
The economics are not usually favorable but you /could/ write an awesome book on all these topics.
Right? :) I’ve thought about it and, actually, a publisher recently approached me to “write a book on something”. I do have ideas, but… when I research how much they take vs. how much I’d take… well, it’s really, really hard to justify the effort considering how little free time I have.
This has happened to me too. My limited experience is that if a publisher approaches you to “write a book on something” then they’re usually a fairly scummy publisher. :-/
Note that the default mode for dtc is -I dtb -O dts so you can just do
dtc bcm2837-rpi-3-b.dtb > bcm2837-rpi-3-b.dts.I would expect the default mode for a compiler to be “compile”, not “decompile”, so the opposite of that. FreeBSD dtc(1) man page agrees at least.
It’s more of a conversion tool than a compiler. But apparently it auto-detects the input format based on the magic number (falling back to the file name), and then automatically does (de)compliation if you don’t specify the output format. Very DWIM and convenient.