Commit | Line | Data |
---|---|---|
5db28905 TR |
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> | |
28085764 MY |
14 | #include <linux/kernel.h> |
15 | #include <linux/sizes.h> | |
5db28905 TR |
16 | |
17 | DECLARE_GLOBAL_DATA_PTR; | |
18 | ||
19 | /* See Documentation/arm64/booting.txt in the Linux kernel */ | |
20 | struct Image_header { | |
21 | uint32_t code0; /* Executable code */ | |
22 | uint32_t code1; /* Executable code */ | |
23 | uint64_t text_offset; /* Image load offset, LE */ | |
24 | uint64_t image_size; /* Effective Image size, LE */ | |
28085764 | 25 | uint64_t flags; /* Kernel flags, LE */ |
5db28905 TR |
26 | uint64_t res2; /* reserved */ |
27 | uint64_t res3; /* reserved */ | |
28 | uint64_t res4; /* reserved */ | |
29 | uint32_t magic; /* Magic number */ | |
30 | uint32_t res5; | |
31 | }; | |
32 | ||
33 | #define LINUX_ARM64_IMAGE_MAGIC 0x644d5241 | |
34 | ||
35 | static int booti_setup(bootm_headers_t *images) | |
36 | { | |
37 | struct Image_header *ih; | |
38 | uint64_t dst; | |
28085764 | 39 | uint64_t image_size, text_offset; |
5db28905 TR |
40 | |
41 | ih = (struct Image_header *)map_sysmem(images->ep, 0); | |
42 | ||
43 | if (ih->magic != le32_to_cpu(LINUX_ARM64_IMAGE_MAGIC)) { | |
44 | puts("Bad Linux ARM64 Image magic!\n"); | |
45 | return 1; | |
46 | } | |
28085764 MY |
47 | |
48 | /* | |
49 | * Prior to Linux commit a2c1d73b94ed, the text_offset field | |
50 | * is of unknown endianness. In these cases, the image_size | |
51 | * field is zero, and we can assume a fixed value of 0x80000. | |
52 | */ | |
5db28905 TR |
53 | if (ih->image_size == 0) { |
54 | puts("Image lacks image_size field, assuming 16MiB\n"); | |
55 | image_size = 16 << 20; | |
28085764 | 56 | text_offset = 0x80000; |
5db28905 TR |
57 | } else { |
58 | image_size = le64_to_cpu(ih->image_size); | |
28085764 | 59 | text_offset = le64_to_cpu(ih->text_offset); |
5db28905 TR |
60 | } |
61 | ||
62 | /* | |
28085764 MY |
63 | * If bit 3 of the flags field is set, the 2MB aligned base of the |
64 | * kernel image can be anywhere in physical memory, so respect | |
65 | * images->ep. Otherwise, relocate the image to the base of RAM | |
66 | * since memory below it is not accessible via the linear mapping. | |
5db28905 | 67 | */ |
28085764 MY |
68 | if (le64_to_cpu(ih->flags) & BIT(3)) |
69 | dst = images->ep - text_offset; | |
70 | else | |
71 | dst = gd->bd->bi_dram[0].start; | |
72 | ||
73 | dst = ALIGN(dst, SZ_2M) + text_offset; | |
5db28905 TR |
74 | |
75 | unmap_sysmem(ih); | |
76 | ||
77 | if (images->ep != dst) { | |
78 | void *src; | |
79 | ||
80 | debug("Moving Image from 0x%lx to 0x%llx\n", images->ep, dst); | |
81 | ||
82 | src = (void *)images->ep; | |
83 | images->ep = dst; | |
84 | memmove((void *)dst, src, image_size); | |
85 | } | |
86 | ||
87 | return 0; | |
88 | } | |
89 | ||
90 | /* | |
91 | * Image booting support | |
92 | */ | |
93 | static int booti_start(cmd_tbl_t *cmdtp, int flag, int argc, | |
94 | char * const argv[], bootm_headers_t *images) | |
95 | { | |
96 | int ret; | |
97 | struct Image_header *ih; | |
98 | ||
99 | ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START, | |
100 | images, 1); | |
101 | ||
102 | /* Setup Linux kernel Image entry point */ | |
103 | if (!argc) { | |
104 | images->ep = load_addr; | |
105 | debug("* kernel: default image load address = 0x%08lx\n", | |
106 | load_addr); | |
107 | } else { | |
108 | images->ep = simple_strtoul(argv[0], NULL, 16); | |
109 | debug("* kernel: cmdline image address = 0x%08lx\n", | |
110 | images->ep); | |
111 | } | |
112 | ||
113 | ret = booti_setup(images); | |
114 | if (ret != 0) | |
115 | return 1; | |
116 | ||
117 | ih = (struct Image_header *)map_sysmem(images->ep, 0); | |
118 | ||
119 | lmb_reserve(&images->lmb, images->ep, le32_to_cpu(ih->image_size)); | |
120 | ||
121 | unmap_sysmem(ih); | |
122 | ||
123 | /* | |
124 | * Handle the BOOTM_STATE_FINDOTHER state ourselves as we do not | |
125 | * have a header that provide this informaiton. | |
126 | */ | |
127 | if (bootm_find_images(flag, argc, argv)) | |
128 | return 1; | |
129 | ||
130 | return 0; | |
131 | } | |
132 | ||
133 | int do_booti(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
134 | { | |
135 | int ret; | |
136 | ||
137 | /* Consume 'booti' */ | |
138 | argc--; argv++; | |
139 | ||
140 | if (booti_start(cmdtp, flag, argc, argv, &images)) | |
141 | return 1; | |
142 | ||
143 | /* | |
144 | * We are doing the BOOTM_STATE_LOADOS state ourselves, so must | |
145 | * disable interrupts ourselves | |
146 | */ | |
147 | bootm_disable_interrupts(); | |
148 | ||
149 | images.os.os = IH_OS_LINUX; | |
0fff19a6 | 150 | images.os.arch = IH_ARCH_ARM64; |
5db28905 | 151 | ret = do_bootm_states(cmdtp, flag, argc, argv, |
4943dc2f CS |
152 | #ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH |
153 | BOOTM_STATE_RAMDISK | | |
154 | #endif | |
5db28905 TR |
155 | BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | |
156 | BOOTM_STATE_OS_GO, | |
157 | &images, 1); | |
158 | ||
159 | return ret; | |
160 | } | |
161 | ||
162 | #ifdef CONFIG_SYS_LONGHELP | |
163 | static char booti_help_text[] = | |
164 | "[addr [initrd[:size]] [fdt]]\n" | |
165 | " - boot arm64 Linux Image stored in memory\n" | |
166 | "\tThe argument 'initrd' is optional and specifies the address\n" | |
167 | "\tof an initrd in memory. The optional parameter ':size' allows\n" | |
168 | "\tspecifying the size of a RAW initrd.\n" | |
169 | #if defined(CONFIG_OF_LIBFDT) | |
170 | "\tSince booting a Linux kernel requires a flat device-tree, a\n" | |
171 | "\tthird argument providing the address of the device-tree blob\n" | |
172 | "\tis required. To boot a kernel with a device-tree blob but\n" | |
173 | "\twithout an initrd image, use a '-' for the initrd argument.\n" | |
174 | #endif | |
175 | ""; | |
176 | #endif | |
177 | ||
178 | U_BOOT_CMD( | |
179 | booti, CONFIG_SYS_MAXARGS, 1, do_booti, | |
180 | "boot arm64 Linux Image image from memory", booti_help_text | |
181 | ); |