1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2000-2009
3*4882a593Smuzhiyun * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #ifndef USE_HOSTCC
9*4882a593Smuzhiyun #include <common.h>
10*4882a593Smuzhiyun #include <bootstage.h>
11*4882a593Smuzhiyun #include <bzlib.h>
12*4882a593Smuzhiyun #include <errno.h>
13*4882a593Smuzhiyun #include <fdt_support.h>
14*4882a593Smuzhiyun #include <lmb.h>
15*4882a593Smuzhiyun #include <malloc.h>
16*4882a593Smuzhiyun #include <mapmem.h>
17*4882a593Smuzhiyun #include <asm/io.h>
18*4882a593Smuzhiyun #include <linux/lzo.h>
19*4882a593Smuzhiyun #include <lzma/LzmaTypes.h>
20*4882a593Smuzhiyun #include <lzma/LzmaDec.h>
21*4882a593Smuzhiyun #include <lzma/LzmaTools.h>
22*4882a593Smuzhiyun #if defined(CONFIG_CMD_USB)
23*4882a593Smuzhiyun #include <usb.h>
24*4882a593Smuzhiyun #endif
25*4882a593Smuzhiyun #else
26*4882a593Smuzhiyun #include "mkimage.h"
27*4882a593Smuzhiyun #endif
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #include <command.h>
30*4882a593Smuzhiyun #include <bootm.h>
31*4882a593Smuzhiyun #include <image.h>
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #ifdef USE_HOSTCC
34*4882a593Smuzhiyun #define CONFIG_SYS_BOOTM_LEN 0x10000000
35*4882a593Smuzhiyun #endif
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #ifndef CONFIG_SYS_BOOTM_LEN
38*4882a593Smuzhiyun /* use 8MByte as default max gunzip size */
39*4882a593Smuzhiyun #define CONFIG_SYS_BOOTM_LEN 0x800000
40*4882a593Smuzhiyun #endif
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun #define IH_INITRD_ARCH IH_ARCH_DEFAULT
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #ifndef USE_HOSTCC
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun bootm_headers_t images; /* pointers to os/initrd/fdt images */
49*4882a593Smuzhiyun
board_do_bootm(int argc,char * const argv[])50*4882a593Smuzhiyun __weak int board_do_bootm(int argc, char * const argv[])
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun return 0;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
bootm_board_start(void)55*4882a593Smuzhiyun __weak int bootm_board_start(void)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun return 0;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,
61*4882a593Smuzhiyun char * const argv[], bootm_headers_t *images,
62*4882a593Smuzhiyun ulong *os_data, ulong *os_len);
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun #ifdef CONFIG_LMB
boot_start_lmb(bootm_headers_t * images)65*4882a593Smuzhiyun static void boot_start_lmb(bootm_headers_t *images)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun lmb_init(&images->lmb);
69*4882a593Smuzhiyun #ifdef CONFIG_NR_DRAM_BANKS
70*4882a593Smuzhiyun int i;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
73*4882a593Smuzhiyun lmb_add(&images->lmb, gd->bd->bi_dram[i].start,
74*4882a593Smuzhiyun gd->bd->bi_dram[i].size);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun #else
77*4882a593Smuzhiyun ulong mem_start;
78*4882a593Smuzhiyun phys_size_t mem_size;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun mem_start = env_get_bootm_low();
81*4882a593Smuzhiyun mem_size = env_get_bootm_size();
82*4882a593Smuzhiyun lmb_add(&images->lmb, (phys_addr_t)mem_start, mem_size);
83*4882a593Smuzhiyun #endif
84*4882a593Smuzhiyun arch_lmb_reserve(&images->lmb);
85*4882a593Smuzhiyun board_lmb_reserve(&images->lmb);
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun #else
88*4882a593Smuzhiyun #define lmb_reserve(lmb, base, size)
boot_start_lmb(bootm_headers_t * images)89*4882a593Smuzhiyun static inline void boot_start_lmb(bootm_headers_t *images) { }
90*4882a593Smuzhiyun #endif
91*4882a593Smuzhiyun
bootm_start(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])92*4882a593Smuzhiyun static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc,
93*4882a593Smuzhiyun char * const argv[])
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun memset((void *)&images, 0, sizeof(images));
96*4882a593Smuzhiyun images.verify = env_get_yesno("verify");
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun boot_start_lmb(&images);
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun bootstage_mark_name(BOOTSTAGE_ID_BOOTM_START, "bootm_start");
101*4882a593Smuzhiyun images.state = BOOTM_STATE_START;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun return bootm_board_start();
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
bootm_find_os(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])106*4882a593Smuzhiyun static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
107*4882a593Smuzhiyun char * const argv[])
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun const void *os_hdr;
110*4882a593Smuzhiyun bool ep_found = false;
111*4882a593Smuzhiyun int ret;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun /* get kernel image header, start address and length */
114*4882a593Smuzhiyun os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
115*4882a593Smuzhiyun &images, &images.os.image_start, &images.os.image_len);
116*4882a593Smuzhiyun if (images.os.image_len == 0) {
117*4882a593Smuzhiyun puts("ERROR: can't get kernel image!\n");
118*4882a593Smuzhiyun return 1;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun /* get image parameters */
122*4882a593Smuzhiyun switch (genimg_get_format(os_hdr)) {
123*4882a593Smuzhiyun #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
124*4882a593Smuzhiyun case IMAGE_FORMAT_LEGACY:
125*4882a593Smuzhiyun images.os.type = image_get_type(os_hdr);
126*4882a593Smuzhiyun images.os.comp = image_get_comp(os_hdr);
127*4882a593Smuzhiyun images.os.os = image_get_os(os_hdr);
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun images.os.end = image_get_image_end(os_hdr);
130*4882a593Smuzhiyun images.os.load = image_get_load(os_hdr);
131*4882a593Smuzhiyun images.os.arch = image_get_arch(os_hdr);
132*4882a593Smuzhiyun break;
133*4882a593Smuzhiyun #endif
134*4882a593Smuzhiyun #if IMAGE_ENABLE_FIT
135*4882a593Smuzhiyun case IMAGE_FORMAT_FIT:
136*4882a593Smuzhiyun if (fit_image_get_type(images.fit_hdr_os,
137*4882a593Smuzhiyun images.fit_noffset_os,
138*4882a593Smuzhiyun &images.os.type)) {
139*4882a593Smuzhiyun puts("Can't get image type!\n");
140*4882a593Smuzhiyun bootstage_error(BOOTSTAGE_ID_FIT_TYPE);
141*4882a593Smuzhiyun return 1;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun if (fit_image_get_comp(images.fit_hdr_os,
145*4882a593Smuzhiyun images.fit_noffset_os,
146*4882a593Smuzhiyun &images.os.comp)) {
147*4882a593Smuzhiyun puts("Can't get image compression!\n");
148*4882a593Smuzhiyun bootstage_error(BOOTSTAGE_ID_FIT_COMPRESSION);
149*4882a593Smuzhiyun return 1;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun if (fit_image_get_os(images.fit_hdr_os, images.fit_noffset_os,
153*4882a593Smuzhiyun &images.os.os)) {
154*4882a593Smuzhiyun puts("Can't get image OS!\n");
155*4882a593Smuzhiyun bootstage_error(BOOTSTAGE_ID_FIT_OS);
156*4882a593Smuzhiyun return 1;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun if (fit_image_get_arch(images.fit_hdr_os,
160*4882a593Smuzhiyun images.fit_noffset_os,
161*4882a593Smuzhiyun &images.os.arch)) {
162*4882a593Smuzhiyun puts("Can't get image ARCH!\n");
163*4882a593Smuzhiyun return 1;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun images.os.end = fit_get_end(images.fit_hdr_os);
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun if (fit_image_get_load(images.fit_hdr_os, images.fit_noffset_os,
169*4882a593Smuzhiyun &images.os.load)) {
170*4882a593Smuzhiyun puts("Can't get image load address!\n");
171*4882a593Smuzhiyun bootstage_error(BOOTSTAGE_ID_FIT_LOADADDR);
172*4882a593Smuzhiyun return 1;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun break;
175*4882a593Smuzhiyun #endif
176*4882a593Smuzhiyun #ifdef CONFIG_ANDROID_BOOT_IMAGE
177*4882a593Smuzhiyun case IMAGE_FORMAT_ANDROID:
178*4882a593Smuzhiyun images.os.type = IH_TYPE_KERNEL;
179*4882a593Smuzhiyun images.os.comp = android_image_get_comp(os_hdr);
180*4882a593Smuzhiyun images.os.os = IH_OS_LINUX;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun images.os.end = android_image_get_end(os_hdr);
183*4882a593Smuzhiyun images.os.load = android_image_get_kload(os_hdr);
184*4882a593Smuzhiyun images.ep = images.os.load;
185*4882a593Smuzhiyun ep_found = true;
186*4882a593Smuzhiyun break;
187*4882a593Smuzhiyun #endif
188*4882a593Smuzhiyun default:
189*4882a593Smuzhiyun puts("ERROR: unknown image format type!\n");
190*4882a593Smuzhiyun return 1;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun /* If we have a valid setup.bin, we will use that for entry (x86) */
194*4882a593Smuzhiyun if (images.os.arch == IH_ARCH_I386 ||
195*4882a593Smuzhiyun images.os.arch == IH_ARCH_X86_64) {
196*4882a593Smuzhiyun ulong len;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun ret = boot_get_setup(&images, IH_ARCH_I386, &images.ep, &len);
199*4882a593Smuzhiyun if (ret < 0 && ret != -ENOENT) {
200*4882a593Smuzhiyun puts("Could not find a valid setup.bin for x86\n");
201*4882a593Smuzhiyun return 1;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun /* Kernel entry point is the setup.bin */
204*4882a593Smuzhiyun } else if (images.legacy_hdr_valid) {
205*4882a593Smuzhiyun images.ep = image_get_ep(&images.legacy_hdr_os_copy);
206*4882a593Smuzhiyun #if IMAGE_ENABLE_FIT
207*4882a593Smuzhiyun } else if (images.fit_uname_os) {
208*4882a593Smuzhiyun int ret;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun ret = fit_image_get_entry(images.fit_hdr_os,
211*4882a593Smuzhiyun images.fit_noffset_os, &images.ep);
212*4882a593Smuzhiyun if (ret) {
213*4882a593Smuzhiyun puts("Can't get entry point property!\n");
214*4882a593Smuzhiyun return 1;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun #endif
217*4882a593Smuzhiyun } else if (!ep_found) {
218*4882a593Smuzhiyun puts("Could not find kernel entry point!\n");
219*4882a593Smuzhiyun return 1;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun if (images.os.type == IH_TYPE_KERNEL_NOLOAD) {
223*4882a593Smuzhiyun images.os.load = images.os.image_start;
224*4882a593Smuzhiyun images.ep += images.os.load;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun images.os.start = map_to_sysmem(os_hdr);
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun return 0;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun /**
233*4882a593Smuzhiyun * bootm_find_images - wrapper to find and locate various images
234*4882a593Smuzhiyun * @flag: Ignored Argument
235*4882a593Smuzhiyun * @argc: command argument count
236*4882a593Smuzhiyun * @argv: command argument list
237*4882a593Smuzhiyun *
238*4882a593Smuzhiyun * boot_find_images() will attempt to load an available ramdisk,
239*4882a593Smuzhiyun * flattened device tree, as well as specifically marked
240*4882a593Smuzhiyun * "loadable" images (loadables are FIT only)
241*4882a593Smuzhiyun *
242*4882a593Smuzhiyun * Note: bootm_find_images will skip an image if it is not found
243*4882a593Smuzhiyun *
244*4882a593Smuzhiyun * @return:
245*4882a593Smuzhiyun * 0, if all existing images were loaded correctly
246*4882a593Smuzhiyun * 1, if an image is found but corrupted, or invalid
247*4882a593Smuzhiyun */
bootm_find_images(int flag,int argc,char * const argv[])248*4882a593Smuzhiyun int bootm_find_images(int flag, int argc, char * const argv[])
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun int ret;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun /* find ramdisk */
253*4882a593Smuzhiyun ret = boot_get_ramdisk(argc, argv, &images, IH_INITRD_ARCH,
254*4882a593Smuzhiyun &images.rd_start, &images.rd_end);
255*4882a593Smuzhiyun if (ret) {
256*4882a593Smuzhiyun puts("Ramdisk image is corrupt or invalid\n");
257*4882a593Smuzhiyun return 1;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun #if IMAGE_ENABLE_OF_LIBFDT
261*4882a593Smuzhiyun /* find flattened device tree */
262*4882a593Smuzhiyun ret = boot_get_fdt(flag, argc, argv, IH_ARCH_DEFAULT, &images,
263*4882a593Smuzhiyun &images.ft_addr, &images.ft_len);
264*4882a593Smuzhiyun if (ret) {
265*4882a593Smuzhiyun puts("Could not find a valid device tree\n");
266*4882a593Smuzhiyun return 1;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun #ifdef CONFIG_CMD_FDT
269*4882a593Smuzhiyun set_working_fdt_addr((ulong)images.ft_addr);
270*4882a593Smuzhiyun #endif
271*4882a593Smuzhiyun lmb_reserve(&images.lmb, (ulong)images.ft_addr, (ulong)images.ft_len);
272*4882a593Smuzhiyun #endif
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun #if IMAGE_ENABLE_FIT
275*4882a593Smuzhiyun #if defined(CONFIG_FPGA) && defined(CONFIG_FPGA_XILINX)
276*4882a593Smuzhiyun /* find bitstreams */
277*4882a593Smuzhiyun ret = boot_get_fpga(argc, argv, &images, IH_ARCH_DEFAULT,
278*4882a593Smuzhiyun NULL, NULL);
279*4882a593Smuzhiyun if (ret) {
280*4882a593Smuzhiyun printf("FPGA image is corrupted or invalid\n");
281*4882a593Smuzhiyun return 1;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun #endif
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun /* find all of the loadables */
286*4882a593Smuzhiyun ret = boot_get_loadable(argc, argv, &images, IH_ARCH_DEFAULT,
287*4882a593Smuzhiyun NULL, NULL);
288*4882a593Smuzhiyun if (ret) {
289*4882a593Smuzhiyun printf("Loadable(s) is corrupt or invalid\n");
290*4882a593Smuzhiyun return 1;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun #endif
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun return 0;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun
bootm_find_other(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])297*4882a593Smuzhiyun static int bootm_find_other(cmd_tbl_t *cmdtp, int flag, int argc,
298*4882a593Smuzhiyun char * const argv[])
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun if (((images.os.type == IH_TYPE_KERNEL) ||
301*4882a593Smuzhiyun (images.os.type == IH_TYPE_KERNEL_NOLOAD) ||
302*4882a593Smuzhiyun (images.os.type == IH_TYPE_MULTI)) &&
303*4882a593Smuzhiyun (images.os.os == IH_OS_LINUX ||
304*4882a593Smuzhiyun images.os.os == IH_OS_VXWORKS))
305*4882a593Smuzhiyun return bootm_find_images(flag, argc, argv);
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun return 0;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun #endif /* USE_HOSTC */
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun /**
312*4882a593Smuzhiyun * print_decomp_msg() - Print a suitable decompression/loading message
313*4882a593Smuzhiyun *
314*4882a593Smuzhiyun * @type: OS type (IH_OS_...)
315*4882a593Smuzhiyun * @comp_type: Compression type being used (IH_COMP_...)
316*4882a593Smuzhiyun * @is_xip: true if the load address matches the image start
317*4882a593Smuzhiyun */
print_decomp_msg(int comp_type,int type,bool is_xip,ulong src,ulong dst)318*4882a593Smuzhiyun static void print_decomp_msg(int comp_type, int type, bool is_xip,
319*4882a593Smuzhiyun ulong src, ulong dst)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun const char *name = genimg_get_type_name(type);
322*4882a593Smuzhiyun const char *comp_name[] = {
323*4882a593Smuzhiyun [IH_COMP_NONE] = "",
324*4882a593Smuzhiyun [IH_COMP_GZIP] = "GZIP",
325*4882a593Smuzhiyun [IH_COMP_BZIP2] = "BZIP2",
326*4882a593Smuzhiyun [IH_COMP_LZMA] = "LZMA",
327*4882a593Smuzhiyun [IH_COMP_LZO] = "LZO",
328*4882a593Smuzhiyun [IH_COMP_LZ4] = "LZ4",
329*4882a593Smuzhiyun [IH_COMP_ZIMAGE]= "ZIMAGE",
330*4882a593Smuzhiyun };
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun if (comp_type == IH_COMP_NONE)
333*4882a593Smuzhiyun printf(" %s %s from 0x%08lx to 0x%08lx ... ",
334*4882a593Smuzhiyun is_xip ? "XIP" : "Loading", name, src, dst);
335*4882a593Smuzhiyun else
336*4882a593Smuzhiyun printf(" Uncompressing %s %s from 0x%08lx to 0x%08lx ... ",
337*4882a593Smuzhiyun comp_name[comp_type], name, src, dst);
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun /**
341*4882a593Smuzhiyun * handle_decomp_error() - display a decompression error
342*4882a593Smuzhiyun *
343*4882a593Smuzhiyun * This function tries to produce a useful message. In the case where the
344*4882a593Smuzhiyun * uncompressed size is the same as the available space, we can assume that
345*4882a593Smuzhiyun * the image is too large for the buffer.
346*4882a593Smuzhiyun *
347*4882a593Smuzhiyun * @comp_type: Compression type being used (IH_COMP_...)
348*4882a593Smuzhiyun * @uncomp_size: Number of bytes uncompressed
349*4882a593Smuzhiyun * @unc_len: Amount of space available for decompression
350*4882a593Smuzhiyun * @ret: Error code to report
351*4882a593Smuzhiyun * @return BOOTM_ERR_RESET, indicating that the board must be reset
352*4882a593Smuzhiyun */
handle_decomp_error(int comp_type,size_t uncomp_size,size_t unc_len,int ret)353*4882a593Smuzhiyun static int handle_decomp_error(int comp_type, size_t uncomp_size,
354*4882a593Smuzhiyun size_t unc_len, int ret)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun const char *name = genimg_get_comp_name(comp_type);
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun if (uncomp_size >= unc_len)
359*4882a593Smuzhiyun printf("Image too large(0x%lx >= 0x%lx): increase CONFIG_SYS_BOOTM_LEN\n",
360*4882a593Smuzhiyun (ulong)uncomp_size, (ulong)unc_len);
361*4882a593Smuzhiyun else
362*4882a593Smuzhiyun printf("%s: uncompress error %d\n", name, ret);
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun /*
365*4882a593Smuzhiyun * The decompression routines are now safe, so will not write beyond
366*4882a593Smuzhiyun * their bounds. Probably it is not necessary to reset, but maintain
367*4882a593Smuzhiyun * the current behaviour for now.
368*4882a593Smuzhiyun */
369*4882a593Smuzhiyun printf("Must RESET board to recover\n");
370*4882a593Smuzhiyun #ifndef USE_HOSTCC
371*4882a593Smuzhiyun bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE);
372*4882a593Smuzhiyun #endif
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun return BOOTM_ERR_RESET;
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun
bootm_parse_comp(const unsigned char * hdr)377*4882a593Smuzhiyun int bootm_parse_comp(const unsigned char *hdr)
378*4882a593Smuzhiyun {
379*4882a593Smuzhiyun #if defined(CONFIG_CMD_BOOTZ)
380*4882a593Smuzhiyun ulong start, end;
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun if (!bootz_setup((ulong)hdr, &start, &end))
383*4882a593Smuzhiyun return IH_COMP_ZIMAGE;
384*4882a593Smuzhiyun #endif
385*4882a593Smuzhiyun #if defined(CONFIG_LZ4)
386*4882a593Smuzhiyun if (lz4_is_valid_header(hdr))
387*4882a593Smuzhiyun return IH_COMP_LZ4;
388*4882a593Smuzhiyun #endif
389*4882a593Smuzhiyun #if defined(CONFIG_LZO)
390*4882a593Smuzhiyun if (lzop_is_valid_header(hdr))
391*4882a593Smuzhiyun return IH_COMP_LZO;
392*4882a593Smuzhiyun #endif
393*4882a593Smuzhiyun #if defined(CONFIG_GZIP)
394*4882a593Smuzhiyun if (gzip_parse_header(hdr, 0xffff) > 0)
395*4882a593Smuzhiyun return IH_COMP_GZIP;
396*4882a593Smuzhiyun #endif
397*4882a593Smuzhiyun #if defined(CONFIG_BZIP2)
398*4882a593Smuzhiyun if ((hdr[0] == 'B') && (hdr[1] == 'Z') && (hdr[2] == 'h'))
399*4882a593Smuzhiyun return IH_COMP_BZIP2;
400*4882a593Smuzhiyun #endif
401*4882a593Smuzhiyun #if defined(CONFIG_LZMA)
402*4882a593Smuzhiyun if (lzma_is_valid(hdr))
403*4882a593Smuzhiyun return IH_COMP_LZMA;
404*4882a593Smuzhiyun #endif
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun return IH_COMP_NONE;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun
bootm_decomp_image(int comp,ulong load,ulong image_start,int type,void * load_buf,void * image_buf,ulong image_len,uint unc_len,ulong * load_end)409*4882a593Smuzhiyun int bootm_decomp_image(int comp, ulong load, ulong image_start, int type,
410*4882a593Smuzhiyun void *load_buf, void *image_buf, ulong image_len,
411*4882a593Smuzhiyun uint unc_len, ulong *load_end)
412*4882a593Smuzhiyun {
413*4882a593Smuzhiyun int ret = 0;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun *load_end = load;
416*4882a593Smuzhiyun print_decomp_msg(comp, type, load == image_start,
417*4882a593Smuzhiyun (ulong)image_buf, (ulong)load_buf);
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun /*
420*4882a593Smuzhiyun * Load the image to the right place, decompressing if needed. After
421*4882a593Smuzhiyun * this, image_len will be set to the number of uncompressed bytes
422*4882a593Smuzhiyun * loaded, ret will be non-zero on error.
423*4882a593Smuzhiyun */
424*4882a593Smuzhiyun switch (comp) {
425*4882a593Smuzhiyun case IH_COMP_NONE:
426*4882a593Smuzhiyun if (load == image_start)
427*4882a593Smuzhiyun break;
428*4882a593Smuzhiyun if (image_len <= unc_len)
429*4882a593Smuzhiyun memmove_wd(load_buf, image_buf, image_len, CHUNKSZ);
430*4882a593Smuzhiyun else
431*4882a593Smuzhiyun ret = 1;
432*4882a593Smuzhiyun break;
433*4882a593Smuzhiyun #ifdef CONFIG_GZIP
434*4882a593Smuzhiyun case IH_COMP_GZIP: {
435*4882a593Smuzhiyun ret = gunzip(load_buf, unc_len, image_buf, &image_len);
436*4882a593Smuzhiyun break;
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun #endif /* CONFIG_GZIP */
439*4882a593Smuzhiyun #ifdef CONFIG_BZIP2
440*4882a593Smuzhiyun case IH_COMP_BZIP2: {
441*4882a593Smuzhiyun uint size = unc_len;
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun /*
444*4882a593Smuzhiyun * If we've got less than 4 MB of malloc() space,
445*4882a593Smuzhiyun * use slower decompression algorithm which requires
446*4882a593Smuzhiyun * at most 2300 KB of memory.
447*4882a593Smuzhiyun */
448*4882a593Smuzhiyun ret = BZ2_bzBuffToBuffDecompress(load_buf, &size,
449*4882a593Smuzhiyun image_buf, image_len,
450*4882a593Smuzhiyun CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0);
451*4882a593Smuzhiyun image_len = size;
452*4882a593Smuzhiyun break;
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun #endif /* CONFIG_BZIP2 */
455*4882a593Smuzhiyun #ifdef CONFIG_LZMA
456*4882a593Smuzhiyun case IH_COMP_LZMA: {
457*4882a593Smuzhiyun SizeT lzma_len = unc_len;
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun ret = lzmaBuffToBuffDecompress(load_buf, &lzma_len,
460*4882a593Smuzhiyun image_buf, image_len);
461*4882a593Smuzhiyun image_len = lzma_len;
462*4882a593Smuzhiyun break;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun #endif /* CONFIG_LZMA */
465*4882a593Smuzhiyun #ifdef CONFIG_LZO
466*4882a593Smuzhiyun case IH_COMP_LZO: {
467*4882a593Smuzhiyun size_t size = unc_len;
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun ret = lzop_decompress(image_buf, image_len, load_buf, &size);
470*4882a593Smuzhiyun image_len = size;
471*4882a593Smuzhiyun break;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun #endif /* CONFIG_LZO */
474*4882a593Smuzhiyun #ifdef CONFIG_LZ4
475*4882a593Smuzhiyun case IH_COMP_LZ4: {
476*4882a593Smuzhiyun size_t size = unc_len;
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun ret = ulz4fn(image_buf, image_len, load_buf, &size);
479*4882a593Smuzhiyun image_len = size;
480*4882a593Smuzhiyun break;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun #endif /* CONFIG_LZ4 */
483*4882a593Smuzhiyun default:
484*4882a593Smuzhiyun printf("Unimplemented compression type %d\n", comp);
485*4882a593Smuzhiyun return BOOTM_ERR_UNIMPLEMENTED;
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun if (ret)
489*4882a593Smuzhiyun return handle_decomp_error(comp, image_len, unc_len, ret);
490*4882a593Smuzhiyun *load_end = load + image_len;
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun if (comp == IH_COMP_NONE || comp == IH_COMP_ZIMAGE)
493*4882a593Smuzhiyun puts("OK\n");
494*4882a593Smuzhiyun else
495*4882a593Smuzhiyun printf("with %08lx bytes OK\n", image_len);
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun return 0;
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun #ifndef USE_HOSTCC
bootm_load_os(bootm_headers_t * images,unsigned long * load_end,int boot_progress)501*4882a593Smuzhiyun static int bootm_load_os(bootm_headers_t *images, unsigned long *load_end,
502*4882a593Smuzhiyun int boot_progress)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun image_info_t os = images->os;
505*4882a593Smuzhiyun ulong load = os.load;
506*4882a593Smuzhiyun ulong blob_start = os.start;
507*4882a593Smuzhiyun ulong blob_end = os.end;
508*4882a593Smuzhiyun ulong image_start = os.image_start;
509*4882a593Smuzhiyun ulong image_len = os.image_len;
510*4882a593Smuzhiyun bool no_overlap;
511*4882a593Smuzhiyun void *load_buf, *image_buf;
512*4882a593Smuzhiyun int err;
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun load_buf = map_sysmem(load, 0);
515*4882a593Smuzhiyun image_buf = map_sysmem(os.image_start, image_len);
516*4882a593Smuzhiyun err = bootm_decomp_image(os.comp, load, os.image_start, os.type,
517*4882a593Smuzhiyun load_buf, image_buf, image_len,
518*4882a593Smuzhiyun CONFIG_SYS_BOOTM_LEN, load_end);
519*4882a593Smuzhiyun if (err) {
520*4882a593Smuzhiyun bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE);
521*4882a593Smuzhiyun return err;
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun flush_cache(load, ALIGN(*load_end - load, ARCH_DMA_MINALIGN));
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun printf(" kernel loaded at 0x%08lx, end = 0x%08lx\n", load, *load_end);
526*4882a593Smuzhiyun bootstage_mark(BOOTSTAGE_ID_KERNEL_LOADED);
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun no_overlap = (os.comp == IH_COMP_NONE && load == image_start);
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun if (!no_overlap && (load < blob_end) && (*load_end > blob_start)) {
531*4882a593Smuzhiyun printf("images.os.start = 0x%lX, images.os.end = 0x%lx\n",
532*4882a593Smuzhiyun blob_start, blob_end);
533*4882a593Smuzhiyun printf("images.os.load = 0x%lx, load_end = 0x%lx\n", load,
534*4882a593Smuzhiyun *load_end);
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun /* Check what type of image this is. */
537*4882a593Smuzhiyun if (images->legacy_hdr_valid) {
538*4882a593Smuzhiyun if (image_get_type(&images->legacy_hdr_os_copy)
539*4882a593Smuzhiyun == IH_TYPE_MULTI)
540*4882a593Smuzhiyun puts("WARNING: legacy format multi component image overwritten\n");
541*4882a593Smuzhiyun return BOOTM_ERR_OVERLAP;
542*4882a593Smuzhiyun } else {
543*4882a593Smuzhiyun puts("ERROR: new format image overwritten - must RESET the board to recover\n");
544*4882a593Smuzhiyun bootstage_error(BOOTSTAGE_ID_OVERWRITTEN);
545*4882a593Smuzhiyun return BOOTM_ERR_RESET;
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun /* update image len as decompressed kernel size for late use */
550*4882a593Smuzhiyun images->os.image_len = *load_end - load;
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun return 0;
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun /**
556*4882a593Smuzhiyun * bootm_disable_interrupts() - Disable interrupts in preparation for load/boot
557*4882a593Smuzhiyun *
558*4882a593Smuzhiyun * @return interrupt flag (0 if interrupts were disabled, non-zero if they were
559*4882a593Smuzhiyun * enabled)
560*4882a593Smuzhiyun */
bootm_disable_interrupts(void)561*4882a593Smuzhiyun ulong bootm_disable_interrupts(void)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun ulong iflag;
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun /*
566*4882a593Smuzhiyun * Do not go further if usb is boot device,
567*4882a593Smuzhiyun * We may access usb at late sequence.
568*4882a593Smuzhiyun */
569*4882a593Smuzhiyun if (!strcmp(env_get("devtype"), "usb"))
570*4882a593Smuzhiyun return 0;
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun /*
573*4882a593Smuzhiyun * We have reached the point of no return: we are going to
574*4882a593Smuzhiyun * overwrite all exception vector code, so we cannot easily
575*4882a593Smuzhiyun * recover from any failures any more...
576*4882a593Smuzhiyun */
577*4882a593Smuzhiyun iflag = disable_interrupts();
578*4882a593Smuzhiyun #ifdef CONFIG_NETCONSOLE
579*4882a593Smuzhiyun /* Stop the ethernet stack if NetConsole could have left it up */
580*4882a593Smuzhiyun eth_halt();
581*4882a593Smuzhiyun # ifndef CONFIG_DM_ETH
582*4882a593Smuzhiyun eth_unregister(eth_get_dev());
583*4882a593Smuzhiyun # endif
584*4882a593Smuzhiyun #endif
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun #if defined(CONFIG_CMD_USB)
587*4882a593Smuzhiyun /*
588*4882a593Smuzhiyun * turn off USB to prevent the host controller from writing to the
589*4882a593Smuzhiyun * SDRAM while Linux is booting. This could happen (at least for OHCI
590*4882a593Smuzhiyun * controller), because the HCCA (Host Controller Communication Area)
591*4882a593Smuzhiyun * lies within the SDRAM and the host controller writes continously to
592*4882a593Smuzhiyun * this area (as busmaster!). The HccaFrameNumber is for example
593*4882a593Smuzhiyun * updated every 1 ms within the HCCA structure in SDRAM! For more
594*4882a593Smuzhiyun * details see the OpenHCI specification.
595*4882a593Smuzhiyun */
596*4882a593Smuzhiyun usb_stop();
597*4882a593Smuzhiyun #endif
598*4882a593Smuzhiyun return iflag;
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun #if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY)
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun #define CONSOLE_ARG "console="
604*4882a593Smuzhiyun #define CONSOLE_ARG_LEN (sizeof(CONSOLE_ARG) - 1)
605*4882a593Smuzhiyun
fixup_silent_linux(void)606*4882a593Smuzhiyun static void fixup_silent_linux(void)
607*4882a593Smuzhiyun {
608*4882a593Smuzhiyun char *buf;
609*4882a593Smuzhiyun const char *env_val;
610*4882a593Smuzhiyun char *cmdline = env_get("bootargs");
611*4882a593Smuzhiyun int want_silent;
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun /*
614*4882a593Smuzhiyun * Only fix cmdline when requested. The environment variable can be:
615*4882a593Smuzhiyun *
616*4882a593Smuzhiyun * no - we never fixup
617*4882a593Smuzhiyun * yes - we always fixup
618*4882a593Smuzhiyun * unset - we rely on the console silent flag
619*4882a593Smuzhiyun */
620*4882a593Smuzhiyun want_silent = env_get_yesno("silent_linux");
621*4882a593Smuzhiyun if (want_silent == 0)
622*4882a593Smuzhiyun return;
623*4882a593Smuzhiyun else if (want_silent == -1 && !(gd->flags & GD_FLG_SILENT))
624*4882a593Smuzhiyun return;
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun debug("before silent fix-up: %s\n", cmdline);
627*4882a593Smuzhiyun if (cmdline && (cmdline[0] != '\0')) {
628*4882a593Smuzhiyun char *start = strstr(cmdline, CONSOLE_ARG);
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun /* Allocate space for maximum possible new command line */
631*4882a593Smuzhiyun buf = malloc(strlen(cmdline) + 1 + CONSOLE_ARG_LEN + 1);
632*4882a593Smuzhiyun if (!buf) {
633*4882a593Smuzhiyun debug("%s: out of memory\n", __func__);
634*4882a593Smuzhiyun return;
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun if (start) {
638*4882a593Smuzhiyun char *end = strchr(start, ' ');
639*4882a593Smuzhiyun int num_start_bytes = start - cmdline + CONSOLE_ARG_LEN;
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun strncpy(buf, cmdline, num_start_bytes);
642*4882a593Smuzhiyun if (end)
643*4882a593Smuzhiyun strcpy(buf + num_start_bytes, end);
644*4882a593Smuzhiyun else
645*4882a593Smuzhiyun buf[num_start_bytes] = '\0';
646*4882a593Smuzhiyun } else {
647*4882a593Smuzhiyun sprintf(buf, "%s %s", cmdline, CONSOLE_ARG);
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun env_val = buf;
650*4882a593Smuzhiyun } else {
651*4882a593Smuzhiyun buf = NULL;
652*4882a593Smuzhiyun env_val = CONSOLE_ARG;
653*4882a593Smuzhiyun }
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun env_set("bootargs", env_val);
656*4882a593Smuzhiyun debug("after silent fix-up: %s\n", env_val);
657*4882a593Smuzhiyun free(buf);
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun #endif /* CONFIG_SILENT_CONSOLE */
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun /**
662*4882a593Smuzhiyun * Execute selected states of the bootm command.
663*4882a593Smuzhiyun *
664*4882a593Smuzhiyun * Note the arguments to this state must be the first argument, Any 'bootm'
665*4882a593Smuzhiyun * or sub-command arguments must have already been taken.
666*4882a593Smuzhiyun *
667*4882a593Smuzhiyun * Note that if states contains more than one flag it MUST contain
668*4882a593Smuzhiyun * BOOTM_STATE_START, since this handles and consumes the command line args.
669*4882a593Smuzhiyun *
670*4882a593Smuzhiyun * Also note that aside from boot_os_fn functions and bootm_load_os no other
671*4882a593Smuzhiyun * functions we store the return value of in 'ret' may use a negative return
672*4882a593Smuzhiyun * value, without special handling.
673*4882a593Smuzhiyun *
674*4882a593Smuzhiyun * @param cmdtp Pointer to bootm command table entry
675*4882a593Smuzhiyun * @param flag Command flags (CMD_FLAG_...)
676*4882a593Smuzhiyun * @param argc Number of subcommand arguments (0 = no arguments)
677*4882a593Smuzhiyun * @param argv Arguments
678*4882a593Smuzhiyun * @param states Mask containing states to run (BOOTM_STATE_...)
679*4882a593Smuzhiyun * @param images Image header information
680*4882a593Smuzhiyun * @param boot_progress 1 to show boot progress, 0 to not do this
681*4882a593Smuzhiyun * @return 0 if ok, something else on error. Some errors will cause this
682*4882a593Smuzhiyun * function to perform a reboot! If states contains BOOTM_STATE_OS_GO
683*4882a593Smuzhiyun * then the intent is to boot an OS, so this function will not return
684*4882a593Smuzhiyun * unless the image type is standalone.
685*4882a593Smuzhiyun */
do_bootm_states(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[],int states,bootm_headers_t * images,int boot_progress)686*4882a593Smuzhiyun int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
687*4882a593Smuzhiyun int states, bootm_headers_t *images, int boot_progress)
688*4882a593Smuzhiyun {
689*4882a593Smuzhiyun boot_os_fn *boot_fn;
690*4882a593Smuzhiyun ulong iflag = 0;
691*4882a593Smuzhiyun int ret = 0, need_boot_fn;
692*4882a593Smuzhiyun u32 unmask;
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun unmask = env_get_ulong("bootm_states_unmask", 16, 0);
695*4882a593Smuzhiyun if (unmask)
696*4882a593Smuzhiyun states &= ~unmask;
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun images->state |= states;
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun /*
701*4882a593Smuzhiyun * Work through the states and see how far we get. We stop on
702*4882a593Smuzhiyun * any error.
703*4882a593Smuzhiyun */
704*4882a593Smuzhiyun if (states & BOOTM_STATE_START)
705*4882a593Smuzhiyun ret = bootm_start(cmdtp, flag, argc, argv);
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun if (!ret && (states & BOOTM_STATE_FINDOS))
708*4882a593Smuzhiyun ret = bootm_find_os(cmdtp, flag, argc, argv);
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun if (!ret && (states & BOOTM_STATE_FINDOTHER))
711*4882a593Smuzhiyun ret = bootm_find_other(cmdtp, flag, argc, argv);
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun /* Load the OS */
714*4882a593Smuzhiyun if (!ret && (states & BOOTM_STATE_LOADOS)) {
715*4882a593Smuzhiyun ulong load_end;
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun iflag = bootm_disable_interrupts();
718*4882a593Smuzhiyun ret = bootm_load_os(images, &load_end, 0);
719*4882a593Smuzhiyun if (ret == 0)
720*4882a593Smuzhiyun lmb_reserve(&images->lmb, images->os.load,
721*4882a593Smuzhiyun (load_end - images->os.load));
722*4882a593Smuzhiyun else if (ret && ret != BOOTM_ERR_OVERLAP)
723*4882a593Smuzhiyun goto err;
724*4882a593Smuzhiyun else if (ret == BOOTM_ERR_OVERLAP)
725*4882a593Smuzhiyun ret = 0;
726*4882a593Smuzhiyun }
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun /* Resever memory before any lmb_alloc, as early as possible */
729*4882a593Smuzhiyun #if IMAGE_ENABLE_OF_LIBFDT && defined(CONFIG_LMB)
730*4882a593Smuzhiyun if (!ret && ((states & BOOTM_STATE_RAMDISK) ||
731*4882a593Smuzhiyun (states & BOOTM_STATE_FDT)))
732*4882a593Smuzhiyun boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr);
733*4882a593Smuzhiyun #endif
734*4882a593Smuzhiyun /* Relocate the ramdisk */
735*4882a593Smuzhiyun #ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
736*4882a593Smuzhiyun if (!ret && (states & BOOTM_STATE_RAMDISK)) {
737*4882a593Smuzhiyun ulong rd_len = images->rd_end - images->rd_start;
738*4882a593Smuzhiyun
739*4882a593Smuzhiyun ret = boot_ramdisk_high(&images->lmb, images->rd_start,
740*4882a593Smuzhiyun rd_len, &images->initrd_start, &images->initrd_end);
741*4882a593Smuzhiyun if (!ret) {
742*4882a593Smuzhiyun env_set_hex("initrd_start", images->initrd_start);
743*4882a593Smuzhiyun env_set_hex("initrd_end", images->initrd_end);
744*4882a593Smuzhiyun }
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun #endif
747*4882a593Smuzhiyun #if IMAGE_ENABLE_OF_LIBFDT && defined(CONFIG_LMB)
748*4882a593Smuzhiyun if (!ret && (states & BOOTM_STATE_FDT)) {
749*4882a593Smuzhiyun ret = boot_relocate_fdt(&images->lmb, &images->ft_addr,
750*4882a593Smuzhiyun &images->ft_len);
751*4882a593Smuzhiyun }
752*4882a593Smuzhiyun #endif
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun /* From now on, we need the OS boot function */
755*4882a593Smuzhiyun if (ret)
756*4882a593Smuzhiyun return ret;
757*4882a593Smuzhiyun boot_fn = bootm_os_get_boot_func(images->os.os);
758*4882a593Smuzhiyun need_boot_fn = states & (BOOTM_STATE_OS_CMDLINE |
759*4882a593Smuzhiyun BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP |
760*4882a593Smuzhiyun BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO);
761*4882a593Smuzhiyun if (boot_fn == NULL && need_boot_fn) {
762*4882a593Smuzhiyun if (iflag)
763*4882a593Smuzhiyun enable_interrupts();
764*4882a593Smuzhiyun printf("ERROR: booting os '%s' (%d) is not supported\n",
765*4882a593Smuzhiyun genimg_get_os_name(images->os.os), images->os.os);
766*4882a593Smuzhiyun bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS);
767*4882a593Smuzhiyun return 1;
768*4882a593Smuzhiyun }
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun /* Call various other states that are not generally used */
772*4882a593Smuzhiyun if (!ret && (states & BOOTM_STATE_OS_CMDLINE))
773*4882a593Smuzhiyun ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images);
774*4882a593Smuzhiyun if (!ret && (states & BOOTM_STATE_OS_BD_T))
775*4882a593Smuzhiyun ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images);
776*4882a593Smuzhiyun if (!ret && (states & BOOTM_STATE_OS_PREP)) {
777*4882a593Smuzhiyun #if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY)
778*4882a593Smuzhiyun if (images->os.os == IH_OS_LINUX)
779*4882a593Smuzhiyun fixup_silent_linux();
780*4882a593Smuzhiyun #endif
781*4882a593Smuzhiyun arch_preboot_os(BOOTM_STATE_OS_PREP, images);
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images);
784*4882a593Smuzhiyun }
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun #ifdef CONFIG_TRACE
787*4882a593Smuzhiyun /* Pretend to run the OS, then run a user command */
788*4882a593Smuzhiyun if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) {
789*4882a593Smuzhiyun char *cmd_list = env_get("fakegocmd");
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO,
792*4882a593Smuzhiyun images, boot_fn);
793*4882a593Smuzhiyun if (!ret && cmd_list)
794*4882a593Smuzhiyun ret = run_command_list(cmd_list, -1, flag);
795*4882a593Smuzhiyun }
796*4882a593Smuzhiyun #endif
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun /* Check for unsupported subcommand. */
799*4882a593Smuzhiyun if (ret) {
800*4882a593Smuzhiyun puts("subcommand not supported\n");
801*4882a593Smuzhiyun return ret;
802*4882a593Smuzhiyun }
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun /* Now run the OS! We hope this doesn't return */
805*4882a593Smuzhiyun if (!ret && (states & BOOTM_STATE_OS_GO))
806*4882a593Smuzhiyun ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO,
807*4882a593Smuzhiyun images, boot_fn);
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun /* Deal with any fallout */
810*4882a593Smuzhiyun err:
811*4882a593Smuzhiyun if (iflag)
812*4882a593Smuzhiyun enable_interrupts();
813*4882a593Smuzhiyun
814*4882a593Smuzhiyun if (ret == BOOTM_ERR_UNIMPLEMENTED)
815*4882a593Smuzhiyun bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL);
816*4882a593Smuzhiyun else if (ret == BOOTM_ERR_RESET)
817*4882a593Smuzhiyun do_reset(cmdtp, flag, argc, argv);
818*4882a593Smuzhiyun
819*4882a593Smuzhiyun return ret;
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun
822*4882a593Smuzhiyun #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
823*4882a593Smuzhiyun /**
824*4882a593Smuzhiyun * image_get_kernel - verify legacy format kernel image
825*4882a593Smuzhiyun * @img_addr: in RAM address of the legacy format image to be verified
826*4882a593Smuzhiyun * @verify: data CRC verification flag
827*4882a593Smuzhiyun *
828*4882a593Smuzhiyun * image_get_kernel() verifies legacy image integrity and returns pointer to
829*4882a593Smuzhiyun * legacy image header if image verification was completed successfully.
830*4882a593Smuzhiyun *
831*4882a593Smuzhiyun * returns:
832*4882a593Smuzhiyun * pointer to a legacy image header if valid image was found
833*4882a593Smuzhiyun * otherwise return NULL
834*4882a593Smuzhiyun */
image_get_kernel(ulong img_addr,int verify)835*4882a593Smuzhiyun static image_header_t *image_get_kernel(ulong img_addr, int verify)
836*4882a593Smuzhiyun {
837*4882a593Smuzhiyun image_header_t *hdr = (image_header_t *)img_addr;
838*4882a593Smuzhiyun
839*4882a593Smuzhiyun if (!image_check_magic(hdr)) {
840*4882a593Smuzhiyun puts("Bad Magic Number\n");
841*4882a593Smuzhiyun bootstage_error(BOOTSTAGE_ID_CHECK_MAGIC);
842*4882a593Smuzhiyun return NULL;
843*4882a593Smuzhiyun }
844*4882a593Smuzhiyun bootstage_mark(BOOTSTAGE_ID_CHECK_HEADER);
845*4882a593Smuzhiyun
846*4882a593Smuzhiyun if (!image_check_hcrc(hdr)) {
847*4882a593Smuzhiyun puts("Bad Header Checksum\n");
848*4882a593Smuzhiyun bootstage_error(BOOTSTAGE_ID_CHECK_HEADER);
849*4882a593Smuzhiyun return NULL;
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun
852*4882a593Smuzhiyun bootstage_mark(BOOTSTAGE_ID_CHECK_CHECKSUM);
853*4882a593Smuzhiyun image_print_contents(hdr);
854*4882a593Smuzhiyun
855*4882a593Smuzhiyun if (verify) {
856*4882a593Smuzhiyun puts(" Verifying Checksum ... ");
857*4882a593Smuzhiyun if (!image_check_dcrc(hdr)) {
858*4882a593Smuzhiyun printf("Bad Data CRC\n");
859*4882a593Smuzhiyun bootstage_error(BOOTSTAGE_ID_CHECK_CHECKSUM);
860*4882a593Smuzhiyun return NULL;
861*4882a593Smuzhiyun }
862*4882a593Smuzhiyun puts("OK\n");
863*4882a593Smuzhiyun }
864*4882a593Smuzhiyun bootstage_mark(BOOTSTAGE_ID_CHECK_ARCH);
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun if (!image_check_target_arch(hdr)) {
867*4882a593Smuzhiyun printf("Unsupported Architecture 0x%x\n", image_get_arch(hdr));
868*4882a593Smuzhiyun bootstage_error(BOOTSTAGE_ID_CHECK_ARCH);
869*4882a593Smuzhiyun return NULL;
870*4882a593Smuzhiyun }
871*4882a593Smuzhiyun return hdr;
872*4882a593Smuzhiyun }
873*4882a593Smuzhiyun #endif
874*4882a593Smuzhiyun
875*4882a593Smuzhiyun /**
876*4882a593Smuzhiyun * boot_get_kernel - find kernel image
877*4882a593Smuzhiyun * @os_data: pointer to a ulong variable, will hold os data start address
878*4882a593Smuzhiyun * @os_len: pointer to a ulong variable, will hold os data length
879*4882a593Smuzhiyun *
880*4882a593Smuzhiyun * boot_get_kernel() tries to find a kernel image, verifies its integrity
881*4882a593Smuzhiyun * and locates kernel data.
882*4882a593Smuzhiyun *
883*4882a593Smuzhiyun * returns:
884*4882a593Smuzhiyun * pointer to image header if valid image was found, plus kernel start
885*4882a593Smuzhiyun * address and length, otherwise NULL
886*4882a593Smuzhiyun */
boot_get_kernel(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[],bootm_headers_t * images,ulong * os_data,ulong * os_len)887*4882a593Smuzhiyun static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,
888*4882a593Smuzhiyun char * const argv[], bootm_headers_t *images,
889*4882a593Smuzhiyun ulong *os_data, ulong *os_len)
890*4882a593Smuzhiyun {
891*4882a593Smuzhiyun #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
892*4882a593Smuzhiyun image_header_t *hdr;
893*4882a593Smuzhiyun #endif
894*4882a593Smuzhiyun ulong img_addr;
895*4882a593Smuzhiyun const void *buf;
896*4882a593Smuzhiyun const char *fit_uname_config = NULL;
897*4882a593Smuzhiyun const char *fit_uname_kernel = NULL;
898*4882a593Smuzhiyun #if IMAGE_ENABLE_FIT
899*4882a593Smuzhiyun int os_noffset;
900*4882a593Smuzhiyun #endif
901*4882a593Smuzhiyun
902*4882a593Smuzhiyun img_addr = genimg_get_kernel_addr_fit(argc < 1 ? NULL : argv[0],
903*4882a593Smuzhiyun &fit_uname_config,
904*4882a593Smuzhiyun &fit_uname_kernel);
905*4882a593Smuzhiyun
906*4882a593Smuzhiyun bootstage_mark(BOOTSTAGE_ID_CHECK_MAGIC);
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun /* check image type, for FIT images get FIT kernel node */
909*4882a593Smuzhiyun *os_data = *os_len = 0;
910*4882a593Smuzhiyun buf = map_sysmem(img_addr, 0);
911*4882a593Smuzhiyun switch (genimg_get_format(buf)) {
912*4882a593Smuzhiyun #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
913*4882a593Smuzhiyun case IMAGE_FORMAT_LEGACY:
914*4882a593Smuzhiyun printf("## Booting kernel from Legacy Image at %08lx ...\n",
915*4882a593Smuzhiyun img_addr);
916*4882a593Smuzhiyun hdr = image_get_kernel(img_addr, images->verify);
917*4882a593Smuzhiyun if (!hdr)
918*4882a593Smuzhiyun return NULL;
919*4882a593Smuzhiyun bootstage_mark(BOOTSTAGE_ID_CHECK_IMAGETYPE);
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun /* get os_data and os_len */
922*4882a593Smuzhiyun switch (image_get_type(hdr)) {
923*4882a593Smuzhiyun case IH_TYPE_KERNEL:
924*4882a593Smuzhiyun case IH_TYPE_KERNEL_NOLOAD:
925*4882a593Smuzhiyun *os_data = image_get_data(hdr);
926*4882a593Smuzhiyun *os_len = image_get_data_size(hdr);
927*4882a593Smuzhiyun break;
928*4882a593Smuzhiyun case IH_TYPE_MULTI:
929*4882a593Smuzhiyun image_multi_getimg(hdr, 0, os_data, os_len);
930*4882a593Smuzhiyun break;
931*4882a593Smuzhiyun case IH_TYPE_STANDALONE:
932*4882a593Smuzhiyun *os_data = image_get_data(hdr);
933*4882a593Smuzhiyun *os_len = image_get_data_size(hdr);
934*4882a593Smuzhiyun break;
935*4882a593Smuzhiyun default:
936*4882a593Smuzhiyun if (cmdtp)
937*4882a593Smuzhiyun printf("Wrong Image Type for %s command\n",
938*4882a593Smuzhiyun cmdtp->name);
939*4882a593Smuzhiyun bootstage_error(BOOTSTAGE_ID_CHECK_IMAGETYPE);
940*4882a593Smuzhiyun return NULL;
941*4882a593Smuzhiyun }
942*4882a593Smuzhiyun
943*4882a593Smuzhiyun /*
944*4882a593Smuzhiyun * copy image header to allow for image overwrites during
945*4882a593Smuzhiyun * kernel decompression.
946*4882a593Smuzhiyun */
947*4882a593Smuzhiyun memmove(&images->legacy_hdr_os_copy, hdr,
948*4882a593Smuzhiyun sizeof(image_header_t));
949*4882a593Smuzhiyun
950*4882a593Smuzhiyun /* save pointer to image header */
951*4882a593Smuzhiyun images->legacy_hdr_os = hdr;
952*4882a593Smuzhiyun
953*4882a593Smuzhiyun images->legacy_hdr_valid = 1;
954*4882a593Smuzhiyun bootstage_mark(BOOTSTAGE_ID_DECOMP_IMAGE);
955*4882a593Smuzhiyun break;
956*4882a593Smuzhiyun #endif
957*4882a593Smuzhiyun #if IMAGE_ENABLE_FIT
958*4882a593Smuzhiyun case IMAGE_FORMAT_FIT:
959*4882a593Smuzhiyun os_noffset = fit_image_load(images, img_addr,
960*4882a593Smuzhiyun &fit_uname_kernel, &fit_uname_config,
961*4882a593Smuzhiyun IH_ARCH_DEFAULT, IH_TYPE_KERNEL,
962*4882a593Smuzhiyun BOOTSTAGE_ID_FIT_KERNEL_START,
963*4882a593Smuzhiyun FIT_LOAD_IGNORED, os_data, os_len);
964*4882a593Smuzhiyun if (os_noffset < 0)
965*4882a593Smuzhiyun return NULL;
966*4882a593Smuzhiyun
967*4882a593Smuzhiyun images->fit_hdr_os = map_sysmem(img_addr, 0);
968*4882a593Smuzhiyun images->fit_uname_os = fit_uname_kernel;
969*4882a593Smuzhiyun images->fit_uname_cfg = fit_uname_config;
970*4882a593Smuzhiyun images->fit_noffset_os = os_noffset;
971*4882a593Smuzhiyun break;
972*4882a593Smuzhiyun #endif
973*4882a593Smuzhiyun #ifdef CONFIG_ANDROID_BOOT_IMAGE
974*4882a593Smuzhiyun case IMAGE_FORMAT_ANDROID:
975*4882a593Smuzhiyun printf("## Booting Android Image at 0x%08lx ...\n", img_addr);
976*4882a593Smuzhiyun if (android_image_get_kernel(buf, images->verify,
977*4882a593Smuzhiyun os_data, os_len))
978*4882a593Smuzhiyun return NULL;
979*4882a593Smuzhiyun break;
980*4882a593Smuzhiyun #endif
981*4882a593Smuzhiyun default:
982*4882a593Smuzhiyun if (cmdtp)
983*4882a593Smuzhiyun printf("Wrong Image Format for %s command\n",
984*4882a593Smuzhiyun cmdtp->name);
985*4882a593Smuzhiyun bootstage_error(BOOTSTAGE_ID_FIT_KERNEL_INFO);
986*4882a593Smuzhiyun return NULL;
987*4882a593Smuzhiyun }
988*4882a593Smuzhiyun
989*4882a593Smuzhiyun debug(" kernel data at 0x%08lx, len = 0x%08lx (%ld)\n",
990*4882a593Smuzhiyun *os_data, *os_len, *os_len);
991*4882a593Smuzhiyun
992*4882a593Smuzhiyun return buf;
993*4882a593Smuzhiyun }
994*4882a593Smuzhiyun #else /* USE_HOSTCC */
995*4882a593Smuzhiyun
memmove_wd(void * to,void * from,size_t len,ulong chunksz)996*4882a593Smuzhiyun void memmove_wd(void *to, void *from, size_t len, ulong chunksz)
997*4882a593Smuzhiyun {
998*4882a593Smuzhiyun memmove(to, from, len);
999*4882a593Smuzhiyun }
1000*4882a593Smuzhiyun
bootm_host_load_image(const void * fit,int req_image_type,int index)1001*4882a593Smuzhiyun static int bootm_host_load_image(const void *fit, int req_image_type, int index)
1002*4882a593Smuzhiyun {
1003*4882a593Smuzhiyun const char *fit_uname_config = NULL;
1004*4882a593Smuzhiyun ulong data, len;
1005*4882a593Smuzhiyun bootm_headers_t images;
1006*4882a593Smuzhiyun int noffset;
1007*4882a593Smuzhiyun ulong load_end;
1008*4882a593Smuzhiyun uint8_t image_type;
1009*4882a593Smuzhiyun uint8_t imape_comp;
1010*4882a593Smuzhiyun void *load_buf;
1011*4882a593Smuzhiyun int ret;
1012*4882a593Smuzhiyun
1013*4882a593Smuzhiyun memset(&images, '\0', sizeof(images));
1014*4882a593Smuzhiyun images.verify = 1;
1015*4882a593Smuzhiyun noffset = fit_image_load_index(&images, (ulong)fit,
1016*4882a593Smuzhiyun NULL, &fit_uname_config,
1017*4882a593Smuzhiyun IH_ARCH_DEFAULT, req_image_type, index, -1,
1018*4882a593Smuzhiyun FIT_LOAD_IGNORED, &data, &len);
1019*4882a593Smuzhiyun if (noffset < 0)
1020*4882a593Smuzhiyun return noffset;
1021*4882a593Smuzhiyun if (fit_image_get_type(fit, noffset, &image_type)) {
1022*4882a593Smuzhiyun puts("Can't get image type!\n");
1023*4882a593Smuzhiyun return -EINVAL;
1024*4882a593Smuzhiyun }
1025*4882a593Smuzhiyun
1026*4882a593Smuzhiyun if (fit_image_get_comp(fit, noffset, &imape_comp)) {
1027*4882a593Smuzhiyun puts("Can't get image compression!\n");
1028*4882a593Smuzhiyun return -EINVAL;
1029*4882a593Smuzhiyun }
1030*4882a593Smuzhiyun
1031*4882a593Smuzhiyun /* Allow the image to expand by a factor of 4, should be safe */
1032*4882a593Smuzhiyun load_buf = malloc((1 << 20) + len * 4);
1033*4882a593Smuzhiyun ret = bootm_decomp_image(imape_comp, 0, data, image_type, load_buf,
1034*4882a593Smuzhiyun (void *)data, len, CONFIG_SYS_BOOTM_LEN,
1035*4882a593Smuzhiyun &load_end);
1036*4882a593Smuzhiyun free(load_buf);
1037*4882a593Smuzhiyun
1038*4882a593Smuzhiyun if (ret && ret != BOOTM_ERR_UNIMPLEMENTED)
1039*4882a593Smuzhiyun return ret;
1040*4882a593Smuzhiyun
1041*4882a593Smuzhiyun return 0;
1042*4882a593Smuzhiyun }
1043*4882a593Smuzhiyun
bootm_host_load_images(const void * fit,int cfg_noffset,int is_spl)1044*4882a593Smuzhiyun int bootm_host_load_images(const void *fit, int cfg_noffset, int is_spl)
1045*4882a593Smuzhiyun {
1046*4882a593Smuzhiyun static uint8_t image_types[] = {
1047*4882a593Smuzhiyun IH_TYPE_KERNEL,
1048*4882a593Smuzhiyun IH_TYPE_FLATDT,
1049*4882a593Smuzhiyun IH_TYPE_RAMDISK,
1050*4882a593Smuzhiyun };
1051*4882a593Smuzhiyun #ifdef CONFIG_SPL_ATF
1052*4882a593Smuzhiyun static uint8_t image_types_spl[] = {
1053*4882a593Smuzhiyun IH_TYPE_FLATDT,
1054*4882a593Smuzhiyun IH_TYPE_FIRMWARE,
1055*4882a593Smuzhiyun IH_TYPE_LOADABLE,
1056*4882a593Smuzhiyun IH_TYPE_LOADABLE,
1057*4882a593Smuzhiyun IH_TYPE_LOADABLE,
1058*4882a593Smuzhiyun };
1059*4882a593Smuzhiyun #else
1060*4882a593Smuzhiyun static uint8_t image_types_spl[] = {
1061*4882a593Smuzhiyun IH_TYPE_FLATDT,
1062*4882a593Smuzhiyun IH_TYPE_FIRMWARE,
1063*4882a593Smuzhiyun IH_TYPE_LOADABLE,
1064*4882a593Smuzhiyun };
1065*4882a593Smuzhiyun #endif
1066*4882a593Smuzhiyun int loadable_index = 0;
1067*4882a593Smuzhiyun int err = 0;
1068*4882a593Smuzhiyun int index;
1069*4882a593Smuzhiyun int i;
1070*4882a593Smuzhiyun
1071*4882a593Smuzhiyun for (i = 0; !is_spl && i < ARRAY_SIZE(image_types); i++) {
1072*4882a593Smuzhiyun int ret;
1073*4882a593Smuzhiyun
1074*4882a593Smuzhiyun ret = bootm_host_load_image(fit, image_types[i], 0);
1075*4882a593Smuzhiyun if (!err && ret && ret != -ENOENT)
1076*4882a593Smuzhiyun err = ret;
1077*4882a593Smuzhiyun }
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun for (i = 0; is_spl && i < ARRAY_SIZE(image_types_spl); i++) {
1080*4882a593Smuzhiyun int ret;
1081*4882a593Smuzhiyun
1082*4882a593Smuzhiyun if (image_types_spl[i] == IH_TYPE_LOADABLE)
1083*4882a593Smuzhiyun index = loadable_index++;
1084*4882a593Smuzhiyun else
1085*4882a593Smuzhiyun index = 0;
1086*4882a593Smuzhiyun
1087*4882a593Smuzhiyun ret = bootm_host_load_image(fit, image_types_spl[i], index);
1088*4882a593Smuzhiyun if (!err && ret && ret != -ENOENT)
1089*4882a593Smuzhiyun err = ret;
1090*4882a593Smuzhiyun }
1091*4882a593Smuzhiyun
1092*4882a593Smuzhiyun /* Return the first error we found */
1093*4882a593Smuzhiyun return err;
1094*4882a593Smuzhiyun }
1095*4882a593Smuzhiyun
1096*4882a593Smuzhiyun #endif /* ndef USE_HOSTCC */
1097