Fix initramfs loading bug introduced in f407b0626f0160fa8cca67c548c8de38c8353e16
[qi.git] / src / phase2.c
1 /*
2  * (C) Copyright 2008 Openmoko, Inc.
3  * Author: Andy Green <andy@openmoko.org>
4  *
5  * Parse the U-Boot header and Boot Linux
6  * based on various code from U-Boot
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 #include <qi.h>
25 #include <neo_gta02.h>
26 #include "blink_led.h"
27 #include <string.h>
28 #define __ARM__
29 #include <image.h>
30 #include <setup.h>
31 #include "nand_read.h"
32 #include <ext2.h>
33
34 unsigned long partition_offset_blocks = 0;
35 unsigned long partition_length_blocks = 0;
36
37 struct kernel_source const * this_kernel = 0;
38
39
40 void bootloader_second_phase(void)
41 {
42         void    (*the_kernel)(int zero, int arch, uint params);
43         int kernel = 0;
44         const struct board_variant * board_variant =
45                                               (this_board->get_board_variant)();
46
47         /* we try the possible kernels for this board in order */
48
49         this_kernel = &this_board->kernel_source[kernel++];
50
51         while (this_kernel->name) {
52                 const char *p;
53                 struct tag *params = (struct tag *)this_board->linux_tag_placement;
54                 void * kernel_dram = (void *)(TEXT_BASE - (8 * 1024 * 1024));
55                 unsigned long crc;
56                 image_header_t  *hdr;
57                 u32 kernel_size;
58
59                 partition_offset_blocks = 0;
60                 partition_length_blocks = 0;
61
62                 /* eat leading white space */
63                 for (p = this_kernel->commandline; *p == ' '; p++);
64
65                 puts("\n\nTrying kernel: ");
66                 puts(this_kernel->name);
67                 puts("\n");
68
69                 /* if this device needs initializing, try to init it */
70                 if (this_kernel->block_init)
71                         if ((this_kernel->block_init)()) {
72                                 puts("block device init failed\n");
73                                 this_kernel = &this_board->
74                                                         kernel_source[kernel++];
75                                 continue;
76                         }
77
78                 /* if there's a partition table implied, parse it, otherwise
79                  * just use a fixed offset
80                  */
81                 if (this_kernel->partition_index) {
82                         unsigned char *p = kernel_dram;
83
84                         if (this_kernel->block_read(kernel_dram, 0, 4) < 0) {
85                                 puts("Bad partition read\n");
86                                 this_kernel = &this_board->
87                                                         kernel_source[kernel++];
88                                 continue;
89                         }
90
91                         if ((p[0x1fe] != 0x55) || (p[0x1ff] != 0xaa)) {
92                                 puts("partition signature missing\n");
93                                 this_kernel = &this_board->
94                                                         kernel_source[kernel++];
95                                 continue;
96                         }
97
98                         p += 0x1be + 8 + (0x10 *
99                                             (this_kernel->partition_index - 1));
100
101                         partition_offset_blocks = (((u32)p[3]) << 24) |
102                                                   (((u32)p[2]) << 16) |
103                                                   (((u32)p[1]) << 8) |
104                                                   p[0];
105                         partition_length_blocks = (((u32)p[7]) << 24) |
106                                                   (((u32)p[6]) << 16) |
107                                                   (((u32)p[5]) << 8) |
108                                                   p[4];
109
110                         puts("    Partition: ");
111                         printdec(this_kernel->partition_index);
112                         puts(" start +");
113                         printdec(partition_offset_blocks);
114                         puts(" 512-byte blocks, size ");
115                         printdec(partition_length_blocks / 2048);
116                         puts(" MiB\n");
117
118                 } else
119                         partition_offset_blocks =
120                                   this_kernel->offset_blocks512_if_no_partition;
121
122                 switch (this_kernel->filesystem) {
123                 case FS_EXT2:
124                         if (!ext2fs_mount()) {
125                                 puts("Unable to mount ext2 filesystem\n");
126                                 this_kernel = &this_board->
127                                                         kernel_source[kernel++];
128                                 continue;
129                         }
130                         puts("    EXT2 open: ");
131                         puts(this_kernel->filepath);
132                         puts("\n");
133                         if (ext2fs_open(this_kernel->filepath) < 0) {
134                                 puts("Open failed\n");
135                                 this_kernel = &this_board->
136                                                         kernel_source[kernel++];
137                                 continue;
138                         }
139                         ext2fs_read(kernel_dram, 4096);
140                         break;
141                 case FS_FAT:
142                         /* FIXME */
143                 case FS_RAW:
144                         puts("     RAW open: +");
145                         printdec(partition_offset_blocks);
146                         puts(" 512-byte blocks\n");
147                         if (this_kernel->block_read(kernel_dram,
148                                               partition_offset_blocks, 8) < 0) {
149                                 puts ("Bad kernel header\n");
150                                 this_kernel = &this_board->
151                                                         kernel_source[kernel++];
152                                 continue;
153                         }
154                         break;
155                 }
156
157                 hdr = (image_header_t *)kernel_dram;
158
159                 if (__be32_to_cpu(hdr->ih_magic) != IH_MAGIC) {
160                         puts("bad magic ");
161                         print32(hdr->ih_magic);
162                         puts("\n");
163                         this_kernel = &this_board->kernel_source[kernel++];
164                         continue;
165                 }
166
167                 puts("        Found: \"");
168                 puts((const char *)hdr->ih_name);
169                 puts("\"\n         Size: ");
170                 printdec(__be32_to_cpu(hdr->ih_size) >> 10);
171                 puts(" KiB\n");
172
173                 kernel_size = ((__be32_to_cpu(hdr->ih_size) +
174                                   sizeof(image_header_t) + 2048) & ~(2048 - 1));
175
176                 switch (this_kernel->filesystem) {
177                 case FS_EXT2:
178                         /* This read API always restarts from beginning */
179                         ext2fs_read(kernel_dram, kernel_size);
180                         break;
181                 case FS_FAT:
182                         /* FIXME */
183                 case FS_RAW:
184                         if ((this_kernel->block_read)(
185                                 kernel_dram, partition_offset_blocks,
186                                                 kernel_size >> 9) < 0) {
187                                 puts ("Bad kernel read\n");
188                                 this_kernel = &this_board->
189                                                         kernel_source[kernel++];
190                                 continue;
191                         }
192                         break;
193                 }
194
195                 puts("      Cmdline: ");
196                 puts(p);
197                 puts("\n");
198
199                 /*
200                  * It's good for now to know that our kernel is intact from
201                  * the storage before we jump into it and maybe crash silently
202                  * even though it costs us some time
203                  */
204                 crc = crc32(0, kernel_dram + sizeof(image_header_t),
205                                                    __be32_to_cpu(hdr->ih_size));
206                 if (crc != __be32_to_cpu(hdr->ih_dcrc)) {
207                         puts("\nKernel CRC ERROR: read 0x");
208                         print32(crc);
209                         puts(" vs hdr CRC 0x");
210                         print32(__be32_to_cpu(hdr->ih_dcrc));
211                         puts("\n");
212                         this_kernel = &this_board->kernel_source[kernel++];
213                         continue;
214                 }
215
216                 the_kernel = (void (*)(int, int, uint))
217                                         (((char *)hdr) + sizeof(image_header_t));
218
219                 /* first tag */
220                 params->hdr.tag = ATAG_CORE;
221                 params->hdr.size = tag_size (tag_core);
222                 params->u.core.flags = 0;
223                 params->u.core.pagesize = 0;
224                 params->u.core.rootdev = 0;
225                 params = tag_next(params);
226
227                 /* revision tag */
228                 params->hdr.tag = ATAG_REVISION;
229                 params->hdr.size = tag_size (tag_revision);
230                 params->u.revision.rev = board_variant->machine_revision;
231                 params = tag_next(params);
232
233                 /* memory tags */
234                 params->hdr.tag = ATAG_MEM;
235                 params->hdr.size = tag_size (tag_mem32);
236                 params->u.mem.start = this_board->linux_mem_start;
237                 params->u.mem.size = this_board->linux_mem_size;
238                 params = tag_next(params);
239
240                 /* kernel commandline */
241
242                 if (*p) {
243                         params->hdr.tag = ATAG_CMDLINE;
244                         params->hdr.size = (sizeof (struct tag_header) +
245                                                        strlen (p) + 1 + 4) >> 2;
246                         strcpy (params->u.cmdline.cmdline, p);
247                         params = tag_next (params);
248                 }
249
250                 /* needs to always be the last tag */
251                 params->hdr.tag = ATAG_NONE;
252                 params->hdr.size = 0;
253
254                 puts ("Starting --->\n\n");
255
256                 /*
257                 * ooh that's it, we're gonna try boot this image!
258                 * never mind the cache, Linux will take care of it
259                 */
260                 the_kernel(0, this_board->linux_machine_id,
261                                                 this_board->linux_tag_placement);
262
263                 /* we won't come back here no matter what */
264         }
265
266         /* none of the kernels worked out */
267
268         puts("No usable kernel image found, we've had it  :-(\n");
269         while (1)
270                 blue_on(1);
271 }