linux/arch/ppc/boot/simple/misc-embedded.c
<<
>>
Prefs
   1/*
   2 * Originally adapted by Gary Thomas.  Much additional work by
   3 * Cort Dougan <cort@fsmlabs.com>.  On top of that still more work by
   4 * Dan Malek <dmalek@jlc.net>.
   5 *
   6 * Currently maintained by: Tom Rini <trini@kernel.crashing.org>
   7 */
   8
   9#include <linux/types.h>
  10#include <linux/string.h>
  11#include <asm/bootinfo.h>
  12#include <asm/mmu.h>
  13#include <asm/page.h>
  14#include <asm/residual.h>
  15#if defined(CONFIG_4xx)
  16#include <asm/ibm4xx.h>
  17#elif defined(CONFIG_8xx)
  18#include <asm/mpc8xx.h>
  19#elif defined(CONFIG_8260)
  20#include <asm/mpc8260.h>
  21#endif
  22
  23#include "nonstdio.h"
  24
  25/* The linker tells us where the image is. */
  26extern char __image_begin, __image_end;
  27extern char __ramdisk_begin, __ramdisk_end;
  28extern char _end[];
  29
  30/* Because of the limited amount of memory on embedded, it presents
  31 * loading problems.  The biggest is that we load this boot program
  32 * into a relatively low memory address, and the Linux kernel Bss often
  33 * extends into this space when it get loaded.  When the kernel starts
  34 * and zeros the BSS space, it also writes over the information we
  35 * save here and pass to the kernel (usually board info).
  36 * On these boards, we grab some known memory holes to hold this information.
  37 */
  38char cmd_buf[256];
  39char *cmd_line = cmd_buf;
  40char *avail_ram;
  41char *end_avail;
  42char *zimage_start;
  43
  44/* This is for 4xx treeboot.  It provides a place for the bootrom
  45 * give us a pointer to a rom environment command line.
  46 */
  47char *bootrom_cmdline = "";
  48
  49/* This is the default cmdline that will be given to the user at boot time..
  50 * If none was specified at compile time, we'll give it one that should work.
  51 * -- Tom */
  52#ifdef CONFIG_CMDLINE_BOOL
  53char compiled_string[] = CONFIG_CMDLINE;
  54#endif
  55char ramroot_string[] = "root=/dev/ram";
  56char netroot_string[] = "root=/dev/nfs rw ip=on";
  57
  58/* Serial port to use. */
  59unsigned long com_port;
  60
  61/* We need to make sure that this is before the images to ensure
  62 * that it's in a mapped location. - Tom */
  63bd_t hold_resid_buf __attribute__ ((__section__ (".data.boot")));
  64bd_t *hold_residual = &hold_resid_buf;
  65
  66extern unsigned long serial_init(int chan, bd_t *bp);
  67extern void serial_close(unsigned long com_port);
  68extern unsigned long start;
  69extern void flush_instruction_cache(void);
  70extern void gunzip(void *, int, unsigned char *, int *);
  71extern void embed_config(bd_t **bp);
  72
  73/* Weak function for boards which don't need to build the
  74 * board info struct because they are using PPCBoot/U-Boot.
  75 */
  76void __attribute__ ((weak))
  77embed_config(bd_t **bdp)
  78{
  79}
  80
  81unsigned long
  82load_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *bp)
  83{
  84        char *cp, ch;
  85        int timer = 0, zimage_size;
  86        unsigned long initrd_size;
  87
  88        /* First, capture the embedded board information.  Then
  89         * initialize the serial console port.
  90         */
  91        embed_config(&bp);
  92#if defined(CONFIG_SERIAL_CPM_CONSOLE) || \
  93    defined(CONFIG_SERIAL_8250_CONSOLE) || \
  94    defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
  95        com_port = serial_init(0, bp);
  96#endif
  97
  98        /* Grab some space for the command line and board info.  Since
  99         * we no longer use the ELF header, but it was loaded, grab
 100         * that space.
 101         */
 102#ifdef CONFIG_MBX
 103        /* Because of the way the MBX loads the ELF image, we can't
 104         * tell where we started.  We read a magic variable from the NVRAM
 105         * that gives us the intermediate buffer load address.
 106         */
 107        load_addr = *(uint *)0xfa000020;
 108        load_addr += 0x10000;           /* Skip ELF header */
 109#endif
 110        /* copy board data */
 111        if (bp)
 112                memcpy(hold_residual,bp,sizeof(bd_t));
 113
 114        /* Set end of memory available to us.  It is always the highest
 115         * memory address provided by the board information.
 116         */
 117        end_avail = (char *)(bp->bi_memsize);
 118
 119        puts("\nloaded at:     "); puthex(load_addr);
 120        puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n");
 121        if ( (unsigned long)load_addr != (unsigned long)&start ) {
 122                puts("relocated to:  "); puthex((unsigned long)&start);
 123                puts(" ");
 124                puthex((unsigned long)((unsigned long)&start + (4*num_words)));
 125                puts("\n");
 126        }
 127
 128        if ( bp ) {
 129                puts("board data at: "); puthex((unsigned long)bp);
 130                puts(" ");
 131                puthex((unsigned long)((unsigned long)bp + sizeof(bd_t)));
 132                puts("\nrelocated to:  ");
 133                puthex((unsigned long)hold_residual);
 134                puts(" ");
 135                puthex((unsigned long)((unsigned long)hold_residual + sizeof(bd_t)));
 136                puts("\n");
 137        }
 138
 139        /*
 140         * We link ourself to an arbitrary low address.  When we run, we
 141         * relocate ourself to that address.  __image_being points to
 142         * the part of the image where the zImage is. -- Tom
 143         */
 144        zimage_start = (char *)(unsigned long)(&__image_begin);
 145        zimage_size = (unsigned long)(&__image_end) -
 146                        (unsigned long)(&__image_begin);
 147
 148        initrd_size = (unsigned long)(&__ramdisk_end) -
 149                (unsigned long)(&__ramdisk_begin);
 150
 151        /*
 152         * The zImage and initrd will be between start and _end, so they've
 153         * already been moved once.  We're good to go now. -- Tom
 154         */
 155        puts("zimage at:     "); puthex((unsigned long)zimage_start);
 156        puts(" "); puthex((unsigned long)(zimage_size+zimage_start));
 157        puts("\n");
 158
 159        if ( initrd_size ) {
 160                puts("initrd at:     ");
 161                puthex((unsigned long)(&__ramdisk_begin));
 162                puts(" "); puthex((unsigned long)(&__ramdisk_end));puts("\n");
 163        }
 164
 165        /*
 166         * setup avail_ram - this is the first part of ram usable
 167         * by the uncompress code.  Anything after this program in RAM
 168         * is now fair game. -- Tom
 169         */
 170        avail_ram = (char *)PAGE_ALIGN((unsigned long)_end);
 171
 172        puts("avail ram:     "); puthex((unsigned long)avail_ram); puts(" ");
 173        puthex((unsigned long)end_avail); puts("\n");
 174        puts("\nLinux/PPC load: ");
 175        cp = cmd_line;
 176        /* This is where we try and pick the right command line for booting.
 177         * If we were given one at compile time, use it.  It Is Right.
 178         * If we weren't, see if we have a ramdisk.  If so, thats root.
 179         * When in doubt, give them the netroot (root=/dev/nfs rw) -- Tom
 180         */
 181#ifdef CONFIG_CMDLINE_BOOL
 182        memcpy (cmd_line, compiled_string, sizeof(compiled_string));
 183#else
 184        if ( initrd_size )
 185                memcpy (cmd_line, ramroot_string, sizeof(ramroot_string));
 186        else
 187                memcpy (cmd_line, netroot_string, sizeof(netroot_string));
 188#endif
 189        while ( *cp )
 190                putc(*cp++);
 191        while (timer++ < 5*1000) {
 192                if (tstc()) {
 193                        while ((ch = getc()) != '\n' && ch != '\r') {
 194                                if (ch == '\b' || ch == '\177') {
 195                                        if (cp != cmd_line) {
 196                                                cp--;
 197                                                puts("\b \b");
 198                                        }
 199                                } else if (ch == '\030'         /* ^x */
 200                                           || ch == '\025') {   /* ^u */
 201                                        while (cp != cmd_line) {
 202                                                cp--;
 203                                                puts("\b \b");
 204                                        }
 205                                } else {
 206                                        *cp++ = ch;
 207                                        putc(ch);
 208                                }
 209                        }
 210                        break;  /* Exit 'timer' loop */
 211                }
 212                udelay(1000);  /* 1 msec */
 213        }
 214        *cp = 0;
 215        puts("\nUncompressing Linux...");
 216
 217        gunzip(0, 0x400000, zimage_start, &zimage_size);
 218        flush_instruction_cache();
 219        puts("done.\n");
 220        {
 221                struct bi_record *rec;
 222                unsigned long initrd_loc = 0;
 223                unsigned long rec_loc = _ALIGN((unsigned long)(zimage_size) +
 224                                (1 << 20) - 1, (1 << 20));
 225                rec = (struct bi_record *)rec_loc;
 226
 227                /* We need to make sure that the initrd and bi_recs do not
 228                 * overlap. */
 229                if ( initrd_size ) {
 230                        initrd_loc = (unsigned long)(&__ramdisk_begin);
 231                        /* If the bi_recs are in the middle of the current
 232                         * initrd, move the initrd to the next MB
 233                         * boundary. */
 234                        if ((rec_loc > initrd_loc) &&
 235                                        ((initrd_loc + initrd_size)
 236                                         > rec_loc)) {
 237                                initrd_loc = _ALIGN((unsigned long)(zimage_size)
 238                                                + (2 << 20) - 1, (2 << 20));
 239                                memmove((void *)initrd_loc, &__ramdisk_begin,
 240                                         initrd_size);
 241                                puts("initrd moved:  "); puthex(initrd_loc);
 242                                puts(" "); puthex(initrd_loc + initrd_size);
 243                                puts("\n");
 244                        }
 245                }
 246
 247                rec->tag = BI_FIRST;
 248                rec->size = sizeof(struct bi_record);
 249                rec = (struct bi_record *)((unsigned long)rec + rec->size);
 250
 251                rec->tag = BI_CMD_LINE;
 252                memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1);
 253                rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1;
 254                rec = (struct bi_record *)((unsigned long)rec + rec->size);
 255
 256                if ( initrd_size ) {
 257                        rec->tag = BI_INITRD;
 258                        rec->data[0] = initrd_loc;
 259                        rec->data[1] = initrd_size;
 260                        rec->size = sizeof(struct bi_record) + 2 *
 261                                sizeof(unsigned long);
 262                        rec = (struct bi_record *)((unsigned long)rec +
 263                                        rec->size);
 264                }
 265
 266                rec->tag = BI_LAST;
 267                rec->size = sizeof(struct bi_record);
 268                rec = (struct bi_record *)((unsigned long)rec + rec->size);
 269        }
 270        puts("Now booting the kernel\n");
 271#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE)
 272        serial_close(com_port);
 273#endif
 274
 275        return (unsigned long)hold_residual;
 276}
 277
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.