aboutsummaryrefslogtreecommitdiff
path: root/usbloader/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'usbloader/main.c')
-rw-r--r--usbloader/main.c304
1 files changed, 304 insertions, 0 deletions
diff --git a/usbloader/main.c b/usbloader/main.c
new file mode 100644
index 0000000..490b138
--- /dev/null
+++ b/usbloader/main.c
@@ -0,0 +1,304 @@
+/*
+ * 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;
+}