summaryrefslogtreecommitdiff
path: root/common/image.c
diff options
context:
space:
mode:
authorBradley Morgan <brads@mainlining.org>2026-10-03 18:57:38 +0000
committerBradley Morgan <brads@mainlining.org>2026-10-03 18:57:38 +0000
commit00fc82f17cff9295387d516384ecdc443acb1b22 (patch)
tree798bef0185878286028fe0eaf7594616a66903e4 /common/image.c
parent7e8514efb64774b6a635b87ae945e519a7c38551 (diff)
tashaboot: arm64 bringup, semihosting payload loader
consoles on the pl011 the dtb points at, walks the memory node and chosen, loads an arm64 kernel Image over semihosting and jumps to it with the documented register state. string functions, printf and libfdt are vendored from lk (lk2nd) and u-boot so the libc surface is the one those projects already proved. built and booted on qemu virt, payload exits clean through semihosting.
Diffstat (limited to 'common/image.c')
-rw-r--r--common/image.c66
1 files changed, 66 insertions, 0 deletions
diff --git a/common/image.c b/common/image.c
new file mode 100644
index 0000000..d114c6a
--- /dev/null
+++ b/common/image.c
@@ -0,0 +1,66 @@
+/* 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 <brads@mainlining.org>
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <stdint.h>
+#include <boot.h>
+#include <endian.h>
+
+#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;
+}