command: Remove the cmd_tbl_t typedef
[oweals/u-boot.git] / cmd / bootm.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2000-2009
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  */
6
7 /*
8  * Boot support
9  */
10 #include <common.h>
11 #include <bootm.h>
12 #include <command.h>
13 #include <env.h>
14 #include <errno.h>
15 #include <image.h>
16 #include <malloc.h>
17 #include <nand.h>
18 #include <asm/byteorder.h>
19 #include <linux/ctype.h>
20 #include <linux/err.h>
21 #include <u-boot/zlib.h>
22 #include <mapmem.h>
23
24 DECLARE_GLOBAL_DATA_PTR;
25
26 #if defined(CONFIG_CMD_IMI)
27 static int image_info(unsigned long addr);
28 #endif
29
30 #if defined(CONFIG_CMD_IMLS)
31 #include <flash.h>
32 #include <mtd/cfi_flash.h>
33 extern flash_info_t flash_info[]; /* info for FLASH chips */
34 #endif
35
36 #if defined(CONFIG_CMD_IMLS) || defined(CONFIG_CMD_IMLS_NAND)
37 static int do_imls(struct cmd_tbl *cmdtp, int flag, int argc,
38                    char *const argv[]);
39 #endif
40
41 /* we overload the cmd field with our state machine info instead of a
42  * function pointer */
43 static struct cmd_tbl cmd_bootm_sub[] = {
44         U_BOOT_CMD_MKENT(start, 0, 1, (void *)BOOTM_STATE_START, "", ""),
45         U_BOOT_CMD_MKENT(loados, 0, 1, (void *)BOOTM_STATE_LOADOS, "", ""),
46 #ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
47         U_BOOT_CMD_MKENT(ramdisk, 0, 1, (void *)BOOTM_STATE_RAMDISK, "", ""),
48 #endif
49 #ifdef CONFIG_OF_LIBFDT
50         U_BOOT_CMD_MKENT(fdt, 0, 1, (void *)BOOTM_STATE_FDT, "", ""),
51 #endif
52         U_BOOT_CMD_MKENT(cmdline, 0, 1, (void *)BOOTM_STATE_OS_CMDLINE, "", ""),
53         U_BOOT_CMD_MKENT(bdt, 0, 1, (void *)BOOTM_STATE_OS_BD_T, "", ""),
54         U_BOOT_CMD_MKENT(prep, 0, 1, (void *)BOOTM_STATE_OS_PREP, "", ""),
55         U_BOOT_CMD_MKENT(fake, 0, 1, (void *)BOOTM_STATE_OS_FAKE_GO, "", ""),
56         U_BOOT_CMD_MKENT(go, 0, 1, (void *)BOOTM_STATE_OS_GO, "", ""),
57 };
58
59 static int do_bootm_subcommand(struct cmd_tbl *cmdtp, int flag, int argc,
60                                char *const argv[])
61 {
62         int ret = 0;
63         long state;
64         struct cmd_tbl *c;
65
66         c = find_cmd_tbl(argv[0], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub));
67         argc--; argv++;
68
69         if (c) {
70                 state = (long)c->cmd;
71                 if (state == BOOTM_STATE_START)
72                         state |= BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER;
73         } else {
74                 /* Unrecognized command */
75                 return CMD_RET_USAGE;
76         }
77
78         if (((state & BOOTM_STATE_START) != BOOTM_STATE_START) &&
79             images.state >= state) {
80                 printf("Trying to execute a command out of order\n");
81                 return CMD_RET_USAGE;
82         }
83
84         ret = do_bootm_states(cmdtp, flag, argc, argv, state, &images, 0);
85
86         return ret;
87 }
88
89 /*******************************************************************/
90 /* bootm - boot application image from image in memory */
91 /*******************************************************************/
92
93 int do_bootm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
94 {
95 #ifdef CONFIG_NEEDS_MANUAL_RELOC
96         static int relocated = 0;
97
98         if (!relocated) {
99                 int i;
100
101                 /* relocate names of sub-command table */
102                 for (i = 0; i < ARRAY_SIZE(cmd_bootm_sub); i++)
103                         cmd_bootm_sub[i].name += gd->reloc_off;
104
105                 relocated = 1;
106         }
107 #endif
108
109         /* determine if we have a sub command */
110         argc--; argv++;
111         if (argc > 0) {
112                 char *endp;
113
114                 simple_strtoul(argv[0], &endp, 16);
115                 /* endp pointing to NULL means that argv[0] was just a
116                  * valid number, pass it along to the normal bootm processing
117                  *
118                  * If endp is ':' or '#' assume a FIT identifier so pass
119                  * along for normal processing.
120                  *
121                  * Right now we assume the first arg should never be '-'
122                  */
123                 if ((*endp != 0) && (*endp != ':') && (*endp != '#'))
124                         return do_bootm_subcommand(cmdtp, flag, argc, argv);
125         }
126
127         return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START |
128                 BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER |
129                 BOOTM_STATE_LOADOS |
130 #ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
131                 BOOTM_STATE_RAMDISK |
132 #endif
133 #if defined(CONFIG_PPC) || defined(CONFIG_MIPS)
134                 BOOTM_STATE_OS_CMDLINE |
135 #endif
136                 BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
137                 BOOTM_STATE_OS_GO, &images, 1);
138 }
139
140 int bootm_maybe_autostart(struct cmd_tbl *cmdtp, const char *cmd)
141 {
142         const char *ep = env_get("autostart");
143
144         if (ep && !strcmp(ep, "yes")) {
145                 char *local_args[2];
146                 local_args[0] = (char *)cmd;
147                 local_args[1] = NULL;
148                 printf("Automatic boot of image at addr 0x%08lX ...\n",
149                        image_load_addr);
150                 return do_bootm(cmdtp, 0, 1, local_args);
151         }
152
153         return 0;
154 }
155
156 #ifdef CONFIG_SYS_LONGHELP
157 static char bootm_help_text[] =
158         "[addr [arg ...]]\n    - boot application image stored in memory\n"
159         "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
160         "\t'arg' can be the address of an initrd image\n"
161 #if defined(CONFIG_OF_LIBFDT)
162         "\tWhen booting a Linux kernel which requires a flat device-tree\n"
163         "\ta third argument is required which is the address of the\n"
164         "\tdevice-tree blob. To boot that kernel without an initrd image,\n"
165         "\tuse a '-' for the second argument. If you do not pass a third\n"
166         "\ta bd_info struct will be passed instead\n"
167 #endif
168 #if defined(CONFIG_FIT)
169         "\t\nFor the new multi component uImage format (FIT) addresses\n"
170         "\tmust be extended to include component or configuration unit name:\n"
171         "\taddr:<subimg_uname> - direct component image specification\n"
172         "\taddr#<conf_uname>   - configuration specification\n"
173         "\tUse iminfo command to get the list of existing component\n"
174         "\timages and configurations.\n"
175 #endif
176         "\nSub-commands to do part of the bootm sequence.  The sub-commands "
177         "must be\n"
178         "issued in the order below (it's ok to not issue all sub-commands):\n"
179         "\tstart [addr [arg ...]]\n"
180         "\tloados  - load OS image\n"
181 #if defined(CONFIG_SYS_BOOT_RAMDISK_HIGH)
182         "\tramdisk - relocate initrd, set env initrd_start/initrd_end\n"
183 #endif
184 #if defined(CONFIG_OF_LIBFDT)
185         "\tfdt     - relocate flat device tree\n"
186 #endif
187         "\tcmdline - OS specific command line processing/setup\n"
188         "\tbdt     - OS specific bd_t processing\n"
189         "\tprep    - OS specific prep before relocation or go\n"
190 #if defined(CONFIG_TRACE)
191         "\tfake    - OS specific fake start without go\n"
192 #endif
193         "\tgo      - start OS";
194 #endif
195
196 U_BOOT_CMD(
197         bootm,  CONFIG_SYS_MAXARGS,     1,      do_bootm,
198         "boot application image from memory", bootm_help_text
199 );
200
201 /*******************************************************************/
202 /* bootd - boot default image */
203 /*******************************************************************/
204 #if defined(CONFIG_CMD_BOOTD)
205 int do_bootd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
206 {
207         return run_command(env_get("bootcmd"), flag);
208 }
209
210 U_BOOT_CMD(
211         boot,   1,      1,      do_bootd,
212         "boot default, i.e., run 'bootcmd'",
213         ""
214 );
215
216 /* keep old command name "bootd" for backward compatibility */
217 U_BOOT_CMD(
218         bootd, 1,       1,      do_bootd,
219         "boot default, i.e., run 'bootcmd'",
220         ""
221 );
222
223 #endif
224
225
226 /*******************************************************************/
227 /* iminfo - print header info for a requested image */
228 /*******************************************************************/
229 #if defined(CONFIG_CMD_IMI)
230 static int do_iminfo(struct cmd_tbl *cmdtp, int flag, int argc,
231                      char *const argv[])
232 {
233         int     arg;
234         ulong   addr;
235         int     rcode = 0;
236
237         if (argc < 2) {
238                 return image_info(image_load_addr);
239         }
240
241         for (arg = 1; arg < argc; ++arg) {
242                 addr = simple_strtoul(argv[arg], NULL, 16);
243                 if (image_info(addr) != 0)
244                         rcode = 1;
245         }
246         return rcode;
247 }
248
249 static int image_info(ulong addr)
250 {
251         void *hdr = (void *)map_sysmem(addr, 0);
252
253         printf("\n## Checking Image at %08lx ...\n", addr);
254
255         switch (genimg_get_format(hdr)) {
256 #if defined(CONFIG_LEGACY_IMAGE_FORMAT)
257         case IMAGE_FORMAT_LEGACY:
258                 puts("   Legacy image found\n");
259                 if (!image_check_magic(hdr)) {
260                         puts("   Bad Magic Number\n");
261                         unmap_sysmem(hdr);
262                         return 1;
263                 }
264
265                 if (!image_check_hcrc(hdr)) {
266                         puts("   Bad Header Checksum\n");
267                         unmap_sysmem(hdr);
268                         return 1;
269                 }
270
271                 image_print_contents(hdr);
272
273                 puts("   Verifying Checksum ... ");
274                 if (!image_check_dcrc(hdr)) {
275                         puts("   Bad Data CRC\n");
276                         unmap_sysmem(hdr);
277                         return 1;
278                 }
279                 puts("OK\n");
280                 unmap_sysmem(hdr);
281                 return 0;
282 #endif
283 #if defined(CONFIG_ANDROID_BOOT_IMAGE)
284         case IMAGE_FORMAT_ANDROID:
285                 puts("   Android image found\n");
286                 android_print_contents(hdr);
287                 unmap_sysmem(hdr);
288                 return 0;
289 #endif
290 #if defined(CONFIG_FIT)
291         case IMAGE_FORMAT_FIT:
292                 puts("   FIT image found\n");
293
294                 if (!fit_check_format(hdr)) {
295                         puts("Bad FIT image format!\n");
296                         unmap_sysmem(hdr);
297                         return 1;
298                 }
299
300                 fit_print_contents(hdr);
301
302                 if (!fit_all_image_verify(hdr)) {
303                         puts("Bad hash in FIT image!\n");
304                         unmap_sysmem(hdr);
305                         return 1;
306                 }
307
308                 unmap_sysmem(hdr);
309                 return 0;
310 #endif
311         default:
312                 puts("Unknown image format!\n");
313                 break;
314         }
315
316         unmap_sysmem(hdr);
317         return 1;
318 }
319
320 U_BOOT_CMD(
321         iminfo, CONFIG_SYS_MAXARGS,     1,      do_iminfo,
322         "print header information for application image",
323         "addr [addr ...]\n"
324         "    - print header information for application image starting at\n"
325         "      address 'addr' in memory; this includes verification of the\n"
326         "      image contents (magic number, header and payload checksums)"
327 );
328 #endif
329
330
331 /*******************************************************************/
332 /* imls - list all images found in flash */
333 /*******************************************************************/
334 #if defined(CONFIG_CMD_IMLS)
335 static int do_imls_nor(void)
336 {
337         flash_info_t *info;
338         int i, j;
339         void *hdr;
340
341         for (i = 0, info = &flash_info[0];
342                 i < CONFIG_SYS_MAX_FLASH_BANKS; ++i, ++info) {
343
344                 if (info->flash_id == FLASH_UNKNOWN)
345                         goto next_bank;
346                 for (j = 0; j < info->sector_count; ++j) {
347
348                         hdr = (void *)info->start[j];
349                         if (!hdr)
350                                 goto next_sector;
351
352                         switch (genimg_get_format(hdr)) {
353 #if defined(CONFIG_LEGACY_IMAGE_FORMAT)
354                         case IMAGE_FORMAT_LEGACY:
355                                 if (!image_check_hcrc(hdr))
356                                         goto next_sector;
357
358                                 printf("Legacy Image at %08lX:\n", (ulong)hdr);
359                                 image_print_contents(hdr);
360
361                                 puts("   Verifying Checksum ... ");
362                                 if (!image_check_dcrc(hdr)) {
363                                         puts("Bad Data CRC\n");
364                                 } else {
365                                         puts("OK\n");
366                                 }
367                                 break;
368 #endif
369 #if defined(CONFIG_FIT)
370                         case IMAGE_FORMAT_FIT:
371                                 if (!fit_check_format(hdr))
372                                         goto next_sector;
373
374                                 printf("FIT Image at %08lX:\n", (ulong)hdr);
375                                 fit_print_contents(hdr);
376                                 break;
377 #endif
378                         default:
379                                 goto next_sector;
380                         }
381
382 next_sector:            ;
383                 }
384 next_bank:      ;
385         }
386         return 0;
387 }
388 #endif
389
390 #if defined(CONFIG_CMD_IMLS_NAND)
391 static int nand_imls_legacyimage(struct mtd_info *mtd, int nand_dev,
392                                  loff_t off, size_t len)
393 {
394         void *imgdata;
395         int ret;
396
397         imgdata = malloc(len);
398         if (!imgdata) {
399                 printf("May be a Legacy Image at NAND device %d offset %08llX:\n",
400                                 nand_dev, off);
401                 printf("   Low memory(cannot allocate memory for image)\n");
402                 return -ENOMEM;
403         }
404
405         ret = nand_read_skip_bad(mtd, off, &len, NULL, mtd->size, imgdata);
406         if (ret < 0 && ret != -EUCLEAN) {
407                 free(imgdata);
408                 return ret;
409         }
410
411         if (!image_check_hcrc(imgdata)) {
412                 free(imgdata);
413                 return 0;
414         }
415
416         printf("Legacy Image at NAND device %d offset %08llX:\n",
417                         nand_dev, off);
418         image_print_contents(imgdata);
419
420         puts("   Verifying Checksum ... ");
421         if (!image_check_dcrc(imgdata))
422                 puts("Bad Data CRC\n");
423         else
424                 puts("OK\n");
425
426         free(imgdata);
427
428         return 0;
429 }
430
431 static int nand_imls_fitimage(struct mtd_info *mtd, int nand_dev, loff_t off,
432                               size_t len)
433 {
434         void *imgdata;
435         int ret;
436
437         imgdata = malloc(len);
438         if (!imgdata) {
439                 printf("May be a FIT Image at NAND device %d offset %08llX:\n",
440                                 nand_dev, off);
441                 printf("   Low memory(cannot allocate memory for image)\n");
442                 return -ENOMEM;
443         }
444
445         ret = nand_read_skip_bad(mtd, off, &len, NULL, mtd->size, imgdata);
446         if (ret < 0 && ret != -EUCLEAN) {
447                 free(imgdata);
448                 return ret;
449         }
450
451         if (!fit_check_format(imgdata)) {
452                 free(imgdata);
453                 return 0;
454         }
455
456         printf("FIT Image at NAND device %d offset %08llX:\n", nand_dev, off);
457
458         fit_print_contents(imgdata);
459         free(imgdata);
460
461         return 0;
462 }
463
464 static int do_imls_nand(void)
465 {
466         struct mtd_info *mtd;
467         int nand_dev = nand_curr_device;
468         size_t len;
469         loff_t off;
470         u32 buffer[16];
471
472         if (nand_dev < 0 || nand_dev >= CONFIG_SYS_MAX_NAND_DEVICE) {
473                 puts("\nNo NAND devices available\n");
474                 return -ENODEV;
475         }
476
477         printf("\n");
478
479         for (nand_dev = 0; nand_dev < CONFIG_SYS_MAX_NAND_DEVICE; nand_dev++) {
480                 mtd = get_nand_dev_by_index(nand_dev);
481                 if (!mtd->name || !mtd->size)
482                         continue;
483
484                 for (off = 0; off < mtd->size; off += mtd->erasesize) {
485                         const image_header_t *header;
486                         int ret;
487
488                         if (nand_block_isbad(mtd, off))
489                                 continue;
490
491                         len = sizeof(buffer);
492
493                         ret = nand_read(mtd, off, &len, (u8 *)buffer);
494                         if (ret < 0 && ret != -EUCLEAN) {
495                                 printf("NAND read error %d at offset %08llX\n",
496                                                 ret, off);
497                                 continue;
498                         }
499
500                         switch (genimg_get_format(buffer)) {
501 #if defined(CONFIG_LEGACY_IMAGE_FORMAT)
502                         case IMAGE_FORMAT_LEGACY:
503                                 header = (const image_header_t *)buffer;
504
505                                 len = image_get_image_size(header);
506                                 nand_imls_legacyimage(mtd, nand_dev, off, len);
507                                 break;
508 #endif
509 #if defined(CONFIG_FIT)
510                         case IMAGE_FORMAT_FIT:
511                                 len = fit_get_size(buffer);
512                                 nand_imls_fitimage(mtd, nand_dev, off, len);
513                                 break;
514 #endif
515                         }
516                 }
517         }
518
519         return 0;
520 }
521 #endif
522
523 #if defined(CONFIG_CMD_IMLS) || defined(CONFIG_CMD_IMLS_NAND)
524 static int do_imls(struct cmd_tbl *cmdtp, int flag, int argc,
525                    char *const argv[])
526 {
527         int ret_nor = 0, ret_nand = 0;
528
529 #if defined(CONFIG_CMD_IMLS)
530         ret_nor = do_imls_nor();
531 #endif
532
533 #if defined(CONFIG_CMD_IMLS_NAND)
534         ret_nand = do_imls_nand();
535 #endif
536
537         if (ret_nor)
538                 return ret_nor;
539
540         if (ret_nand)
541                 return ret_nand;
542
543         return (0);
544 }
545
546 U_BOOT_CMD(
547         imls,   1,              1,      do_imls,
548         "list all images found in flash",
549         "\n"
550         "    - Prints information about all images found at sector/block\n"
551         "      boundaries in nor/nand flash."
552 );
553 #endif