X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=arch%2Farm%2Flib%2Fbootm.c;h=0325d08ca93d7d619bd04bfcc941777bc6c7c18f;hb=fbbbc86e8ebac4f42f4ca39ceba80cea27c983bc;hp=5ac1302aa6e1c8d6b96bec3c7bc623a2257b2718;hpb=47ea6edfb3004fb2d2a979e19c3f6e4e32f45e51;p=platform%2Fkernel%2Fu-boot.git diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index 5ac1302..0325d08 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -1,4 +1,8 @@ -/* +/* Copyright (C) 2011 + * Corscience GmbH & Co. KG - Simon Schwarz + * - Added prep subcommand support + * - Reorganized source - modeled after powerpc version + * * (C) Copyright 2002 * Sysgo Real-Time Solutions, GmbH * Marius Groeger @@ -18,7 +22,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include @@ -26,109 +29,72 @@ #include #include #include +#include +#include +#include +#include DECLARE_GLOBAL_DATA_PTR; -#if defined (CONFIG_SETUP_MEMORY_TAGS) || \ - defined (CONFIG_CMDLINE_TAG) || \ - defined (CONFIG_INITRD_TAG) || \ - defined (CONFIG_SERIAL_TAG) || \ - defined (CONFIG_REVISION_TAG) -static void setup_start_tag (bd_t *bd); - -# ifdef CONFIG_SETUP_MEMORY_TAGS -static void setup_memory_tags (bd_t *bd); -# endif -static void setup_commandline_tag (bd_t *bd, char *commandline); - -# ifdef CONFIG_INITRD_TAG -static void setup_initrd_tag (bd_t *bd, ulong initrd_start, - ulong initrd_end); -# endif -static void setup_end_tag (bd_t *bd); - static struct tag *params; -#endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */ -int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) +static ulong get_sp(void) { - bd_t *bd = gd->bd; - char *s; - int machid = bd->bi_arch_number; - void (*theKernel)(int zero, int arch, uint params); - -#ifdef CONFIG_CMDLINE_TAG - char *commandline = getenv ("bootargs"); -#endif - - if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) - return 1; + ulong ret; - theKernel = (void (*)(int, int, uint))images->ep; - - s = getenv ("machid"); - if (s) { - machid = simple_strtoul (s, NULL, 16); - printf ("Using machid 0x%x from environment\n", machid); - } + asm("mov %0, sp" : "=r"(ret) : ); + return ret; +} - show_boot_progress (15); +void arch_lmb_reserve(struct lmb *lmb) +{ + ulong sp; + + /* + * Booting a (Linux) kernel image + * + * Allocate space for command line and board info - the + * address should be as high as possible within the reach of + * the kernel (see CONFIG_SYS_BOOTMAPSZ settings), but in unused + * memory, which means far enough below the current stack + * pointer. + */ + sp = get_sp(); + debug("## Current stack ends at 0x%08lx ", sp); - debug ("## Transferring control to Linux (at address %08lx) ...\n", - (ulong) theKernel); + /* adjust sp by 4K to be safe */ + sp -= 4096; + lmb_reserve(lmb, sp, + gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size - sp); +} -#if defined (CONFIG_SETUP_MEMORY_TAGS) || \ - defined (CONFIG_CMDLINE_TAG) || \ - defined (CONFIG_INITRD_TAG) || \ - defined (CONFIG_SERIAL_TAG) || \ - defined (CONFIG_REVISION_TAG) - setup_start_tag (bd); -#ifdef CONFIG_SERIAL_TAG - setup_serial_tag (¶ms); -#endif -#ifdef CONFIG_REVISION_TAG - setup_revision_tag (¶ms); -#endif -#ifdef CONFIG_SETUP_MEMORY_TAGS - setup_memory_tags (bd); -#endif -#ifdef CONFIG_CMDLINE_TAG - setup_commandline_tag (bd, commandline); -#endif -#ifdef CONFIG_INITRD_TAG - if (images->rd_start && images->rd_end) - setup_initrd_tag (bd, images->rd_start, images->rd_end); +/** + * announce_and_cleanup() - Print message and prepare for kernel boot + * + * @fake: non-zero to do everything except actually boot + */ +static void announce_and_cleanup(int fake) +{ + printf("\nStarting kernel ...%s\n\n", fake ? + "(fake run for tracing)" : ""); + bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); +#ifdef CONFIG_BOOTSTAGE_FDT + if (flag == BOOTM_STATE_OS_FAKE_GO) + bootstage_fdt_add_report(); #endif - setup_end_tag (bd); +#ifdef CONFIG_BOOTSTAGE_REPORT + bootstage_report(); #endif - /* we assume that the kernel is in place */ - printf ("\nStarting kernel ...\n\n"); - #ifdef CONFIG_USB_DEVICE - { - extern void udc_disconnect (void); - udc_disconnect (); - } + udc_disconnect(); #endif - - cleanup_before_linux (); - - theKernel (0, machid, bd->bi_boot_params); - /* does not return */ - - return 1; + cleanup_before_linux(); } - -#if defined (CONFIG_SETUP_MEMORY_TAGS) || \ - defined (CONFIG_CMDLINE_TAG) || \ - defined (CONFIG_INITRD_TAG) || \ - defined (CONFIG_SERIAL_TAG) || \ - defined (CONFIG_REVISION_TAG) static void setup_start_tag (bd_t *bd) { - params = (struct tag *) bd->bi_boot_params; + params = (struct tag *)bd->bi_boot_params; params->hdr.tag = ATAG_CORE; params->hdr.size = tag_size (tag_core); @@ -140,9 +106,7 @@ static void setup_start_tag (bd_t *bd) params = tag_next (params); } - -#ifdef CONFIG_SETUP_MEMORY_TAGS -static void setup_memory_tags (bd_t *bd) +static void setup_memory_tags(bd_t *bd) { int i; @@ -156,10 +120,8 @@ static void setup_memory_tags (bd_t *bd) params = tag_next (params); } } -#endif /* CONFIG_SETUP_MEMORY_TAGS */ - -static void setup_commandline_tag (bd_t *bd, char *commandline) +static void setup_commandline_tag(bd_t *bd, char *commandline) { char *p; @@ -184,9 +146,7 @@ static void setup_commandline_tag (bd_t *bd, char *commandline) params = tag_next (params); } - -#ifdef CONFIG_INITRD_TAG -static void setup_initrd_tag (bd_t *bd, ulong initrd_start, ulong initrd_end) +static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end) { /* an ATAG_INITRD node tells the kernel where the compressed * ramdisk can be found. ATAG_RDIMG is a better name, actually. @@ -199,14 +159,11 @@ static void setup_initrd_tag (bd_t *bd, ulong initrd_start, ulong initrd_end) params = tag_next (params); } -#endif /* CONFIG_INITRD_TAG */ -#ifdef CONFIG_SERIAL_TAG -void setup_serial_tag (struct tag **tmp) +static void setup_serial_tag(struct tag **tmp) { struct tag *params = *tmp; struct tag_serialnr serialnr; - void get_board_serial(struct tag_serialnr *serialnr); get_board_serial(&serialnr); params->hdr.tag = ATAG_SERIAL; @@ -216,13 +173,10 @@ void setup_serial_tag (struct tag **tmp) params = tag_next (params); *tmp = params; } -#endif -#ifdef CONFIG_REVISION_TAG -void setup_revision_tag(struct tag **in_params) +static void setup_revision_tag(struct tag **in_params) { u32 rev = 0; - u32 get_board_rev(void); rev = get_board_rev(); params->hdr.tag = ATAG_REVISION; @@ -230,13 +184,139 @@ void setup_revision_tag(struct tag **in_params) params->u.revision.rev = rev; params = tag_next (params); } -#endif /* CONFIG_REVISION_TAG */ - -static void setup_end_tag (bd_t *bd) +static void setup_end_tag(bd_t *bd) { params->hdr.tag = ATAG_NONE; params->hdr.size = 0; } -#endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */ +__weak void setup_board_tags(struct tag **in_params) {} + +/* Subcommand: PREP */ +static void boot_prep_linux(bootm_headers_t *images) +{ + char *commandline = getenv("bootargs"); + + if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) { +#ifdef CONFIG_OF_LIBFDT + debug("using: FDT\n"); + if (image_setup_linux(images)) { + printf("FDT creation failed! hanging..."); + hang(); + } +#endif + } else if (BOOTM_ENABLE_TAGS) { + debug("using: ATAGS\n"); + setup_start_tag(gd->bd); + if (BOOTM_ENABLE_SERIAL_TAG) + setup_serial_tag(¶ms); + if (BOOTM_ENABLE_CMDLINE_TAG) + setup_commandline_tag(gd->bd, commandline); + if (BOOTM_ENABLE_REVISION_TAG) + setup_revision_tag(¶ms); + if (BOOTM_ENABLE_MEMORY_TAGS) + setup_memory_tags(gd->bd); + if (BOOTM_ENABLE_INITRD_TAG) { + if (images->rd_start && images->rd_end) { + setup_initrd_tag(gd->bd, images->rd_start, + images->rd_end); + } + } + setup_board_tags(¶ms); + setup_end_tag(gd->bd); + } else { + printf("FDT and ATAGS support not compiled in - hanging\n"); + hang(); + } +} + +/* Subcommand: GO */ +static void boot_jump_linux(bootm_headers_t *images, int flag) +{ + unsigned long machid = gd->bd->bi_arch_number; + char *s; + void (*kernel_entry)(int zero, int arch, uint params); + unsigned long r2; + int fake = (flag & BOOTM_STATE_OS_FAKE_GO); + + kernel_entry = (void (*)(int, int, uint))images->ep; + + s = getenv("machid"); + if (s) { + strict_strtoul(s, 16, &machid); + printf("Using machid 0x%lx from environment\n", machid); + } + + debug("## Transferring control to Linux (at address %08lx)" \ + "...\n", (ulong) kernel_entry); + bootstage_mark(BOOTSTAGE_ID_RUN_OS); + announce_and_cleanup(fake); + + if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) + r2 = (unsigned long)images->ft_addr; + else + r2 = gd->bd->bi_boot_params; + + if (!fake) + kernel_entry(0, machid, r2); +} + +/* Main Entry point for arm bootm implementation + * + * Modeled after the powerpc implementation + * DIFFERENCE: Instead of calling prep and go at the end + * they are called if subcommand is equal 0. + */ +int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) +{ + /* No need for those on ARM */ + if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE) + return -1; + + if (flag & BOOTM_STATE_OS_PREP) { + boot_prep_linux(images); + return 0; + } + + if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) { + boot_jump_linux(images, flag); + return 0; + } + + boot_prep_linux(images); + boot_jump_linux(images, flag); + return 0; +} + +#ifdef CONFIG_CMD_BOOTZ + +struct zimage_header { + uint32_t code[9]; + uint32_t zi_magic; + uint32_t zi_start; + uint32_t zi_end; +}; + +#define LINUX_ARM_ZIMAGE_MAGIC 0x016f2818 + +int bootz_setup(ulong image, ulong *start, ulong *end) +{ + struct zimage_header *zi; + + zi = (struct zimage_header *)map_sysmem(image, 0); + if (zi->zi_magic != LINUX_ARM_ZIMAGE_MAGIC) { + puts("Bad Linux ARM zImage magic!\n"); + return 1; + } + + *start = zi->zi_start; + *end = zi->zi_end; + + printf("Kernel image @ %#08lx [ %#08lx - %#08lx ]\n", image, *start, + *end); + + return 0; +} + +#endif /* CONFIG_CMD_BOOTZ */