blob: 490b1381cd959636815ef76f527c9c6b8d679666 [file] [log] [blame]
/*
* 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;
}