]> git.sur5r.net Git - u-boot/blobdiff - lib_m68k/m68k_linux.c
86xx: Fix compilation warning in sys_eprom.c
[u-boot] / lib_m68k / m68k_linux.c
index a32de1a907ef6e8f02dc41a4587d4315e4b23f4f..cc974c2d60d7dfb4f5f8aa28f47a54b01ff50e9e 100644 (file)
 #include <command.h>
 #include <image.h>
 #include <zlib.h>
+#include <bzlib.h>
+#include <watchdog.h>
+#include <environment.h>
 #include <asm/byteorder.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 #define PHYSADDR(x) x
 
 #define LINUX_MAX_ENVS         256
 #define LINUX_MAX_ARGS         256
 
+#define CHUNKSZ                        (64 * 1024)
+
 #ifdef CONFIG_SHOW_BOOT_PROGRESS
 # include <status_led.h>
 # define SHOW_BOOT_PROGRESS(arg)       show_boot_progress(arg)
 # define SHOW_BOOT_PROGRESS(arg)
 #endif
 
-extern image_header_t header;  /* from cmd_bootm.c */
+extern image_header_t header;
+
+void do_bootm_linux(cmd_tbl_t * cmdtp, int flag,
+                   int argc, char *argv[],
+                   ulong addr, ulong * len_ptr, int verify)
+{
+       ulong sp;
+       ulong len, checksum;
+       ulong initrd_start, initrd_end;
+       ulong cmd_start, cmd_end;
+       ulong initrd_high;
+       ulong data;
+       int initrd_copy_to_ram = 1;
+       char *cmdline;
+       char *s;
+       bd_t *kbd;
+       void (*kernel) (bd_t *, ulong, ulong, ulong, ulong);
+       image_header_t *hdr = &header;
+
+       if ((s = getenv("initrd_high")) != NULL) {
+               /* a value of "no" or a similar string will act like 0,
+                * turning the "load high" feature off. This is intentional.
+                */
+               initrd_high = simple_strtoul(s, NULL, 16);
+               if (initrd_high == ~0)
+                       initrd_copy_to_ram = 0;
+       } else {                /* not set, no restrictions to load high */
+               initrd_high = ~0;
+       }
+
+#ifdef CONFIG_LOGBUFFER
+       kbd = gd->bd;
+       /* Prevent initrd from overwriting logbuffer */
+       if (initrd_high < (kbd->bi_memsize - LOGBUFF_LEN - LOGBUFF_OVERHEAD))
+               initrd_high = kbd->bi_memsize - LOGBUFF_LEN - LOGBUFF_OVERHEAD;
+       debug("## Logbuffer at 0x%08lX ", kbd->bi_memsize - LOGBUFF_LEN);
+#endif
 
-extern int do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]);
+       /*
+        * 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 CFG_BOOTMAPSZ settings), but in unused
+        * memory, which means far enough below the current stack
+        * pointer.
+        */
+       asm("movel %%a7, %%d0\n"
+           "movel %%d0, %0\n": "=d"(sp): :"%d0");
 
-static int linux_argc;
-static char **linux_argv;
+       debug("## Current stack ends at 0x%08lX ", sp);
 
-static char **linux_env;
-static char *linux_env_p;
-static int linux_env_idx;
+       sp -= 2048;             /* just to be sure */
+       if (sp > CFG_BOOTMAPSZ)
+               sp = CFG_BOOTMAPSZ;
+       sp &= ~0xF;
 
-static void linux_params_init (ulong start, char *commandline);
-static void linux_env_set (char *env_name, char *env_val);
+       debug("=> set upper limit to 0x%08lX\n", sp);
 
-void do_bootm_linux (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[],
-                    ulong addr, ulong * len_ptr, int verify)
-{
-       DECLARE_GLOBAL_DATA_PTR;
+       cmdline = (char *)((sp - CFG_BARGSIZE) & ~0xF);
+       kbd = (bd_t *) (((ulong) cmdline - sizeof(bd_t)) & ~0xF);
 
-       ulong len = 0, checksum;
-       ulong initrd_start, initrd_end;
-       ulong data;
-       void (*theKernel) (int, char **, char **, int *);
-       image_header_t *hdr = &header;
-       char *commandline = getenv ("bootargs");
-       char env_buf[12];
+       if ((s = getenv("bootargs")) == NULL)
+               s = "";
 
-       theKernel =
-               (void (*)(int, char **, char **, int *)) ntohl (hdr->ih_ep);
+       strcpy(cmdline, s);
+
+       cmd_start = (ulong) & cmdline[0];
+       cmd_end = cmd_start + strlen(cmdline);
+
+       *kbd = *(gd->bd);
+
+#ifdef DEBUG
+       printf("## cmdline at 0x%08lX ... 0x%08lX\n", cmd_start, cmd_end);
+
+       do_bdinfo(NULL, 0, 0, NULL);
+#endif
+
+       if ((s = getenv("clocks_in_mhz")) != NULL) {
+               /* convert all clock information to MHz */
+               kbd->bi_intfreq /= 1000000L;
+               kbd->bi_busfreq /= 1000000L;
+       }
+
+       kernel =
+           (void (*)(bd_t *, ulong, ulong, ulong, ulong))ntohl(hdr->ih_ep);
 
        /*
         * Check if there is an initrd image
         */
+
        if (argc >= 3) {
-               SHOW_BOOT_PROGRESS (9);
+               debug("Not skipping initrd\n");
+               SHOW_BOOT_PROGRESS(9);
 
-               addr = simple_strtoul (argv[2], NULL, 16);
+               addr = simple_strtoul(argv[2], NULL, 16);
 
-               printf ("## Loading Ramdisk Image at %08lx ...\n", addr);
+               printf("## Loading RAMDisk Image at %08lx ...\n", addr);
 
                /* Copy header so we can blank CRC field for re-calculation */
-               memcpy (&header, (char *) addr, sizeof (image_header_t));
+               memmove(&header, (char *)addr, sizeof(image_header_t));
 
-               if (ntohl (hdr->ih_magic) != IH_MAGIC) {
-                       printf ("Bad Magic Number\n");
-                       SHOW_BOOT_PROGRESS (-10);
-                       do_reset (cmdtp, flag, argc, argv);
+               if (ntohl(hdr->ih_magic) != IH_MAGIC) {
+                       puts("Bad Magic Number\n");
+                       SHOW_BOOT_PROGRESS(-10);
+                       do_reset(cmdtp, flag, argc, argv);
                }
 
                data = (ulong) & header;
-               len = sizeof (image_header_t);
+               len = sizeof(image_header_t);
 
-               checksum = ntohl (hdr->ih_hcrc);
+               checksum = ntohl(hdr->ih_hcrc);
                hdr->ih_hcrc = 0;
 
-               if (crc32 (0, (char *) data, len) != checksum) {
-                       printf ("Bad Header Checksum\n");
-                       SHOW_BOOT_PROGRESS (-11);
-                       do_reset (cmdtp, flag, argc, argv);
+               if (crc32(0, (uchar *) data, len) != checksum) {
+                       puts("Bad Header Checksum\n");
+                       SHOW_BOOT_PROGRESS(-11);
+                       do_reset(cmdtp, flag, argc, argv);
                }
 
-               SHOW_BOOT_PROGRESS (10);
+               SHOW_BOOT_PROGRESS(10);
 
-               print_image_hdr (hdr);
+               print_image_hdr(hdr);
 
-               data = addr + sizeof (image_header_t);
-               len = ntohl (hdr->ih_size);
+               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;
 
-                       printf ("   Verifying Checksum ... ");
-                       csum = crc32 (0, (char *) data, len);
-                       if (csum != ntohl (hdr->ih_dcrc)) {
-                               printf ("Bad Data CRC\n");
-                               SHOW_BOOT_PROGRESS (-12);
-                               do_reset (cmdtp, flag, argc, argv);
+                               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(cmdtp, flag, argc, argv);
                        }
-                       printf ("OK\n");
+                       puts("OK\n");
                }
 
-               SHOW_BOOT_PROGRESS (11);
+               SHOW_BOOT_PROGRESS(11);
 
                if ((hdr->ih_os != IH_OS_LINUX) ||
                    (hdr->ih_arch != IH_CPU_M68K) ||
                    (hdr->ih_type != IH_TYPE_RAMDISK)) {
-                       printf ("No Linux M68K Ramdisk Image\n");
-                       SHOW_BOOT_PROGRESS (-13);
-                       do_reset (cmdtp, flag, argc, argv);
+                       puts("No Linux ColdFire Ramdisk Image\n");
+                       SHOW_BOOT_PROGRESS(-13);
+                       do_reset(cmdtp, flag, argc, argv);
                }
 
                /*
                 * Now check if we have a multifile image
                 */
        } else if ((hdr->ih_type == IH_TYPE_MULTI) && (len_ptr[1])) {
-               ulong tail = ntohl (len_ptr[0]) % 4;
+               u_long tail = ntohl(len_ptr[0]) % 4;
                int i;
 
-               SHOW_BOOT_PROGRESS (13);
+               SHOW_BOOT_PROGRESS(13);
 
                /* skip kernel length and terminator */
                data = (ulong) (&len_ptr[2]);
@@ -145,130 +230,111 @@ void do_bootm_linux (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[],
                for (i = 1; len_ptr[i]; ++i)
                        data += 4;
                /* add kernel length, and align */
-               data += ntohl (len_ptr[0]);
+               data += ntohl(len_ptr[0]);
                if (tail) {
                        data += 4 - tail;
                }
 
-               len = ntohl (len_ptr[1]);
+               len = ntohl(len_ptr[1]);
 
        } else {
                /*
                 * no initrd image
                 */
-               SHOW_BOOT_PROGRESS (14);
+               SHOW_BOOT_PROGRESS(14);
 
-               data = 0;
+               len = data = 0;
        }
 
-#ifdef DEBUG
        if (!data) {
-               printf ("No initrd\n");
+               debug("No initrd\n");
        }
-#endif
 
        if (data) {
-               initrd_start = data;
-               initrd_end = initrd_start + len;
-       } else {
-               initrd_start = 0;
-               initrd_end = 0;
-       }
-
-       SHOW_BOOT_PROGRESS (15);
-
-#ifdef DEBUG
-       printf ("## Transferring control to Linux (at address %08lx) ...\n",
-               (ulong) theKernel);
-#endif
-
-       linux_params_init (PHYSADDR (gd->bd->bi_boot_params), commandline);
-
-       sprintf (env_buf, "%lu", gd->ram_size >> 20);
-       linux_env_set ("memsize", env_buf);
-
-       sprintf (env_buf, "0x%08X", (uint) PHYSADDR (initrd_start));
-       linux_env_set ("initrd_start", env_buf);
-
-       sprintf (env_buf, "0x%X", (uint) (initrd_end - initrd_start));
-       linux_env_set ("initrd_size", env_buf);
-
-       sprintf (env_buf, "0x%08X", (uint) (gd->bd->bi_flashstart));
-       linux_env_set ("flash_start", env_buf);
-
-       sprintf (env_buf, "0x%X", (uint) (gd->bd->bi_flashsize));
-       linux_env_set ("flash_size", env_buf);
-
-       /* we assume that the kernel is in place */
-       printf ("\nStarting kernel ...\n\n");
-
-       theKernel (linux_argc, linux_argv, linux_env, 0);
-}
-
-static void linux_params_init (ulong start, char *line)
-{
-       char *next, *quote, *argp;
-
-       linux_argc = 1;
-       linux_argv = (char **) start;
-       linux_argv[0] = 0;
-       argp = (char *) (linux_argv + LINUX_MAX_ARGS);
-
-       next = line;
-
-       while (line && *line && linux_argc < LINUX_MAX_ARGS) {
-               quote = strchr (line, '"');
-               next = strchr (line, ' ');
-
-               while (next != NULL && quote != NULL && quote < next) {
-                       /* we found a left quote before the next blank
-                        * now we have to find the matching right quote
-                        */
-                       next = strchr (quote + 1, '"');
-                       if (next != NULL) {
-                               quote = strchr (next + 1, '"');
-                               next = strchr (next + 1, ' ');
+               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("movel %%a7, %%d0\n"
+                                   "movel %%d0, %0\n": "=d"(nsp): :"%d0");
+
+                               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;
                        }
-               }
 
-               if (next == NULL) {
-                       next = line + strlen (line);
+                       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");
                }
-
-               linux_argv[linux_argc] = argp;
-               memcpy (argp, line, next - line);
-               argp[next - line] = 0;
-
-               argp += next - line + 1;
-               linux_argc++;
-
-               if (*next)
-                       next++;
-
-               line = next;
+       } else {
+               initrd_start = 0;
+               initrd_end = 0;
        }
 
-       linux_env = (char **) (((ulong) argp + 15) & ~15);
-       linux_env[0] = 0;
-       linux_env_p = (char *) (linux_env + LINUX_MAX_ENVS);
-       linux_env_idx = 0;
-}
-
-static void linux_env_set (char *env_name, char *env_val)
-{
-       if (linux_env_idx < LINUX_MAX_ENVS - 1) {
-               linux_env[linux_env_idx] = linux_env_p;
-
-               strcpy (linux_env_p, env_name);
-               linux_env_p += strlen (env_name);
+       debug("## Transferring control to Linux (at address %08lx) ...\n",
+             (ulong) kernel);
 
-               strcpy (linux_env_p, "=");
-               linux_env_p += 1;
+       SHOW_BOOT_PROGRESS(15);
 
-               strcpy (linux_env_p, env_val);
-               linux_env_p += strlen (env_val);
-
-               linux_env_p++;
-               linux_env[++linux_env_idx] = 0;
-       }
+       /*
+        * Linux Kernel Parameters (passing board info data):
+        *   r3: ptr to board info data
+        *   r4: initrd_start or 0 if no initrd
+        *   r5: initrd_end - unused if r4 is 0
+        *   r6: Start of command line string
+        *   r7: End   of command line string
+        */
+       (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end);
+       /* does not return */
 }