powerpc/83xx: Add i2c eeprom to dts for MPC837x RDB
[safe/jmp/linux-2.6] / arch / powerpc / boot / main.c
index ab9dfe2..a28f021 100644 (file)
 #include "stdio.h"
 #include "ops.h"
 #include "gunzip_util.h"
-#include "flatdevtree.h"
 #include "reg.h"
 
-extern char _start[];
-extern char __bss_start[];
-extern char _end[];
-extern char _vmlinux_start[];
-extern char _vmlinux_end[];
-extern char _initrd_start[];
-extern char _initrd_end[];
-extern char _dtb_start[];
-extern char _dtb_end[];
-
 static struct gunzip_state gzstate;
 
 struct addr_range {
@@ -36,76 +25,8 @@ struct addr_range {
        unsigned long size;
 };
 
-struct elf_info {
-       unsigned long loadsize;
-       unsigned long memsize;
-       unsigned long elfoffset;
-};
-
-typedef void (*kernel_entry_t)(unsigned long, unsigned long, void *);
-
 #undef DEBUG
 
-static int parse_elf64(void *hdr, struct elf_info *info)
-{
-       Elf64_Ehdr *elf64 = hdr;
-       Elf64_Phdr *elf64ph;
-       unsigned int i;
-
-       if (!(elf64->e_ident[EI_MAG0]  == ELFMAG0       &&
-             elf64->e_ident[EI_MAG1]  == ELFMAG1       &&
-             elf64->e_ident[EI_MAG2]  == ELFMAG2       &&
-             elf64->e_ident[EI_MAG3]  == ELFMAG3       &&
-             elf64->e_ident[EI_CLASS] == ELFCLASS64    &&
-             elf64->e_ident[EI_DATA]  == ELFDATA2MSB   &&
-             elf64->e_type            == ET_EXEC       &&
-             elf64->e_machine         == EM_PPC64))
-               return 0;
-
-       elf64ph = (Elf64_Phdr *)((unsigned long)elf64 +
-                                (unsigned long)elf64->e_phoff);
-       for (i = 0; i < (unsigned int)elf64->e_phnum; i++, elf64ph++)
-               if (elf64ph->p_type == PT_LOAD)
-                       break;
-       if (i >= (unsigned int)elf64->e_phnum)
-               return 0;
-
-       info->loadsize = (unsigned long)elf64ph->p_filesz;
-       info->memsize = (unsigned long)elf64ph->p_memsz;
-       info->elfoffset = (unsigned long)elf64ph->p_offset;
-
-       return 1;
-}
-
-static int parse_elf32(void *hdr, struct elf_info *info)
-{
-       Elf32_Ehdr *elf32 = hdr;
-       Elf32_Phdr *elf32ph;
-       unsigned int i;
-
-       if (!(elf32->e_ident[EI_MAG0]  == ELFMAG0       &&
-             elf32->e_ident[EI_MAG1]  == ELFMAG1       &&
-             elf32->e_ident[EI_MAG2]  == ELFMAG2       &&
-             elf32->e_ident[EI_MAG3]  == ELFMAG3       &&
-             elf32->e_ident[EI_CLASS] == ELFCLASS32    &&
-             elf32->e_ident[EI_DATA]  == ELFDATA2MSB   &&
-             elf32->e_type            == ET_EXEC       &&
-             elf32->e_machine         == EM_PPC))
-               return 0;
-
-       elf32ph = (Elf32_Phdr *) ((unsigned long)elf32 + elf32->e_phoff);
-       for (i = 0; i < elf32->e_phnum; i++, elf32ph++)
-               if (elf32ph->p_type == PT_LOAD)
-                       break;
-       if (i >= elf32->e_phnum)
-               return 0;
-
-       info->loadsize = elf32ph->p_filesz;
-       info->memsize = elf32ph->p_memsz;
-       info->elfoffset = elf32ph->p_offset;
-       return 1;
-}
-
 static struct addr_range prep_kernel(void)
 {
        char elfheader[256];
@@ -135,9 +56,19 @@ static struct addr_range prep_kernel(void)
        if (platform_ops.vmlinux_alloc) {
                addr = platform_ops.vmlinux_alloc(ei.memsize);
        } else {
-               if ((unsigned long)_start < ei.memsize)
+               /*
+                * Check if the kernel image (without bss) would overwrite the
+                * bootwrapper. The device tree has been moved in fdt_init()
+                * to an area allocated with malloc() (somewhere past _end).
+                */
+               if ((unsigned long)_start < ei.loadsize)
                        fatal("Insufficient memory for kernel at address 0!"
-                              " (_start=%p)\n\r", _start);
+                              " (_start=%p, uncompressed size=%08lx)\n\r",
+                              _start, ei.loadsize);
+
+               if ((unsigned long)_end < ei.memsize)
+                       fatal("The final kernel image would overwrite the "
+                                       "device tree\n\r");
        }
 
        /* Finally, gunzip the kernel */
@@ -145,7 +76,10 @@ static struct addr_range prep_kernel(void)
               vmlinuz_addr, vmlinuz_addr+vmlinuz_size);
        /* discard up to the actual load data */
        gunzip_discard(&gzstate, ei.elfoffset - sizeof(elfheader));
-       len = gunzip_finish(&gzstate, addr, ei.memsize);
+       len = gunzip_finish(&gzstate, addr, ei.loadsize);
+       if (len != ei.loadsize)
+               fatal("ran out of data!  only got 0x%x of 0x%lx bytes.\n\r",
+                               len, ei.loadsize);
        printf("done 0x%x bytes\n\r", len);
 
        flush_cache(addr, ei.loadsize);
@@ -205,31 +139,22 @@ static struct addr_range prep_initrd(struct addr_range vmlinux, void *chosen,
  * edit the command line passed to vmlinux (by setting /chosen/bootargs).
  * The buffer is put in it's own section so that tools may locate it easier.
  */
-static char builtin_cmdline[COMMAND_LINE_SIZE]
+static char cmdline[COMMAND_LINE_SIZE]
        __attribute__((__section__("__builtin_cmdline")));
 
-static void get_cmdline(char *buf, int size)
+static void prep_cmdline(void *chosen)
 {
-       void *devp;
-       int len = strlen(builtin_cmdline);
-
-       buf[0] = '\0';
-
-       if (len > 0) { /* builtin_cmdline overrides dt's /chosen/bootargs */
-               len = min(len, size-1);
-               strncpy(buf, builtin_cmdline, len);
-               buf[len] = '\0';
-       }
-       else if ((devp = finddevice("/chosen")))
-               getprop(devp, "bootargs", buf, size);
-}
+       if (cmdline[0] == '\0')
+               getprop(chosen, "bootargs", cmdline, COMMAND_LINE_SIZE-1);
 
-static void set_cmdline(char *buf)
-{
-       void *devp;
+       printf("\n\rLinux/PowerPC load: %s", cmdline);
+       /* If possible, edit the command line */
+       if (console_ops.edit_cmdline)
+               console_ops.edit_cmdline(cmdline, COMMAND_LINE_SIZE);
+       printf("\n\r");
 
-       if ((devp = finddevice("/chosen")))
-               setprop(devp, "bootargs", buf, strlen(buf) + 1);
+       /* Put the command line back into the devtree for the kernel */
+       setprop_str(chosen, "bootargs", cmdline);
 }
 
 struct platform_ops platform_ops;
@@ -241,10 +166,16 @@ void start(void)
 {
        struct addr_range vmlinux, initrd;
        kernel_entry_t kentry;
-       char cmdline[COMMAND_LINE_SIZE];
        unsigned long ft_addr = 0;
        void *chosen;
 
+       /* Do this first, because malloc() could clobber the loader's
+        * command line.  Only use the loader command line if a
+        * built-in command line wasn't set by an external tool */
+       if ((loader_info.cmdline_len > 0) && (cmdline[0] == '\0'))
+               memmove(cmdline, loader_info.cmdline,
+                       min(loader_info.cmdline_len, COMMAND_LINE_SIZE-1));
+
        if (console_ops.open && (console_ops.open() < 0))
                exit();
        if (platform_ops.fixups)
@@ -261,18 +192,7 @@ void start(void)
        vmlinux = prep_kernel();
        initrd = prep_initrd(vmlinux, chosen,
                             loader_info.initrd_addr, loader_info.initrd_size);
-
-       /* If cmdline came from zimage wrapper or if we can edit the one
-        * in the dt, print it out and edit it, if possible.
-        */
-       if ((strlen(builtin_cmdline) > 0) || console_ops.edit_cmdline) {
-               get_cmdline(cmdline, COMMAND_LINE_SIZE);
-               printf("\n\rLinux/PowerPC load: %s", cmdline);
-               if (console_ops.edit_cmdline)
-                       console_ops.edit_cmdline(cmdline, COMMAND_LINE_SIZE);
-               printf("\n\r");
-               set_cmdline(cmdline);
-       }
+       prep_cmdline(chosen);
 
        printf("Finalizing device tree...");
        if (dt_ops.finalize)