/* 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 fallback where image_size is 0 and * the offset was fixed. qemu virt loads us at the bottom of RAM, same * place the kernel wants to be, so the common case is a no move. * * Copyright (C) 2026 Bradley Morgan */ #include #include #include #include #include #define SZ_2M 0x200000UL #define SZ_16M 0x1000000UL #define IMAGE_OFFSET_FIXUP 0x80000ULL int tb_image_setup(uintptr_t image, uintptr_t mem_base, uint32 mem_size, struct tb_image *img) { struct Image_header *ih = (struct Image_header *)image; uint64_t image_size; uint64_t text_offset; uintptr_t dst; 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 = IMAGE_OFFSET_FIXUP; } else { image_size = le64_to_cpu(ih->image_size); text_offset = le64_to_cpu(ih->text_offset); } if (image_size > mem_size) return -1; /* * 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)) dst = image - text_offset; else dst = mem_base; /* the whole image, header included, sits here, and code0 at its * start is the first instruction executed */ img->load = ((dst + SZ_2M - 1) & ~(uintptr_t)(SZ_2M - 1)) + text_offset; img->ep = img->load; img->size = image_size; if (dst + image_size > mem_base + mem_size) return -1; return 0; }