summaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
authorMarek Vasut <[email protected]>2025-11-19 20:32:51 +0100
committerMattijs Korpershoek <[email protected]>2025-12-05 17:21:47 +0100
commit2da3af2f9ee0dbacaf26e95e1ae5261445f1a43c (patch)
tree8c41a919df6fdb2b44e1a1805c3a9c2c56e39faa /boot
parent59f9fcc1f514762674ac07c13c2a85f7aace7250 (diff)
boot: android: Always use 8-byte aligned DT with libfdt
Newer versions of libfdt strictly check whether the FDT blob passed to them is at 8-byte aligned offset, if it is not, then the library fails checks with -FDT_ERR_ALIGNMENT . Currently, android_image_print_dtb_contents() passed FDT directly mapped from abootimg to libfdt, and this FDT is not always aligned to 8-byte offset. Specifically, the FDTs are somewhat packed in the abootimg, therefore if the first FDT blob is e.g. 0xfd bytes long, then the next FDT blob ends up at 0xfd offset, which is not 8-byte aligned. Fix this by first extracting the header into 8-byte aligned buffer, checking only the header for validity, and then by copying the entire FDT into newly allocated 8-byte aligned buffer. While this is not efficient, it is the correct way to handle DTs, which must be at 8-byte aligned offsets. Mitigate the inefficiency for the common case by checking whether the DT might be 8-byte aligned and if it is, map it directly. Signed-off-by: Marek Vasut <[email protected]> Reviewed-by: Mattijs Korpershoek <[email protected]> Reviewed-by: Tom Rini <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mattijs Korpershoek <[email protected]>
Diffstat (limited to 'boot')
-rw-r--r--boot/image-android.c42
1 files changed, 31 insertions, 11 deletions
diff --git a/boot/image-android.c b/boot/image-android.c
index e46dee0d9b3..ea47869a64c 100644
--- a/boot/image-android.c
+++ b/boot/image-android.c
@@ -721,17 +721,19 @@ bool android_image_get_dtb_by_index(ulong hdr_addr, ulong vendor_boot_img,
dtb_addr = dtb_img_addr;
while (dtb_addr < dtb_img_addr + dtb_img_size) {
const struct fdt_header *fdt;
+ struct fdt_header fdth __aligned(8);
u32 dtb_size;
fdt = map_sysmem(dtb_addr, sizeof(*fdt));
- if (fdt_check_header(fdt) != 0) {
- unmap_sysmem(fdt);
+ memcpy(&fdth, fdt, sizeof(*fdt));
+ unmap_sysmem(fdt);
+
+ if (fdt_check_header(&fdth) != 0) {
printf("Error: Invalid FDT header for index %u\n", i);
return false;
}
- dtb_size = fdt_totalsize(fdt);
- unmap_sysmem(fdt);
+ dtb_size = fdt_totalsize(&fdth);
if (i == index) {
if (size)
@@ -885,23 +887,41 @@ bool android_image_print_dtb_contents(ulong hdr_addr)
dtb_addr = dtb_img_addr;
while (dtb_addr < dtb_img_addr + dtb_img_size) {
const struct fdt_header *fdt;
+ struct fdt_header *fulldt;
+ struct fdt_header fdth __aligned(8);
u32 dtb_size;
fdt = map_sysmem(dtb_addr, sizeof(*fdt));
- if (fdt_check_header(fdt) != 0) {
- unmap_sysmem(fdt);
+ memcpy(&fdth, fdt, sizeof(*fdt));
+ unmap_sysmem(fdt);
+
+ if (fdt_check_header(&fdth) != 0) {
printf("Error: Invalid FDT header for index %u\n", i);
return false;
}
- res = android_image_print_dtb_info(fdt, i);
- if (!res) {
+ dtb_size = fdt_totalsize(&fdth);
+
+ /* The device tree must be at an 8-byte aligned address */
+ if (!IS_ALIGNED((uintptr_t)fdt, 8)) {
+ fulldt = memalign(8, dtb_size);
+ if (!fulldt)
+ return false;
+
+ fdt = map_sysmem(dtb_addr, dtb_size);
+ memcpy(fulldt, fdt, dtb_size);
unmap_sysmem(fdt);
- return false;
+ res = android_image_print_dtb_info(fulldt, i);
+ free(fulldt);
+ } else {
+ fulldt = map_sysmem(dtb_addr, dtb_size);
+ res = android_image_print_dtb_info(fulldt, i);
+ unmap_sysmem(fulldt);
}
- dtb_size = fdt_totalsize(fdt);
- unmap_sysmem(fdt);
+ if (!res)
+ return false;
+
dtb_addr += dtb_size;
++i;
}