1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 26808ef9aSBin Chen /* 36808ef9aSBin Chen * (C) Copyright 2000-2009 46808ef9aSBin Chen * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 56808ef9aSBin Chen */ 66808ef9aSBin Chen 76808ef9aSBin Chen #include <common.h> 86808ef9aSBin Chen #include <mapmem.h> 96808ef9aSBin Chen #include <linux/sizes.h> 106808ef9aSBin Chen 116808ef9aSBin Chen DECLARE_GLOBAL_DATA_PTR; 126808ef9aSBin Chen 136808ef9aSBin Chen #define LINUX_ARM64_IMAGE_MAGIC 0x644d5241 146808ef9aSBin Chen 156808ef9aSBin Chen /* See Documentation/arm64/booting.txt in the Linux kernel */ 166808ef9aSBin Chen struct Image_header { 176808ef9aSBin Chen uint32_t code0; /* Executable code */ 186808ef9aSBin Chen uint32_t code1; /* Executable code */ 196808ef9aSBin Chen uint64_t text_offset; /* Image load offset, LE */ 206808ef9aSBin Chen uint64_t image_size; /* Effective Image size, LE */ 216808ef9aSBin Chen uint64_t flags; /* Kernel flags, LE */ 226808ef9aSBin Chen uint64_t res2; /* reserved */ 236808ef9aSBin Chen uint64_t res3; /* reserved */ 246808ef9aSBin Chen uint64_t res4; /* reserved */ 256808ef9aSBin Chen uint32_t magic; /* Magic number */ 266808ef9aSBin Chen uint32_t res5; 276808ef9aSBin Chen }; 286808ef9aSBin Chen 296808ef9aSBin Chen int booti_setup(ulong image, ulong *relocated_addr, ulong *size) 306808ef9aSBin Chen { 316808ef9aSBin Chen struct Image_header *ih; 326808ef9aSBin Chen uint64_t dst; 336808ef9aSBin Chen uint64_t image_size, text_offset; 346808ef9aSBin Chen 356808ef9aSBin Chen *relocated_addr = image; 366808ef9aSBin Chen 376808ef9aSBin Chen ih = (struct Image_header *)map_sysmem(image, 0); 386808ef9aSBin Chen 396808ef9aSBin Chen if (ih->magic != le32_to_cpu(LINUX_ARM64_IMAGE_MAGIC)) { 406808ef9aSBin Chen puts("Bad Linux ARM64 Image magic!\n"); 416808ef9aSBin Chen return 1; 426808ef9aSBin Chen } 436808ef9aSBin Chen 446808ef9aSBin Chen /* 456808ef9aSBin Chen * Prior to Linux commit a2c1d73b94ed, the text_offset field 466808ef9aSBin Chen * is of unknown endianness. In these cases, the image_size 476808ef9aSBin Chen * field is zero, and we can assume a fixed value of 0x80000. 486808ef9aSBin Chen */ 496808ef9aSBin Chen if (ih->image_size == 0) { 506808ef9aSBin Chen puts("Image lacks image_size field, assuming 16MiB\n"); 516808ef9aSBin Chen image_size = 16 << 20; 526808ef9aSBin Chen text_offset = 0x80000; 536808ef9aSBin Chen } else { 546808ef9aSBin Chen image_size = le64_to_cpu(ih->image_size); 556808ef9aSBin Chen text_offset = le64_to_cpu(ih->text_offset); 566808ef9aSBin Chen } 576808ef9aSBin Chen 586808ef9aSBin Chen *size = image_size; 596808ef9aSBin Chen 606808ef9aSBin Chen /* 616808ef9aSBin Chen * If bit 3 of the flags field is set, the 2MB aligned base of the 626808ef9aSBin Chen * kernel image can be anywhere in physical memory, so respect 636808ef9aSBin Chen * images->ep. Otherwise, relocate the image to the base of RAM 646808ef9aSBin Chen * since memory below it is not accessible via the linear mapping. 656808ef9aSBin Chen */ 666808ef9aSBin Chen if (le64_to_cpu(ih->flags) & BIT(3)) 676808ef9aSBin Chen dst = image - text_offset; 686808ef9aSBin Chen else 696808ef9aSBin Chen dst = gd->bd->bi_dram[0].start; 706808ef9aSBin Chen 716808ef9aSBin Chen *relocated_addr = ALIGN(dst, SZ_2M) + text_offset; 726808ef9aSBin Chen 736808ef9aSBin Chen unmap_sysmem(ih); 746808ef9aSBin Chen 756808ef9aSBin Chen return 0; 766808ef9aSBin Chen } 77