bootm: refactor image detection and os load steps
authorKumar Gala <galak@kernel.crashing.org>
Fri, 15 Aug 2008 13:24:41 +0000 (08:24 -0500)
committerWolfgang Denk <wd@denx.de>
Tue, 26 Aug 2008 21:41:43 +0000 (23:41 +0200)
Created a bootm_start() that handles the parsing and detection of all
the images that will be used by the bootm command (OS, ramdisk, fdt).
As part of this we now tract all the relevant image offsets in the
bootm_headers_t struct. This will allow us to have all the needed
state for future sub-commands and lets us reduce a bit of arch
specific code on SPARC.

Created a bootm_load_os() that deals with decompression and loading
the OS image.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
common/cmd_bootm.c
include/image.h
lib_sparc/bootm.c

index dc88e6307b6fc619765b884d81e5f2add2a5d72c..5f7458b80a3e80615cad943f8a30fa1bbfe2ded3 100644 (file)
@@ -150,22 +150,11 @@ void board_lmb_reserve(struct lmb *lmb) __attribute__((weak, alias("__board_lmb_
 # error Unknown CPU type
 #endif
 
-/*******************************************************************/
-/* bootm - boot application image from image in memory */
-/*******************************************************************/
-int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 {
-       ulong           iflag;
-       const char      *type_name;
-       uint            unc_len = CFG_BOOTM_LEN;
-       uint8_t         comp, type, os;
-
-       void            *os_hdr;
-       ulong           os_data, os_len;
-       ulong           image_start, image_end;
-       ulong           load_start, load_end;
        ulong           mem_start;
        phys_size_t     mem_size;
+       void            *os_hdr;
        int             ret;
 
        memset ((void *)&images, 0, sizeof (images));
@@ -182,8 +171,8 @@ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 
        /* get kernel image header, start address and length */
        os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,
-                       &images, &os_data, &os_len);
-       if (os_len == 0) {
+                       &images, &images.os.image_start, &images.os.image_len);
+       if (images.os.image_len == 0) {
                puts ("ERROR: can't get kernel image!\n");
                return 1;
        }
@@ -191,40 +180,40 @@ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
        /* get image parameters */
        switch (genimg_get_format (os_hdr)) {
        case IMAGE_FORMAT_LEGACY:
-               type = image_get_type (os_hdr);
-               comp = image_get_comp (os_hdr);
-               os = image_get_os (os_hdr);
+               images.os.type = image_get_type (os_hdr);
+               images.os.comp = image_get_comp (os_hdr);
+               images.os.os = image_get_os (os_hdr);
 
-               image_end = image_get_image_end (os_hdr);
-               load_start = image_get_load (os_hdr);
+               images.os.end = image_get_image_end (os_hdr);
+               images.os.load = image_get_load (os_hdr);
                break;
 #if defined(CONFIG_FIT)
        case IMAGE_FORMAT_FIT:
                if (fit_image_get_type (images.fit_hdr_os,
-                                       images.fit_noffset_os, &type)) {
+                                       images.fit_noffset_os, &images.os.type)) {
                        puts ("Can't get image type!\n");
                        show_boot_progress (-109);
                        return 1;
                }
 
                if (fit_image_get_comp (images.fit_hdr_os,
-                                       images.fit_noffset_os, &comp)) {
+                                       images.fit_noffset_os, &images.os.comp)) {
                        puts ("Can't get image compression!\n");
                        show_boot_progress (-110);
                        return 1;
                }
 
                if (fit_image_get_os (images.fit_hdr_os,
-                                       images.fit_noffset_os, &os)) {
+                                       images.fit_noffset_os, &images.os.os)) {
                        puts ("Can't get image OS!\n");
                        show_boot_progress (-111);
                        return 1;
                }
 
-               image_end = fit_get_end (images.fit_hdr_os);
+               images.os.end = fit_get_end (images.fit_hdr_os);
 
                if (fit_image_get_load (images.fit_hdr_os, images.fit_noffset_os,
-                                       &load_start)) {
+                                       &images.os.load)) {
                        puts ("Can't get image load address!\n");
                        show_boot_progress (-112);
                        return 1;
@@ -253,7 +242,7 @@ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
                return 1;
        }
 
-       if (os == IH_OS_LINUX) {
+       if (images.os.os == IH_OS_LINUX) {
                /* find ramdisk */
                ret = boot_get_ramdisk (argc, argv, &images, IH_INITRD_ARCH,
                                &images.rd_start, &images.rd_end);
@@ -275,64 +264,52 @@ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 #endif
        }
 
-       image_start = (ulong)os_hdr;
-       load_end = 0;
-       type_name = genimg_get_type_name (type);
+       images.os.start = (ulong)os_hdr;
+       images.valid = 1;
 
-       /*
-        * We have reached the point of no return: we are going to
-        * overwrite all exception vector code, so we cannot easily
-        * recover from any failures any more...
-        */
-       iflag = disable_interrupts();
-
-#if defined(CONFIG_CMD_USB)
-       /*
-        * turn off USB to prevent the host controller from writing to the
-        * SDRAM while Linux is booting. This could happen (at least for OHCI
-        * controller), because the HCCA (Host Controller Communication Area)
-        * lies within the SDRAM and the host controller writes continously to
-        * this area (as busmaster!). The HccaFrameNumber is for example
-        * updated every 1 ms within the HCCA structure in SDRAM! For more
-        * details see the OpenHCI specification.
-        */
-       usb_stop();
-#endif
+       return 0;
+}
 
+#define BOOTM_ERR_RESET                -1
+#define BOOTM_ERR_OVERLAP      -2
+#define BOOTM_ERR_UNIMPLEMENTED        -3
+static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress)
+{
+       uint8_t comp = os.comp;
+       ulong load = os.load;
+       ulong blob_start = os.start;
+       ulong blob_end = os.end;
+       ulong image_start = os.image_start;
+       ulong image_len = os.image_len;
+       uint unc_len = CFG_BOOTM_LEN;
 
-#ifdef CONFIG_AMIGAONEG3SE
-       /*
-        * We've possible left the caches enabled during
-        * bios emulation, so turn them off again
-        */
-       icache_disable();
-       dcache_disable();
-#endif
+       const char *type_name = genimg_get_type_name (os.type);
 
        switch (comp) {
        case IH_COMP_NONE:
-               if (load_start == (ulong)os_hdr) {
+               if (load == blob_start) {
                        printf ("   XIP %s ... ", type_name);
                } else {
                        printf ("   Loading %s ... ", type_name);
 
-                       memmove_wd ((void *)load_start,
-                                  (void *)os_data, os_len, CHUNKSZ);
+                       memmove_wd ((void *)load,
+                                  (void *)image_start, image_len, CHUNKSZ);
                }
-               load_end = load_start + os_len;
+               *load_end = load + image_len;
                puts("OK\n");
                break;
        case IH_COMP_GZIP:
                printf ("   Uncompressing %s ... ", type_name);
-               if (gunzip ((void *)load_start, unc_len,
-                                       (uchar *)os_data, &os_len) != 0) {
+               if (gunzip ((void *)load, unc_len,
+                                       (uchar *)image_start, &image_len) != 0) {
                        puts ("GUNZIP: uncompress or overwrite error "
                                "- must RESET board to recover\n");
-                       show_boot_progress (-6);
-                       do_reset (cmdtp, flag, argc, argv);
+                       if (boot_progress)
+                               show_boot_progress (-6);
+                       return BOOTM_ERR_RESET;
                }
 
-               load_end = load_start + os_len;
+               *load_end = load + image_len;
                break;
 #ifdef CONFIG_BZIP2
        case IH_COMP_BZIP2:
@@ -342,51 +319,110 @@ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
                 * use slower decompression algorithm which requires
                 * at most 2300 KB of memory.
                 */
-               int i = BZ2_bzBuffToBuffDecompress ((char*)load_start,
-                                       &unc_len, (char *)os_data, os_len,
+               int i = BZ2_bzBuffToBuffDecompress ((char*)load,
+                                       &unc_len, (char *)image_start, image_len,
                                        CFG_MALLOC_LEN < (4096 * 1024), 0);
                if (i != BZ_OK) {
                        printf ("BUNZIP2: uncompress or overwrite error %d "
                                "- must RESET board to recover\n", i);
-                       show_boot_progress (-6);
-                       do_reset (cmdtp, flag, argc, argv);
+                       if (boot_progress)
+                               show_boot_progress (-6);
+                       return BOOTM_ERR_RESET;
                }
 
-               load_end = load_start + unc_len;
+               *load_end = load + unc_len;
                break;
 #endif /* CONFIG_BZIP2 */
        default:
-               if (iflag)
-                       enable_interrupts();
                printf ("Unimplemented compression type %d\n", comp);
-               show_boot_progress (-7);
-               return 1;
+               return BOOTM_ERR_UNIMPLEMENTED;
        }
        puts ("OK\n");
-       debug ("   kernel loaded at 0x%08lx, end = 0x%08lx\n", load_start, load_end);
-       show_boot_progress (7);
+       debug ("   kernel loaded at 0x%08lx, end = 0x%08lx\n", load, load_end);
+       if (boot_progress)
+               show_boot_progress (7);
 
-       if ((load_start < image_end) && (load_end > image_start)) {
-               debug ("image_start = 0x%lX, image_end = 0x%lx\n", image_start, image_end);
-               debug ("load_start = 0x%lx, load_end = 0x%lx\n", load_start, load_end);
+       if ((load < blob_end) && (*load_end > blob_start)) {
+               debug ("images.os.start = 0x%lX, images.os.end = 0x%lx\n", blob_start, blob_end);
+               debug ("images.os.load = 0x%lx, load_end = 0x%lx\n", load, load_end);
 
-               if (images.legacy_hdr_valid) {
-                       if (image_get_type (&images.legacy_hdr_os_copy) == IH_TYPE_MULTI)
-                               puts ("WARNING: legacy format multi component "
-                                       "image overwritten\n");
-               } else {
-                       puts ("ERROR: new format image overwritten - "
-                               "must RESET the board to recover\n");
-                       show_boot_progress (-113);
+               return BOOTM_ERR_OVERLAP;
+       }
+
+       return 0;
+}
+
+/*******************************************************************/
+/* bootm - boot application image from image in memory */
+/*******************************************************************/
+int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+
+       ulong           iflag;
+       ulong           load_end = 0;
+       int             ret;
+
+       bootm_start(cmdtp, flag, argc, argv);
+
+       /*
+        * We have reached the point of no return: we are going to
+        * overwrite all exception vector code, so we cannot easily
+        * recover from any failures any more...
+        */
+       iflag = disable_interrupts();
+
+#if defined(CONFIG_CMD_USB)
+       /*
+        * turn off USB to prevent the host controller from writing to the
+        * SDRAM while Linux is booting. This could happen (at least for OHCI
+        * controller), because the HCCA (Host Controller Communication Area)
+        * lies within the SDRAM and the host controller writes continously to
+        * this area (as busmaster!). The HccaFrameNumber is for example
+        * updated every 1 ms within the HCCA structure in SDRAM! For more
+        * details see the OpenHCI specification.
+        */
+       usb_stop();
+#endif
+
+#ifdef CONFIG_AMIGAONEG3SE
+       /*
+        * We've possible left the caches enabled during
+        * bios emulation, so turn them off again
+        */
+       icache_disable();
+       dcache_disable();
+#endif
+
+       ret = bootm_load_os(images.os, &load_end, 1);
+
+       if (ret < 0) {
+               if (ret == BOOTM_ERR_RESET)
                        do_reset (cmdtp, flag, argc, argv);
+               if (ret == BOOTM_ERR_OVERLAP) {
+                       if (images.legacy_hdr_valid) {
+                               if (image_get_type (&images.legacy_hdr_os_copy) == IH_TYPE_MULTI)
+                                       puts ("WARNING: legacy format multi component "
+                                               "image overwritten\n");
+                       } else {
+                               puts ("ERROR: new format image overwritten - "
+                                       "must RESET the board to recover\n");
+                               show_boot_progress (-113);
+                               do_reset (cmdtp, flag, argc, argv);
+                       }
+               }
+               if (ret == BOOTM_ERR_UNIMPLEMENTED) {
+                       if (iflag)
+                               enable_interrupts();
+                       show_boot_progress (-7);
+                       return 1;
                }
        }
 
-       show_boot_progress (8);
+       lmb_reserve(&images.lmb, images.os.load, (load_end - images.os.load));
 
-       lmb_reserve(&images.lmb, load_start, (load_end - load_start));
+       show_boot_progress (8);
 
-       switch (os) {
+       switch (images.os.os) {
        default:                        /* handled by (original) Linux case */
        case IH_OS_LINUX:
 #ifdef CONFIG_SILENT_CONSOLE
index c1acd7b822f636e45ac62d839d9b56e9c78f94f5..9be806e12d7533033c7bd1f7b3358f8c11b1ed37 100644 (file)
@@ -187,6 +187,13 @@ typedef struct image_header {
        uint8_t         ih_name[IH_NMLEN];      /* Image Name           */
 } image_header_t;
 
+typedef struct image_info {
+       ulong           start, end;             /* start/end of blob */
+       ulong           image_start, image_len; /* start of image within blob, len of image */
+       ulong           load;                   /* load addr for the image */
+       uint8_t         comp, type, os;         /* compression, type of image, os type */
+} image_info_t;
+
 /*
  * Legacy and FIT format headers used by do_bootm() and do_bootm_<os>()
  * routines.
@@ -219,6 +226,7 @@ typedef struct bootm_headers {
 #endif
 #endif
 
+       image_info_t    os;             /* os image info */
        ulong           ep;             /* entry point of OS */
 
        ulong           rd_start, rd_end;/* ramdisk start/end */
@@ -229,6 +237,7 @@ typedef struct bootm_headers {
        ulong           ft_len;         /* length of flat device tree */
 
        int             verify;         /* getenv("verify")[0] != 'n' */
+       int             valid;          /* set to 1 if we've set values in the header */
 #ifndef USE_HOSTCC
        struct lmb      lmb;            /* for memory mgmt */
 #endif
index aac05e4b264f65a72c2e5b4a73d2732353b08b5e..f3abdcfdc412d416e69a5a2c92f2b5a738393952 100644 (file)
@@ -87,7 +87,6 @@ void do_bootm_linux(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[],
                    bootm_headers_t * images)
 {
        char *bootargs;
-       ulong load;
        ulong initrd_start, initrd_end;
        ulong rd_len;
        unsigned int data, len, checksum;
@@ -96,24 +95,8 @@ void do_bootm_linux(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[],
        struct lmb *lmb = &images->lmb;
        int ret;
 
-       if (images->legacy_hdr_valid) {
-               load = image_get_load(images->legacy_hdr_os);
-#if defined(CONFIG_FIT)
-       } else if (images->fit_uname_os) {
-               ret = fit_image_get_load(images->fit_hdr_os,
-                                        images->fit_noffset_os, &load);
-               if (ret) {
-                       puts("Can't get load address property!\n");
-                       goto error;
-               }
-#endif
-       } else {
-               puts("Could not find kernel entry point!\n");
-               goto error;
-       }
-
        /* Get virtual address of kernel start */
-       linux_hdr = (void *)load;
+       linux_hdr = (void *)images->os.load;
 
        /* */
        kernel = (void (*)(struct linux_romvec *, void *))images->ep;