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