/* * (C) Copyright 2007-2011 * Allwinner Technology Co., Ltd. * Tom Cubie * * 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 #include #include //#include #include #include #include #include #include #include #include #include #include #include #include #include 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", "\n - boot application image stored in memory\n" "\t'addr' should be the address of boot image which is kernel+ramdisk.img\n" );