337 lines
8.8 KiB
C
337 lines
8.8 KiB
C
/*
|
|
* (C) Copyright 2007-2011
|
|
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
|
|
* Tom Cubie <tangliang@allwinnertech.com>
|
|
*
|
|
* Boot an image which is generated by android mkbootimg tool
|
|
*
|
|
* (C) Copyright 2000-2003
|
|
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
|
*
|
|
* See file CREDITS for list of people who contributed to this
|
|
* project.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
* MA 02111-1307 USA
|
|
*/
|
|
|
|
/*
|
|
* Misc boot support
|
|
*/
|
|
#include <common.h>
|
|
#include <command.h>
|
|
#include <net.h>
|
|
//#include <sunxi_board.h>
|
|
#include <android_image.h>
|
|
#include <fdtdec.h>
|
|
#include <asm/io.h>
|
|
#include <fdt_support.h>
|
|
#include <image.h>
|
|
#include <sunxi_board.h>
|
|
#include <power/sunxi/pmu.h>
|
|
#include <smc.h>
|
|
#include <cputask.h>
|
|
#include <sys_config_old.h>
|
|
#include <sys_partition.h>
|
|
#include <sunxi_mbr.h>
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
|
|
enum {
|
|
ARCH_ARM = 0,
|
|
ARCH_ARM64,
|
|
};
|
|
|
|
typedef void (*Kernel_Entry)(int zero,int machine_id,void *fdt_addr);
|
|
__weak void clean_timestamp_counter(void)
|
|
{
|
|
pr_msg("weak clean_timestamp_counter\n");
|
|
}
|
|
|
|
static void announce_and_cleanup(int fake)
|
|
{
|
|
pr_msg("prepare for kernel\n");
|
|
#ifndef CONFIG_ARCH_SUN3IW1P1
|
|
sunxi_board_prepare_kernel();
|
|
#endif
|
|
#ifdef CONFIG_BOOTSTAGE_FDT
|
|
bootstage_fdt_add_report();
|
|
#endif
|
|
#ifdef CONFIG_BOOTSTAGE_REPORT
|
|
bootstage_report();
|
|
#endif
|
|
|
|
#ifdef CONFIG_USB_DEVICE
|
|
udc_disconnect();
|
|
#endif
|
|
cleanup_before_linux();
|
|
pr_force("\nStarting kernel ...%s\n\n", fake ?
|
|
"(fake run for tracing)" : "");
|
|
}
|
|
|
|
|
|
uint get_arch_type(struct andr_img_hdr *hdr)
|
|
{
|
|
if ((hdr->kernel_addr & 0xfffff) == 0x80000)
|
|
return ARCH_ARM64;
|
|
else
|
|
return ARCH_ARM;
|
|
}
|
|
|
|
#ifdef CONFIG_SUNXI_SECURE_SYSTEM
|
|
static int android_image_get_signature(const struct andr_img_hdr *hdr,
|
|
ulong *sign_data, ulong *sign_len)
|
|
{
|
|
struct boot_img_hdr_ex *hdr_ex;
|
|
ulong addr=0;
|
|
|
|
hdr_ex = (struct boot_img_hdr_ex *)hdr;
|
|
if(strncmp((void *)(hdr_ex->cert_magic),AW_CERT_MAGIC,strlen(AW_CERT_MAGIC))){
|
|
printf("No cert image embeded, image %s\n",hdr_ex->cert_magic);
|
|
return 0;
|
|
}
|
|
|
|
addr = (unsigned long)hdr;
|
|
|
|
addr += hdr->page_size;
|
|
addr += ALIGN(hdr->kernel_size, hdr->page_size);
|
|
addr += ALIGN(hdr->ramdisk_size, hdr->page_size);
|
|
if(hdr->second_size)
|
|
addr += ALIGN(hdr->second_size, hdr->page_size);
|
|
|
|
*sign_data = (ulong)addr;
|
|
*sign_len = hdr_ex->cert_size;
|
|
memset(hdr_ex->cert_magic,0,ANDR_BOOT_MAGIC_SIZE+sizeof(unsigned));
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
int do_boota_linux (void *kernel_addr, void *dtb_base, uint arch_type)
|
|
{
|
|
int fake = 0;
|
|
Kernel_Entry kernel_entry = NULL;
|
|
|
|
|
|
kernel_entry = (Kernel_Entry)(ulong)(kernel_addr);
|
|
|
|
debug("## Transferring control to Linux (at address %lx)...\n",
|
|
(ulong) kernel_entry);
|
|
|
|
#ifdef CONFIG_SUNXI_FINS_FUNC
|
|
extern int __attribute__((__no_instrument_function__))
|
|
ff_move_reloc_data(void);
|
|
ff_move_reloc_data();
|
|
#endif
|
|
|
|
#ifdef CONFIG_SUNXI_MULITCORE_BOOT
|
|
sunxi_secondary_cpu_poweroff();
|
|
sunxi_fdt_reflush_all();
|
|
#endif
|
|
|
|
debug("moving platform.dtb from %lx to: %lx, size 0x%lx\n",
|
|
(ulong)dtb_base,
|
|
(ulong)(gd->fdt_blob),gd->fdt_size);
|
|
//fdt_blob save the addree of working_fdt
|
|
memcpy((void*)dtb_base, gd->fdt_blob,gd->fdt_size);
|
|
if(fdt_check_header(dtb_base) !=0 )
|
|
{
|
|
printf("fdt header check error befor boot\n");
|
|
return -1;
|
|
}
|
|
|
|
announce_and_cleanup(fake);
|
|
if (sunxi_probe_secure_monitor()) {
|
|
arm_svc_run_os((ulong)kernel_addr, (ulong)dtb_base, arch_type);
|
|
} else {
|
|
clean_timestamp_counter();
|
|
kernel_entry(0,0xffffffff,dtb_base);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void * memcpy2(void * dest,const void * src,__kernel_size_t n)
|
|
{
|
|
if (src == dest)
|
|
return dest;
|
|
if (src < dest) {
|
|
if (src + n > dest) {
|
|
memcpy((void*) (dest + (dest - src)), dest, src + n - dest);
|
|
n = dest - src;
|
|
}
|
|
memcpy(dest, src, n);
|
|
} else {
|
|
memcpy(dest, src, n);
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
void update_bootargs(void)
|
|
{
|
|
char *str;
|
|
char cmdline[1024] = {0};
|
|
char tmpbuf[128] = {0};
|
|
char *verifiedbootstate_info = getenv("verifiedbootstate");
|
|
str = getenv("bootargs");
|
|
|
|
strcpy(cmdline,str);
|
|
//charge type
|
|
if(gd->chargemode)
|
|
{
|
|
if((0==strcmp(getenv("bootcmd"),"run setargs_mmc boot_normal"))||(0==strcmp(getenv("bootcmd"),"run setargs_nand boot_normal")))
|
|
{
|
|
printf("only in boot normal mode, pass charger para to kernel\n");
|
|
strcat(cmdline," androidboot.mode=charger");
|
|
}
|
|
}
|
|
#ifdef CONFIG_SUNXI_SERIAL
|
|
//serial info
|
|
str = getenv("snum");
|
|
sprintf(tmpbuf," androidboot.serialno=%s",str);
|
|
strcat(cmdline,tmpbuf);
|
|
#endif
|
|
//harware info
|
|
sprintf(tmpbuf," androidboot.hardware=%s",board_hardware_info());
|
|
strcat(cmdline,tmpbuf);
|
|
/*boot type*/
|
|
sprintf(tmpbuf," boot_type=%d",get_boot_storage_type_ext());
|
|
strcat(cmdline,tmpbuf);
|
|
/* gpt support */
|
|
if(PART_TYPE_GPT == sunxi_partition_get_type())
|
|
{
|
|
sprintf(tmpbuf," gpt=1");
|
|
strcat(cmdline,tmpbuf);
|
|
}
|
|
|
|
|
|
if (gd->securemode) {
|
|
/* verified boot state info */
|
|
sprintf(tmpbuf, " androidboot.verifiedbootstate=%s",
|
|
verifiedbootstate_info);
|
|
strcat(cmdline, tmpbuf);
|
|
}
|
|
setenv("bootargs", cmdline);
|
|
printf("android.hardware = %s\n", board_hardware_info());
|
|
}
|
|
|
|
extern int switch_boot_partition(void);
|
|
extern int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
|
|
|
|
int do_boota (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
|
|
ulong os_load_addr;
|
|
ulong os_data = 0,os_len = 0;
|
|
ulong rd_data,rd_len;
|
|
uint arch_type = 0;
|
|
void *kernel_addr = NULL;
|
|
struct andr_img_hdr *fb_hdr = NULL;
|
|
void *dtb_base = (void*)CONFIG_SUNXI_FDT_ADDR;
|
|
|
|
if (argc < 2)
|
|
return cmd_usage(cmdtp);
|
|
|
|
os_load_addr = simple_strtoul(argv[1], NULL, 16);
|
|
fb_hdr = (struct andr_img_hdr *)os_load_addr;
|
|
|
|
if(android_image_check_header(fb_hdr))
|
|
{
|
|
puts("boota: bad boot image magic, maybe not a boot.img?\n");
|
|
switch_boot_partition();
|
|
do_reset(NULL, 0, 0,NULL);
|
|
return -1;
|
|
}
|
|
android_image_get_kernel(fb_hdr,0,&os_data,&os_len);
|
|
android_image_get_ramdisk(fb_hdr,&rd_data,&rd_len);
|
|
arch_type = get_arch_type(fb_hdr);
|
|
kernel_addr = (void *)fb_hdr->kernel_addr;
|
|
#ifdef CONFIG_SUNXI_SECURE_SYSTEM
|
|
if(gd->securemode)
|
|
{
|
|
if (gd->lockflag == SUNXI_UNLOCKED) {
|
|
setenv("verifiedbootstate", "orange");
|
|
printf("start to display warnings.bmp\n");
|
|
sunxi_bmp_display("warnings.bmp");
|
|
} else {
|
|
ulong total_len = ALIGN(fb_hdr->ramdisk_size, fb_hdr->page_size) + \
|
|
ALIGN(fb_hdr->kernel_size, fb_hdr->page_size) + \
|
|
fb_hdr->page_size;
|
|
|
|
printf("total_len=%d\n", (unsigned int)total_len);
|
|
ulong sign_data , sign_len;
|
|
int ret;
|
|
|
|
if (!strcmp(getenv("verifiedbootstate"), "yellow")) {
|
|
printf("start to display warnings.bmp\n");
|
|
sunxi_bmp_display("warnings.bmp");
|
|
} else {
|
|
setenv("verifiedbootstate", "green");
|
|
}
|
|
if (android_image_get_signature(fb_hdr, &sign_data, &sign_len))
|
|
ret = sunxi_verify_embed_signature((void *)os_load_addr,
|
|
(unsigned int)total_len,
|
|
argv[2], (void *)sign_data, sign_len);
|
|
else
|
|
ret = sunxi_verify_signature((void *)os_load_addr,
|
|
(unsigned int)total_len, argv[2]);
|
|
|
|
if (ret) {
|
|
printf("boota: verify the %s failed\n", argv[2]);
|
|
setenv("verifiedbootstate", "red");
|
|
|
|
printf("start to display warnings.bmp\n");
|
|
sunxi_bmp_display("warnings.bmp");
|
|
__msdelay(30000);
|
|
sunxi_board_shutdown();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
memcpy2((void*) (long)fb_hdr->kernel_addr, (const void *)os_data, os_len);
|
|
memcpy2((void*) (long)fb_hdr->ramdisk_addr, (const void *)rd_data, rd_len);
|
|
#ifdef SYS_CONFIG_MEMBASE
|
|
debug("moving sysconfig.bin from %lx to: %lx, size 0x%lx\n",
|
|
get_script_reloc_buf(SOC_SCRIPT),
|
|
(ulong)(SYS_CONFIG_MEMBASE),
|
|
get_script_reloc_size(SOC_SCRIPT));
|
|
|
|
memcpy((void*)SYS_CONFIG_MEMBASE, (void*)get_script_reloc_buf(SOC_SCRIPT),get_script_reloc_size(SOC_SCRIPT));
|
|
#endif
|
|
update_bootargs();
|
|
|
|
//update fdt bootargs from env config
|
|
fdt_chosen(working_fdt);
|
|
fdt_initrd(working_fdt,(ulong)fb_hdr->ramdisk_addr, (ulong)(fb_hdr->ramdisk_addr+rd_len));
|
|
|
|
pr_msg("ready to boot\n");
|
|
#if 1
|
|
do_boota_linux(kernel_addr, dtb_base, arch_type);
|
|
puts("Boot linux failed, control return to monitor\n");
|
|
#else
|
|
puts("Boot linux test ok, control return to monitor\n");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
U_BOOT_CMD(
|
|
boota, 3, 1, do_boota,
|
|
"boota - boot android bootimg from memory\n",
|
|
"<addr>\n - boot application image stored in memory\n"
|
|
"\t'addr' should be the address of boot image which is kernel+ramdisk.img\n"
|
|
);
|
|
|