1 /* 2 * (C) Copyright 2000-2009 3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <bootm.h> 10 #include <command.h> 11 #include <image.h> 12 #include <lmb.h> 13 #include <mapmem.h> 14 15 DECLARE_GLOBAL_DATA_PTR; 16 17 /* See Documentation/arm64/booting.txt in the Linux kernel */ 18 struct Image_header { 19 uint32_t code0; /* Executable code */ 20 uint32_t code1; /* Executable code */ 21 uint64_t text_offset; /* Image load offset, LE */ 22 uint64_t image_size; /* Effective Image size, LE */ 23 uint64_t res1; /* reserved */ 24 uint64_t res2; /* reserved */ 25 uint64_t res3; /* reserved */ 26 uint64_t res4; /* reserved */ 27 uint32_t magic; /* Magic number */ 28 uint32_t res5; 29 }; 30 31 #define LINUX_ARM64_IMAGE_MAGIC 0x644d5241 32 33 static int booti_setup(bootm_headers_t *images) 34 { 35 struct Image_header *ih; 36 uint64_t dst; 37 uint64_t image_size; 38 39 ih = (struct Image_header *)map_sysmem(images->ep, 0); 40 41 if (ih->magic != le32_to_cpu(LINUX_ARM64_IMAGE_MAGIC)) { 42 puts("Bad Linux ARM64 Image magic!\n"); 43 return 1; 44 } 45 46 if (ih->image_size == 0) { 47 puts("Image lacks image_size field, assuming 16MiB\n"); 48 image_size = 16 << 20; 49 } else { 50 image_size = le64_to_cpu(ih->image_size); 51 } 52 53 /* 54 * If we are not at the correct run-time location, set the new 55 * correct location and then move the image there. 56 */ 57 dst = gd->bd->bi_dram[0].start + le64_to_cpu(ih->text_offset); 58 59 unmap_sysmem(ih); 60 61 if (images->ep != dst) { 62 void *src; 63 64 debug("Moving Image from 0x%lx to 0x%llx\n", images->ep, dst); 65 66 src = (void *)images->ep; 67 images->ep = dst; 68 memmove((void *)dst, src, image_size); 69 } 70 71 return 0; 72 } 73 74 /* 75 * Image booting support 76 */ 77 static int booti_start(cmd_tbl_t *cmdtp, int flag, int argc, 78 char * const argv[], bootm_headers_t *images) 79 { 80 int ret; 81 struct Image_header *ih; 82 83 ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START, 84 images, 1); 85 86 /* Setup Linux kernel Image entry point */ 87 if (!argc) { 88 images->ep = load_addr; 89 debug("* kernel: default image load address = 0x%08lx\n", 90 load_addr); 91 } else { 92 images->ep = simple_strtoul(argv[0], NULL, 16); 93 debug("* kernel: cmdline image address = 0x%08lx\n", 94 images->ep); 95 } 96 97 ret = booti_setup(images); 98 if (ret != 0) 99 return 1; 100 101 ih = (struct Image_header *)map_sysmem(images->ep, 0); 102 103 lmb_reserve(&images->lmb, images->ep, le32_to_cpu(ih->image_size)); 104 105 unmap_sysmem(ih); 106 107 /* 108 * Handle the BOOTM_STATE_FINDOTHER state ourselves as we do not 109 * have a header that provide this informaiton. 110 */ 111 if (bootm_find_images(flag, argc, argv)) 112 return 1; 113 114 return 0; 115 } 116 117 int do_booti(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 118 { 119 int ret; 120 121 /* Consume 'booti' */ 122 argc--; argv++; 123 124 if (booti_start(cmdtp, flag, argc, argv, &images)) 125 return 1; 126 127 /* 128 * We are doing the BOOTM_STATE_LOADOS state ourselves, so must 129 * disable interrupts ourselves 130 */ 131 bootm_disable_interrupts(); 132 133 images.os.os = IH_OS_LINUX; 134 ret = do_bootm_states(cmdtp, flag, argc, argv, 135 #ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH 136 BOOTM_STATE_RAMDISK | 137 #endif 138 BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | 139 BOOTM_STATE_OS_GO, 140 &images, 1); 141 142 return ret; 143 } 144 145 #ifdef CONFIG_SYS_LONGHELP 146 static char booti_help_text[] = 147 "[addr [initrd[:size]] [fdt]]\n" 148 " - boot arm64 Linux Image stored in memory\n" 149 "\tThe argument 'initrd' is optional and specifies the address\n" 150 "\tof an initrd in memory. The optional parameter ':size' allows\n" 151 "\tspecifying the size of a RAW initrd.\n" 152 #if defined(CONFIG_OF_LIBFDT) 153 "\tSince booting a Linux kernel requires a flat device-tree, a\n" 154 "\tthird argument providing the address of the device-tree blob\n" 155 "\tis required. To boot a kernel with a device-tree blob but\n" 156 "\twithout an initrd image, use a '-' for the initrd argument.\n" 157 #endif 158 ""; 159 #endif 160 161 U_BOOT_CMD( 162 booti, CONFIG_SYS_MAXARGS, 1, do_booti, 163 "boot arm64 Linux Image image from memory", booti_help_text 164 ); 165