| /* |
| * Copyright (C) 2008 The Android Open Source Project |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
| * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
| * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
| * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| */ |
| |
| #include <boot/boot.h> |
| #include <boot/uart.h> |
| #include <boot/tags.h> |
| #include <boot/flash.h> |
| #include <boot/board.h> |
| |
| #include <bootimg.h> |
| |
| #define FLASH_PAGE_SIZE 2048 |
| #define FLASH_PAGE_BITS 11 |
| |
| #define ADDR_TAGS 0x10000100 |
| |
| static void create_atags(unsigned taddr, const char *cmdline, |
| unsigned raddr, unsigned rsize) |
| { |
| unsigned n = 0; |
| unsigned pcount; |
| unsigned *tags = (unsigned *) taddr; |
| |
| // ATAG_CORE |
| tags[n++] = 2; |
| tags[n++] = 0x54410001; |
| |
| if(rsize) { |
| // ATAG_INITRD2 |
| tags[n++] = 4; |
| tags[n++] = 0x54420005; |
| tags[n++] = raddr; |
| tags[n++] = rsize; |
| } |
| |
| if((pcount = flash_get_ptn_count())){ |
| ptentry *ptn; |
| unsigned pn; |
| unsigned m = n + 2; |
| |
| for(pn = 0; pn < pcount; pn++) { |
| ptn = flash_get_ptn(pn); |
| memcpy(tags + m, ptn, sizeof(ptentry)); |
| m += (sizeof(ptentry) / sizeof(unsigned)); |
| } |
| |
| tags[n + 0] = m - n; |
| tags[n + 1] = 0x4d534d70; |
| n = m; |
| } |
| if(cmdline && cmdline[0]) { |
| const char *src; |
| char *dst; |
| unsigned len = 0; |
| |
| dst = (char*) (tags + n + 2); |
| src = cmdline; |
| while((*dst++ = *src++)) len++; |
| |
| len++; |
| len = (len + 3) & (~3); |
| |
| // ATAG_CMDLINE |
| tags[n++] = 2 + (len / 4); |
| tags[n++] = 0x54410009; |
| |
| n += (len / 4); |
| } |
| |
| // ATAG_NONE |
| tags[n++] = 0; |
| tags[n++] = 0; |
| } |
| |
| static void boot_linux(unsigned kaddr) |
| { |
| void (*entry)(unsigned,unsigned,unsigned) = (void*) kaddr; |
| |
| entry(0, board_machtype(), ADDR_TAGS); |
| } |
| |
| unsigned char raw_header[2048]; |
| |
| int boot_linux_from_flash(void) |
| { |
| boot_img_hdr *hdr = (void*) raw_header; |
| unsigned n; |
| ptentry *p; |
| unsigned offset = 0; |
| const char *cmdline; |
| |
| if((p = flash_find_ptn("boot")) == 0) { |
| cprintf("NO BOOT PARTITION\n"); |
| return -1; |
| } |
| |
| if(flash_read(p, offset, raw_header, 2048)) { |
| cprintf("CANNOT READ BOOT IMAGE HEADER\n"); |
| return -1; |
| } |
| offset += 2048; |
| |
| if(memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) { |
| cprintf("INVALID BOOT IMAGE HEADER\n"); |
| return -1; |
| } |
| |
| n = (hdr->kernel_size + (FLASH_PAGE_SIZE - 1)) & (~(FLASH_PAGE_SIZE - 1)); |
| if(flash_read(p, offset, (void*) hdr->kernel_addr, n)) { |
| cprintf("CANNOT READ KERNEL IMAGE\n"); |
| return -1; |
| } |
| offset += n; |
| |
| n = (hdr->ramdisk_size + (FLASH_PAGE_SIZE - 1)) & (~(FLASH_PAGE_SIZE - 1)); |
| if(flash_read(p, offset, (void*) hdr->ramdisk_addr, n)) { |
| cprintf("CANNOT READ RAMDISK IMAGE\n"); |
| return -1; |
| } |
| offset += n; |
| |
| dprintf("\nkernel @ %x (%d bytes)\n", hdr->kernel_addr, hdr->kernel_size); |
| dprintf("ramdisk @ %x (%d bytes)\n\n\n", hdr->ramdisk_addr, hdr->ramdisk_size); |
| |
| if(hdr->cmdline[0]) { |
| cmdline = (char*) hdr->cmdline; |
| } else { |
| cmdline = board_cmdline(); |
| if(cmdline == 0) { |
| cmdline = "mem=50M console=null"; |
| } |
| } |
| cprintf("cmdline = '%s'\n", cmdline); |
| |
| cprintf("\nBooting Linux\n"); |
| |
| create_atags(ADDR_TAGS, cmdline, |
| hdr->ramdisk_addr, hdr->ramdisk_size); |
| |
| boot_linux(hdr->kernel_addr); |
| return 0; |
| } |
| |
| void usbloader_init(void); |
| void uart_putc(unsigned); |
| const char *get_fastboot_version(void); |
| |
| extern unsigned linux_type; |
| extern unsigned linux_tags; |
| |
| static unsigned revision = 0; |
| |
| char serialno[32]; |
| |
| void dump_smem_info(void); |
| |
| static void tag_dump(unsigned tag, void *data, unsigned sz, void *cookie) |
| { |
| dprintf("tag type=%x data=%x size=%x\n", tag, (unsigned) data, sz); |
| } |
| |
| static struct tag_handler tag_dump_handler = { |
| .func = tag_dump, |
| .type = 0, |
| }; |
| |
| void xdcc_putc(unsigned x) |
| { |
| while (dcc_putc(x) < 0) ; |
| } |
| |
| #define SERIALNO_STR "androidboot.serialno=" |
| #define SERIALNO_LEN strlen(SERIALNO_STR) |
| |
| static int boot_from_flash = 1; |
| |
| void key_changed(unsigned int key, unsigned int down) |
| { |
| if(!down) return; |
| if(key == BOOT_KEY_STOP_BOOT) boot_from_flash = 0; |
| } |
| |
| static int tags_okay(unsigned taddr) |
| { |
| unsigned *tags = (unsigned*) taddr; |
| |
| if(taddr != ADDR_TAGS) return 0; |
| if(tags[0] != 2) return 0; |
| if(tags[1] != 0x54410001) return 0; |
| |
| return 1; |
| } |
| |
| int _main(unsigned zero, unsigned type, unsigned tags) |
| { |
| const char *cmdline = 0; |
| int n; |
| |
| arm11_clock_init(); |
| |
| /* must do this before board_init() so that we |
| ** use the partition table in the tags if it |
| ** already exists |
| */ |
| if((zero == 0) && (type != 0) && tags_okay(tags)) { |
| linux_type = type; |
| linux_tags = tags; |
| |
| cmdline = tags_get_cmdline((void*) linux_tags); |
| |
| tags_import_partitions((void*) linux_tags); |
| revision = tags_get_revision((void*) linux_tags); |
| if(revision == 1) { |
| console_set_colors(0x03E0, 0xFFFF); |
| } |
| if(revision == 2) { |
| console_set_colors(0x49B2, 0xFFFF); |
| } |
| |
| /* we're running as a second-stage, so wait for interrupt */ |
| boot_from_flash = 0; |
| } else { |
| linux_type = board_machtype(); |
| linux_tags = 0; |
| } |
| |
| board_init(); |
| keypad_init(); |
| |
| console_init(); |
| dprintf_set_putc(uart_putc); |
| |
| if(linux_tags == 0) { |
| /* generate atags containing partitions |
| * from the bootloader, etc |
| */ |
| linux_tags = ADDR_TAGS; |
| create_atags(linux_tags, 0, 0, 0); |
| } |
| |
| if (cmdline) { |
| char *sn = strstr(cmdline, SERIALNO_STR); |
| if (sn) { |
| char *s = serialno; |
| sn += SERIALNO_LEN; |
| while (*sn && (*sn != ' ') && ((s - serialno) < 31)) { |
| *s++ = *sn++; |
| } |
| *s++ = 0; |
| } |
| } |
| |
| cprintf("\n\nUSB FastBoot: V%s\n", get_fastboot_version()); |
| cprintf("Machine ID: %d v%d\n", linux_type, revision); |
| cprintf("Build Date: "__DATE__", "__TIME__"\n\n"); |
| |
| cprintf("Serial Number: %s\n\n", serialno[0] ? serialno : "UNKNOWN"); |
| |
| flash_dump_ptn(); |
| |
| flash_init(); |
| |
| /* scan the keyboard a bit */ |
| for(n = 0; n < 50; n++) { |
| boot_poll(); |
| } |
| |
| if (boot_from_flash) { |
| cprintf("\n ** BOOTING LINUX FROM FLASH **\n"); |
| boot_linux_from_flash(); |
| } |
| |
| usbloader_init(); |
| |
| for(;;) { |
| usb_poll(); |
| } |
| return 0; |
| } |