Root/qiboot/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 <ext2.h>
32
33
34typedef void (*the_kernel_fn)(int zero, int arch, uint params);
35
36unsigned long partition_offset_blocks = 0;
37unsigned long partition_length_blocks = 0;
38
39struct kernel_source const * this_kernel = 0;
40
41static const int INITRD_OFFSET = (8 * 1024 * 1024);
42
43
44int raise(int n)
45{
46    return 0;
47}
48
49static void indicate(enum ui_indication ui_indication)
50{
51    if (this_board->set_ui_indication)
52        (this_board->set_ui_indication)(ui_indication);
53}
54
55static int read_file(const char * filepath, u8 * destination, int size)
56{
57    int len = size;
58    int ret;
59
60    switch (this_kernel->filesystem) {
61    case FS_EXT2:
62        if (!ext2fs_mount()) {
63            puts("Unable to mount ext2 filesystem\n");
64            indicate(UI_IND_MOUNT_FAIL);
65            return -2; /* death */
66        }
67        puts(" EXT2 open: ");
68        puts(filepath);
69        len = ext2fs_open(filepath);
70        if (len < 0) {
71            puts(" Open failed\n");
72            return -1;
73        }
74        puts(" OK\n");
75        ret = ext2fs_read((char *)destination, size);
76        if (ret < 0) {
77            puts(" Read failed\n");
78            return -1;
79        }
80        break;
81
82    case FS_FAT:
83        /* FIXME */
84    case FS_RAW:
85        /* any filename-related request in raw filesystem will fail */
86        if (filepath)
87            return -1;
88        puts(" RAW open: +");
89        printdec(partition_offset_blocks);
90        puts(" 512-byte blocks\n");
91        if (this_kernel->block_read(destination,
92                      partition_offset_blocks, size >> 9) < 0) {
93            puts("Bad kernel header\n");
94            return -1;
95        }
96        break;
97    }
98
99    return len;
100}
101
102static int do_block_init(void)
103{
104    static void * last_block_init = NULL;
105    static int last_block_init_result = 0;
106    int fresh = 0;
107
108    /* if this device needs initializing, try to init it */
109    if (!this_kernel->block_init)
110        return 1; /* happy */
111
112    /*
113     * cache result to limit attempts for same
114     * block device to one time
115     */
116    if (this_kernel->block_init != last_block_init) {
117        last_block_init = this_kernel->block_init;
118        last_block_init_result = (this_kernel->block_init)();
119        fresh = 1;
120    }
121
122    if (last_block_init_result) {
123        puts("block device init failed\n");
124        if (fresh)
125            indicate(UI_IND_MOUNT_FAIL);
126
127        return 0; /* failed */
128    }
129    last_block_init = this_kernel->block_init;
130
131    return 1; /* happy */
132}
133
134static int do_partitions(void *kernel_dram)
135{
136    unsigned char *p = kernel_dram;
137
138    /* if there's a partition table implied, parse it, otherwise
139     * just use a fixed offset
140     */
141    if (!this_kernel->partition_index) {
142        partition_offset_blocks =
143              this_kernel->offset_blocks512_if_no_partition;
144        return 1;
145    }
146
147    if ((int)this_kernel->block_read(kernel_dram, 0, 4) < 0) {
148        puts("Bad partition read\n");
149        indicate(UI_IND_MOUNT_FAIL);
150        return 0;
151    }
152
153    if ((p[0x1fe] != 0x55) || (p[0x1ff] != 0xaa)) {
154        puts("partition signature missing\n");
155        indicate(UI_IND_MOUNT_FAIL);
156        return 0;
157    }
158
159    p += 0x1be + 8 + (0x10 * (this_kernel->partition_index - 1));
160
161    partition_offset_blocks = (((u32)p[3]) << 24) |
162                  (((u32)p[2]) << 16) |
163                  (((u32)p[1]) << 8) |
164                  p[0];
165    partition_length_blocks = (((u32)p[7]) << 24) |
166                  (((u32)p[6]) << 16) |
167                  (((u32)p[5]) << 8) |
168                  p[4];
169
170    puts(" Partition: ");
171    printdec(this_kernel->partition_index);
172    puts(" start +");
173    printdec(partition_offset_blocks);
174    puts(" 512-byte blocks, size ");
175    printdec(partition_length_blocks / 2048);
176    puts(" MiB\n");
177
178    return 1;
179}
180
181static void do_params(unsigned initramfs_len,
182    const char *commandline_rootfs_append)
183{
184    const struct board_variant * board_variant =
185                          (this_board->get_board_variant)();
186    const char *p;
187    char * cmdline;
188    struct tag *params = (struct tag *)this_board->linux_tag_placement;
189
190    /* eat leading white space */
191    for (p = this_board->commandline_board; *p == ' '; p++);
192
193    /* first tag */
194    params->hdr.tag = ATAG_CORE;
195    params->hdr.size = tag_size(tag_core);
196    params->u.core.flags = 0;
197    params->u.core.pagesize = 0;
198    params->u.core.rootdev = 0;
199    params = tag_next(params);
200
201    /* revision tag */
202    params->hdr.tag = ATAG_REVISION;
203    params->hdr.size = tag_size(tag_revision);
204    params->u.revision.rev = board_variant->machine_revision;
205    params = tag_next(params);
206
207    /* memory tags */
208    params->hdr.tag = ATAG_MEM;
209    params->hdr.size = tag_size(tag_mem32);
210    params->u.mem.start = this_board->linux_mem_start;
211    params->u.mem.size = this_board->linux_mem_size;
212    params = tag_next(params);
213
214    if (this_kernel->initramfs_filepath) {
215        /* INITRD2 tag */
216        params->hdr.tag = ATAG_INITRD2;
217        params->hdr.size = tag_size(tag_initrd);
218        params->u.initrd.start = this_board->linux_mem_start +
219                                  INITRD_OFFSET;
220        params->u.initrd.size = initramfs_len;
221        params = tag_next(params);
222    }
223
224    /* kernel commandline */
225
226    cmdline = params->u.cmdline.cmdline;
227
228    /* start with the fixed device part of the commandline */
229
230    cmdline += strlen(strcpy(cmdline, p));
231
232    /* if the board itself needs a computed commandline, add it now */
233
234    if (this_board->append_device_specific_cmdline)
235        cmdline = (this_board->append_device_specific_cmdline)(cmdline);
236
237    /* If he is giving an append commandline for this rootfs, apply that */
238
239    if (this_kernel->commandline_append)
240        cmdline += strlen(strcpy(cmdline,
241                      this_kernel->commandline_append));
242        if (commandline_rootfs_append[0])
243            cmdline += strlen(strcpy(cmdline,
244                      commandline_rootfs_append));
245
246    /* deal with any trailing newlines that hitched a ride */
247
248    while (*(cmdline - 1) == '\n')
249        cmdline--;
250
251    *cmdline = '\0';
252
253    /*
254     * if he's still holding down the UI_ACTION_SKIPKERNEL key
255     * now we finished loading the kernel, take it to mean he wants
256     * to have the debugging options added to the commandline
257     */
258
259    if (this_board->commandline_board_debug && this_board->get_ui_debug)
260        if ((this_board->get_ui_debug)())
261            cmdline += strlen(strcpy(cmdline, this_board->
262                          commandline_board_debug));
263
264    params->hdr.tag = ATAG_CMDLINE;
265    params->hdr.size = (sizeof(struct tag_header) +
266        strlen(params->u.cmdline.cmdline) + 1 + 4) >> 2;
267
268    puts(" Cmdline: ");
269    puts(params->u.cmdline.cmdline);
270    puts("\n");
271
272    params = tag_next(params);
273
274    /* needs to always be the last tag */
275    params->hdr.tag = ATAG_NONE;
276    params->hdr.size = 0;
277}
278
279static int do_crc(const image_header_t *hdr, const void *kernel_dram)
280{
281    unsigned long crc;
282
283    /*
284     * It's good for now to know that our kernel is intact from
285     * the storage before we jump into it and maybe crash silently
286     * even though it costs us some time
287     */
288    crc = crc32(0, kernel_dram + sizeof(image_header_t),
289                           __be32_to_cpu(hdr->ih_size));
290    if (crc == __be32_to_cpu(hdr->ih_dcrc))
291        return 1;
292
293    puts("\nKernel CRC ERROR: read 0x");
294    print32(crc);
295    puts(" vs hdr CRC 0x");
296    print32(__be32_to_cpu(hdr->ih_dcrc));
297    puts("\n");
298
299    return 0;
300}
301
302static the_kernel_fn load_uimage(void *kernel_dram)
303{
304    image_header_t *hdr;
305    u32 kernel_size;
306
307    hdr = (image_header_t *)kernel_dram;
308
309    if (__be32_to_cpu(hdr->ih_magic) != IH_MAGIC) {
310        puts("bad magic ");
311        print32(hdr->ih_magic);
312        puts("\n");
313        return NULL;
314    }
315
316    puts(" Found: \"");
317    puts((const char *)hdr->ih_name);
318    puts("\"\n Size: ");
319    printdec(__be32_to_cpu(hdr->ih_size) >> 10);
320    puts(" KiB\n");
321
322    kernel_size = ((__be32_to_cpu(hdr->ih_size) +
323              sizeof(image_header_t) + 2048) & ~(2048 - 1));
324
325    if (read_file(this_kernel->filepath, kernel_dram, kernel_size) < 0) {
326        indicate(UI_IND_KERNEL_PULL_FAIL);
327        return NULL;
328    }
329
330    indicate(UI_IND_KERNEL_PULL_OK);
331
332    if (!do_crc(hdr, kernel_dram))
333        return NULL;
334
335    return (the_kernel_fn) (((char *)hdr) + sizeof(image_header_t));
336}
337
338static the_kernel_fn load_zimage(void *kernel_dram)
339{
340    u32 magic = *(u32 *) (kernel_dram + 0x24);
341    u32 size = *(u32 *) (kernel_dram + 0x2c);
342    int got;
343
344    if (magic != 0x016f2818) {
345        puts("bad magic ");
346        print32(magic);
347        puts("\n");
348        return NULL;
349    }
350
351    puts(" Size: ");
352    printdec(size >> 10);
353    puts(" KiB\n");
354
355    got = read_file(this_kernel->filepath, kernel_dram, size);
356    if (got < 0) {
357        indicate(UI_IND_KERNEL_PULL_FAIL);
358        return NULL;
359    }
360
361    if (got != size) {
362        puts("short kernel\n");
363        return NULL;
364    }
365
366    indicate(UI_IND_KERNEL_PULL_OK);
367
368    return (the_kernel_fn) kernel_dram;
369}
370
371static void try_this_kernel(void)
372{
373    the_kernel_fn the_kernel;
374    unsigned int initramfs_len = 0;
375    static char commandline_rootfs_append[512] = "";
376    int ret;
377    void * kernel_dram = (void *)this_board->linux_mem_start + 0x8000;
378
379    partition_offset_blocks = 0;
380    partition_length_blocks = 0;
381
382    puts("\nTrying kernel: ");
383    puts(this_kernel->name);
384    puts("\n");
385
386    indicate(UI_IND_MOUNT_PART);
387
388    if (!do_block_init())
389        return;
390
391    if (!do_partitions(kernel_dram))
392        return;
393
394    /* does he want us to skip this? */
395
396    ret = read_file(this_board->noboot, kernel_dram, 512);
397    if (ret != -1) {
398        /* -2 (mount fail) should make us give up too */
399        if (ret >= 0) {
400            puts(" (Skipping on finding ");
401            puts(this_board->noboot);
402            puts(")\n");
403            indicate(UI_IND_SKIPPING);
404        }
405        return;
406    }
407
408    /* is there a commandline append file? */
409
410    commandline_rootfs_append[0] = '\0';
411    read_file(this_board->append, (u8 *)commandline_rootfs_append, 512);
412
413    indicate(UI_IND_KERNEL_PULL);
414
415    /* pull the kernel image */
416
417    if (read_file(this_kernel->filepath, kernel_dram, 4096) < 0)
418        return;
419
420    the_kernel = load_uimage(kernel_dram);
421    if (!the_kernel)
422        the_kernel = load_zimage(kernel_dram);
423    if (!the_kernel)
424        return;
425
426    /* initramfs if needed */
427
428    if (this_kernel->initramfs_filepath) {
429        indicate(UI_IND_INITRAMFS_PULL);
430        initramfs_len = read_file(this_kernel->initramfs_filepath,
431              (u8 *)this_board->linux_mem_start + INITRD_OFFSET,
432                              16 * 1024 * 1024);
433        if (initramfs_len < 0) {
434            puts("initramfs load failed\n");
435            indicate(UI_IND_INITRAMFS_PULL_FAIL);
436            return;
437        }
438        indicate(UI_IND_INITRAMFS_PULL_OK);
439    }
440
441    do_params(initramfs_len, commandline_rootfs_append);
442
443    /* give board implementation a chance to shut down
444     * anything it may have going on, leave GPIO set for Linux
445     */
446    if (this_board->close)
447        (this_board->close)();
448
449    puts("Starting --->\n\n");
450    indicate(UI_IND_KERNEL_START);
451
452    /*
453    * ooh that's it, we're gonna try boot this image!
454    * never mind the cache, Linux will take care of it
455    */
456    the_kernel(0, this_board->linux_machine_id,
457                    this_board->linux_tag_placement);
458
459    /* we won't come back here no matter what */
460}
461
462void bootloader_second_phase(void)
463{
464    /* give device a chance to print device-specific things */
465
466    if (this_board->post_serial_init)
467        (this_board->post_serial_init)();
468
469    /* we try the possible kernels for this board in order */
470
471    for (this_kernel = this_board->kernel_source; this_kernel->name;
472        this_kernel++)
473        try_this_kernel();
474
475    /* none of the kernels worked out */
476
477    puts("\nNo usable kernel image found\n");
478
479    /*
480     * sit there doing a memory test in this case.
481     *
482     * This phase 2 code will get destroyed but it's OK, we won't be
483     * coming back and the whole memory test and dependency functions are
484     * in phase 1 / steppingstone, so we can test entire memory range.
485     *
486     * It means we just boot with SD Card with kernel(s) renamed or removed
487     * to provoke memory test.
488     */
489
490    indicate(UI_IND_MEM_TEST);
491
492    memory_test((void *)this_board->linux_mem_start,
493                            this_board->linux_mem_size);
494
495}
496

Archive Download this file



interactive