diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2007-07-05 18:02:09 +0200 |
---|---|---|
committer | Sascha Hauer <sha@octopus.labnet.pengutronix.de> | 2007-07-05 18:02:09 +0200 |
commit | 954d38d0baffff3bec60751142f3b28cf7919ffc (patch) | |
tree | 6cdb56a69f33f2959ffcee2151a70d88dfb357fe /arch/ppc | |
parent | d173d87f9179267c6f8f8a90fc0feb30a32b5d21 (diff) | |
download | barebox-954d38d0baffff3bec60751142f3b28cf7919ffc.tar.gz barebox-954d38d0baffff3bec60751142f3b28cf7919ffc.tar.xz |
svn_rev_609
on our way to boot...
Diffstat (limited to 'arch/ppc')
-rw-r--r-- | arch/ppc/lib/ppclinux.c | 418 |
1 files changed, 106 insertions, 312 deletions
diff --git a/arch/ppc/lib/ppclinux.c b/arch/ppc/lib/ppclinux.c index 8ef91a40be..c6ff9871af 100644 --- a/arch/ppc/lib/ppclinux.c +++ b/arch/ppc/lib/ppclinux.c @@ -1,3 +1,4 @@ +#define DEBUG #include <common.h> #include <command.h> @@ -6,6 +7,8 @@ #include <environment.h> #include <asm/global_data.h> #include <asm/bitops.h> +#include <errno.h> +#include <fs.h> #ifdef CONFIG_OF_FLAT_TREE #include <ft_build.h> @@ -13,16 +16,12 @@ extern bd_t *bd; #define SHOW_BOOT_PROGRESS(x) -void __attribute__((noinline)) -do_bootm_linux (cmd_tbl_t *cmdtp, int flag, - int argc, char *argv[], - ulong addr, - ulong *len_ptr, - int verify) +int +do_bootm_linux(image_header_t *os_header, image_header_t *initrd_header, const char *oftree) { ulong sp; ulong len, checksum; - ulong initrd_start, initrd_end; + ulong initrd_start, initrd_end = 0; ulong cmd_start, cmd_end; ulong initrd_high; ulong data; @@ -31,11 +30,89 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, char *s; bd_t *kbd; void (*kernel)(bd_t *, ulong, ulong, ulong, ulong); - image_header_t *hdr = &header; #ifdef CONFIG_OF_FLAT_TREE char *of_flat_tree = NULL; - ulong of_data = 0; +// ulong of_data = 0; #endif + void *os_data = NULL; + void *initrd_data = NULL; + void *of_data = NULL; + unsigned long os_len, initrd_len; + unsigned long *lenp; + + printf("entering %s: os_header: %p initrd_header: %p oftree: %p\n", + __FUNCTION__, os_header, initrd_header, oftree); + + if (os_header->ih_type == IH_TYPE_MULTI) { + unsigned long *data = (unsigned long *)(os_header + 1); + unsigned long len1 = 0, len2 = 0; + + if (!*data) { + printf("multifile image with 0 entries???\n"); + return -1; + } + os_len = ntohl(*data); /* first one is the kernel */ + data++; + + if (*data) { + len1 = ntohl(*data); /* could be initrd or oftree */ + data++; + } + + if (*data) { + len2 = ntohl(*data); /* could be oftree */ + data++; + } + + while (*data) /* skip all remaining files */ + data++; + + data++; /* skip terminating zero */ + + os_data = (void *)ntohl(data); + + if (len2) { + initrd_data = (void *) + ((unsigned long)data + ((os_len + 3) & ~3)); + initrd_len = len1; + of_data = (void *) + ((unsigned long)initrd_data + ((initrd_len + 3) & ~3)); + } else if (len1) { + /* We could check here if this is a multifile image + * with only a kernel and an oftree. Original U-Boot + * did not do this, so leave it out for now. + */ + initrd_data = (void *)((unsigned long)data + ((os_len + 3) & ~3)); + initrd_len = len1; + } + } else { + os_data = (void *)(os_header + 1); + printf("set os_data to %p\n", os_data); + } + + if (initrd_header) + initrd_data = (void *)(initrd_header + 1); + +#ifdef CONFIG_OF_FLAT_TREE + if (oftree) { + image_header_t *oftree_header; + /* The oftree can be given either as an uboot image or as a + * binary blob. First try to read it as an image. + */ + oftree_header = map_image(oftree, 1); + if (oftree_header) { + of_data = (void *)(oftree_header + 1); + } else { + of_data = read_file(oftree); + if (!of_data) { + printf("could not read %s: %s\n", oftree, errno_str()); + return -1; + } + } + /* FIXME: check if this is really an oftree */ + } +#endif + printf("loading kernel.\n"); if ((s = getenv ("initrd_high")) != NULL) { /* a value of "no" or a similar string will act like 0, @@ -80,20 +157,22 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, cmdline = (char *)((sp - CONFIG_CBSIZE) & ~0xF); kbd = (bd_t *)(((ulong)cmdline - sizeof(bd_t)) & ~0xF); + printf("cmdline: %p kbd: %p\n", cmdline, kbd); + if ((s = getenv("bootargs")) == NULL) s = ""; strcpy (cmdline, s); - cmd_start = (ulong)&cmdline[0]; + cmd_start = (ulong)cmdline; cmd_end = cmd_start + strlen(cmdline); - *kbd = *(bd); + init_board_data(kbd); #ifdef DEBUG printf ("## cmdline at 0x%08lX ... 0x%08lX\n", cmd_start, cmd_end); - do_bdinfo (NULL, 0, 0, NULL); +// do_bdinfo (NULL, 0, 0, NULL); #endif if ((s = getenv ("clocks_in_mhz")) != NULL) { @@ -101,11 +180,11 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, kbd->bi_intfreq /= 1000000L; kbd->bi_busfreq /= 1000000L; #if defined(CONFIG_MPC8220) - kbd->bi_inpfreq /= 1000000L; - kbd->bi_pcifreq /= 1000000L; - kbd->bi_pevfreq /= 1000000L; - kbd->bi_flbfreq /= 1000000L; - kbd->bi_vcofreq /= 1000000L; + kbd->bi_inpfreq /= 1000000L; + kbd->bi_pcifreq /= 1000000L; + kbd->bi_pevfreq /= 1000000L; + kbd->bi_flbfreq /= 1000000L; + kbd->bi_vcofreq /= 1000000L; #endif #if defined(CONFIG_CPM2) kbd->bi_cpmfreq /= 1000000L; @@ -119,298 +198,13 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, #endif /* CONFIG_MPC5xxx */ } - kernel = (void (*)(bd_t *, ulong, ulong, ulong, ulong)) ntohl(hdr->ih_ep); - - /* - * Check if there is an initrd image - */ - -#ifdef CONFIG_OF_FLAT_TREE - /* Look for a '-' which indicates to ignore the ramdisk argument */ - if (argc >= 3 && strcmp(argv[2], "-") == 0) { - debug ("Skipping initrd\n"); - len = data = 0; - } - else -#endif - if (argc >= 3) { - debug ("Not skipping initrd\n"); - SHOW_BOOT_PROGRESS (9); - - addr = simple_strtoul(argv[2], NULL, 16); - - printf ("## Loading RAMDisk Image at %08lx ...\n", addr); - - /* Copy header so we can blank CRC field for re-calculation */ - memmove (&header, (char *)addr, sizeof(image_header_t)); - - if (ntohl(hdr->ih_magic) != IH_MAGIC) { - puts ("Bad Magic Number\n"); - SHOW_BOOT_PROGRESS (-10); - do_reset (); - } - - data = (ulong)&header; - len = sizeof(image_header_t); - - checksum = ntohl(hdr->ih_hcrc); - hdr->ih_hcrc = 0; - - if (crc32 (0, (uchar *)data, len) != checksum) { - puts ("Bad Header Checksum\n"); - SHOW_BOOT_PROGRESS (-11); - do_reset(); - } - - SHOW_BOOT_PROGRESS (10); - - print_image_hdr (hdr); - - data = addr + sizeof(image_header_t); - len = ntohl(hdr->ih_size); - - if (verify) { - ulong csum = 0; -#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) - ulong cdata = data, edata = cdata + len; -#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ - - puts (" Verifying Checksum ... "); - -#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) - - while (cdata < edata) { - ulong chunk = edata - cdata; - - if (chunk > CHUNKSZ) - chunk = CHUNKSZ; - csum = crc32 (csum, (uchar *)cdata, chunk); - cdata += chunk; - - WATCHDOG_RESET(); - } -#else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */ - csum = crc32 (0, (uchar *)data, len); -#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ - - if (csum != ntohl(hdr->ih_dcrc)) { - puts ("Bad Data CRC\n"); - SHOW_BOOT_PROGRESS (-12); - do_reset (); - } - puts ("OK\n"); - } - - SHOW_BOOT_PROGRESS (11); - - if ((hdr->ih_os != IH_OS_LINUX) || - (hdr->ih_arch != IH_CPU_PPC) || - (hdr->ih_type != IH_TYPE_RAMDISK) ) { - puts ("No Linux PPC Ramdisk Image\n"); - SHOW_BOOT_PROGRESS (-13); - do_reset (); - } - - /* - * Now check if we have a multifile image - */ - } else if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1])) { - u_long tail = ntohl(len_ptr[0]) % 4; - int i; - - SHOW_BOOT_PROGRESS (13); - - /* skip kernel length and terminator */ - data = (ulong)(&len_ptr[2]); - /* skip any additional image length fields */ - for (i=1; len_ptr[i]; ++i) - data += 4; - /* add kernel length, and align */ - data += ntohl(len_ptr[0]); - if (tail) { - data += 4 - tail; - } - - len = ntohl(len_ptr[1]); - - } else { - /* - * no initrd image - */ - SHOW_BOOT_PROGRESS (14); - - len = data = 0; - } - -#ifdef CONFIG_OF_FLAT_TREE - if(argc > 3) { - of_flat_tree = (char *) simple_strtoul(argv[3], NULL, 16); - hdr = (image_header_t *)of_flat_tree; - - if (*(ulong *)of_flat_tree == OF_DT_HEADER) { -#ifdef CONFIG_OF_FLAT_TREE_FLASH /* FIXME */ - if (addr2info((ulong)of_flat_tree) != NULL) - of_data = (ulong)of_flat_tree; -#endif - } else if (ntohl(hdr->ih_magic) == IH_MAGIC) { - printf("## Flat Device Tree Image at %08lX\n", hdr); - print_image_hdr(hdr); - - if ((ntohl(hdr->ih_load) < ((unsigned long)hdr + ntohl(hdr->ih_size) + sizeof(hdr))) && - ((ntohl(hdr->ih_load) + ntohl(hdr->ih_size)) > (unsigned long)hdr)) { - printf ("ERROR: Load address overwrites Flat Device Tree uImage\n"); - return; - } - - printf(" Verifying Checksum ... "); - memmove (&header, (char *)hdr, sizeof(image_header_t)); - checksum = ntohl(header.ih_hcrc); - header.ih_hcrc = 0; - - if(checksum != crc32(0, (uchar *)&header, sizeof(image_header_t))) { - printf("ERROR: Flat Device Tree header checksum is invalid\n"); - return; - } - - checksum = ntohl(hdr->ih_dcrc); - addr = (ulong)((uchar *)(hdr) + sizeof(image_header_t)); - len = ntohl(hdr->ih_size); - - if(checksum != crc32(0, (uchar *)addr, len)) { - printf("ERROR: Flat Device Tree checksum is invalid\n"); - return; - } - printf("OK\n"); - - if (ntohl(hdr->ih_type) != IH_TYPE_FLATDT) { - printf ("ERROR: uImage not Flat Device Tree type\n"); - return; - } - if (ntohl(hdr->ih_comp) != IH_COMP_NONE) { - printf("ERROR: uImage is not uncompressed\n"); - return; - } - if (*((ulong *)(of_flat_tree + sizeof(image_header_t))) != OF_DT_HEADER) { - printf ("ERROR: uImage data is not a flat device tree\n"); - return; - } - - memmove((void *)ntohl(hdr->ih_load), - (void *)(of_flat_tree + sizeof(image_header_t)), - ntohl(hdr->ih_size)); - of_flat_tree = (char *)ntohl(hdr->ih_load); - } else { - printf ("Did not find a flat flat device tree at address %08lX\n", of_flat_tree); - return; - } - printf (" Booting using flat device tree at 0x%x\n", - of_flat_tree); - } else if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1]) && (len_ptr[2])) { - u_long tail = ntohl(len_ptr[0]) % 4; - int i; - - /* skip kernel length, initrd length, and terminator */ - of_data = (ulong)(&len_ptr[3]); - /* skip any additional image length fields */ - for (i=2; len_ptr[i]; ++i) - of_data += 4; - /* add kernel length, and align */ - of_data += ntohl(len_ptr[0]); - if (tail) { - of_data += 4 - tail; - } - - /* add initrd length, and align */ - tail = ntohl(len_ptr[1]) % 4; - of_data += ntohl(len_ptr[1]); - if (tail) { - of_data += 4 - tail; - } - - if (((struct boot_param_header *)of_data)->magic != OF_DT_HEADER) { - printf ("ERROR: image is not a flat device tree\n"); - return; - } - - if (((struct boot_param_header *)of_data)->totalsize != ntohl(len_ptr[2])) { - printf ("ERROR: flat device tree size does not agree with image\n"); - return; - } - } -#endif - if (!data) { - debug ("No initrd\n"); - } - - if (data) { - if (!initrd_copy_to_ram) { /* zero-copy ramdisk support */ - initrd_start = data; - initrd_end = initrd_start + len; - } else { - initrd_start = (ulong)kbd - len; - initrd_start &= ~(4096 - 1); /* align on page */ - - if (initrd_high) { - ulong nsp; - - /* - * the inital ramdisk does not need to be within - * CFG_BOOTMAPSZ as it is not accessed until after - * the mm system is initialised. - * - * do the stack bottom calculation again and see if - * the initrd will fit just below the monitor stack - * bottom without overwriting the area allocated - * above for command line args and board info. - */ - asm( "mr %0,1": "=r"(nsp) : ); - nsp -= 2048; /* just to be sure */ - nsp &= ~0xF; - if (nsp > initrd_high) /* limit as specified */ - nsp = initrd_high; - nsp -= len; - nsp &= ~(4096 - 1); /* align on page */ - if (nsp >= sp) - initrd_start = nsp; - } - - SHOW_BOOT_PROGRESS (12); - - debug ("## initrd at 0x%08lX ... 0x%08lX (len=%ld=0x%lX)\n", - data, data + len - 1, len, len); - - initrd_end = initrd_start + len; - printf (" Loading Ramdisk to %08lx, end %08lx ... ", - initrd_start, initrd_end); -#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) - { - size_t l = len; - void *to = (void *)initrd_start; - void *from = (void *)data; - - while (l > 0) { - size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l; - WATCHDOG_RESET(); - memmove (to, from, tail); - to += tail; - from += tail; - l -= tail; - } - } -#else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */ - memmove ((void *)initrd_start, (void *)data, len); -#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ - puts ("OK\n"); - } - } else { - initrd_start = 0; - initrd_end = 0; - } + kernel = (void (*)(bd_t *, ulong, ulong, ulong, ulong))(32 * 1024 * 1024); /* FIXME */ - debug ("## Transferring control to Linux (at address %08lx) ...\n", - (ulong)kernel); + printf("uncompressing\n"); + if (relocate_image(os_header, (void *)(32 * 1024 * 1024))) + return -1; + printf("done\n"); - SHOW_BOOT_PROGRESS (15); #if defined(CFG_INIT_RAM_LOCK) && !defined(CONFIG_E500) unlock_ram_in_cache(); @@ -422,8 +216,8 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, ulong of_start, of_len; of_len = ((struct boot_param_header *)of_data)->totalsize; /* provide extra 8k pad */ - if (initrd_start) - of_start = initrd_start - of_len - 8192; + if (initrd_data) + of_start = (unsigned long)initrd_data - of_len - 8192; else of_start = (ulong)kbd - of_len - 8192; of_start &= ~(4096 - 1); /* align on page */ @@ -448,7 +242,7 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, #ifdef CONFIG_OF_FLAT_TREE if (!of_flat_tree) /* no device tree; boot old style */ #endif - (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end); + (*kernel) (kbd, initrd_data, initrd_end, cmd_start, cmd_end); /* does not return */ #ifdef CONFIG_OF_FLAT_TREE @@ -460,8 +254,8 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, * r6: NULL * r7: NULL */ - ft_setup(of_flat_tree, kbd, initrd_start, initrd_end); - /* ft_dump_blob(of_flat_tree); */ + ft_setup(of_flat_tree, kbd, initrd_data, initrd_end); + ft_dump_blob(of_flat_tree); (*kernel) ((bd_t *)of_flat_tree, (ulong)kernel, 0, 0, 0); #endif |