/* SPDX-License-Identifier: GPL-2.0+ */ /* * image.c - arm64 kernel Image validation and placement. * * The relocation rules are the ones from the kernel boot protocol, * including the pre a2c1d73b94ed quirks, same math u-boot's * booti_setup() runs. * * Copyright (C) 2026 Bradley Morgan */ #include #include #include #include #define LINUX_ARM64_IMAGE_MAGIC 0x644d5241 /* "ARM\x64" */ #define SZ_16M 0x01000000 #define SZ_2M 0x00200000 /* the 64 byte header from Documentation/arch/arm64/booting.rst */ struct Image_header { uint32 code0; /* executable */ uint32 code1; /* unused */ uint64 text_offset; /* load offset, LE */ uint64 image_size; /* size, LE */ uint64 flags; /* bit 3: relocatable */ uint64 res1; uint64 res2; uint64 res3; uint32 magic; /* "ARM\x64" */ uint32 res4; }; int tb_image_setup(uintptr_t image, struct tb_image *img) { const struct Image_header *ih = (const struct Image_header *)image; uint64_t image_size, text_offset; if (le32_to_cpu(ih->magic) != LINUX_ARM64_IMAGE_MAGIC) return -1; if (le64_to_cpu(ih->image_size) == 0) { /* ancient image, no size field, assume the old defaults */ image_size = SZ_16M; text_offset = 0x80000; } else { image_size = le64_to_cpu(ih->image_size); text_offset = le64_to_cpu(ih->text_offset); } /* * flag bit 3 says the image can live anywhere, honour where it * already is. otherwise the base must be 2MB aligned, the * physical offset from there is text_offset. */ if (le64_to_cpu(ih->flags) & (1ULL << 3)) { uintptr_t base = image - text_offset; img->load = ((base + SZ_2M - 1) & ~(uintptr_t)(SZ_2M - 1)) + text_offset; } else { /* * no relocate flag: the image must sit text_offset from a * 2MB aligned base. it is already staged at the fixed * address, treat its own position as the answer. */ img->load = image; } /* the whole image, header included, lives at load, entry is code0 */ img->ep = img->load; img->size = image_size; return 0; }