#include #include #include #include #ifdef CFG_SUNXI_FDT_ADDR #ifdef CFG_RESERVE_FDT_SIZE #include #endif #endif #if 0 #define kernel_dbg(fmt, arg...) printf(fmt, ##arg) #else #define kernel_dbg(fmt, arg...) #endif #define ALIGN(x, a) __ALIGN_MASK((x), (typeof(x))(a)-1) #define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) #define SUNXI_FLASH_READ_FIRST_SIZE (32 * 1024) int exist_uboot_jmp_cardproduct(phys_addr_t uboot_base) { if (uboot_base) { uboot_head_t *header = (uboot_head_t *)uboot_base; /* fastboot scheme, uboot must jump to the card for mass production*/ printf("workmode 0x%x\n", header->boot_data.work_mode); if (header->boot_data.work_mode == WORK_MODE_CARD_PRODUCT) boot0_jmp(uboot_base); } return 0; } #ifdef CFG_SUNXI_SUPPORT_RAMDISK int android_image_get_ramdisk(const struct andr_img_hdr *hdr, ulong *rd_data, ulong *rd_len) { if (!hdr->ramdisk_size) return -1; *rd_data = (unsigned long)hdr; *rd_data += hdr->page_size; *rd_data += ALIGN(hdr->kernel_size, hdr->page_size); *rd_len = hdr->ramdisk_size; return 0; } #endif #ifdef CFG_LOAD_DTB_FROM_KERNEL extern __attribute__((section(".data"))) struct fdt_header *working_fdt; int android_image_get_dtb(const struct andr_img_hdr *hdr, ulong *dtb_data, ulong *dtb_len) { if (!hdr->dtb_size) return -1; *dtb_data = (unsigned long)hdr; *dtb_data += hdr->page_size; *dtb_data += ALIGN(hdr->kernel_size, hdr->page_size); *dtb_data += ALIGN(hdr->ramdisk_size, hdr->page_size); *dtb_data += ALIGN(hdr->second_size, hdr->page_size); *dtb_data += ALIGN(hdr->recovery_dtbo_size, hdr->page_size); *dtb_len = hdr->dtb_size; return 0; } #endif int sunxi_mem_info(unsigned long mem_addr, unsigned long mem_len, unsigned long other_mem_addr, unsigned long other_mem_len) { /* * | access target | * | case 1| * |case 2| * |case 3| * |case 4| * |case 5| * | case 6 | * only 4 & 5 is ok */ int ret = 0; if ((mem_addr >= other_mem_addr) && /*case 2 + case3*/ (mem_addr < other_mem_addr + other_mem_len)) { ret = -1; } else if ((mem_addr < other_mem_addr) && /*case 1*/ (mem_addr + mem_len >= other_mem_addr)) { ret = -1; } else if ((mem_addr < other_mem_addr) && (mem_addr + mem_len >= other_mem_addr + other_mem_len)) { /*case 6*/ ret = -1; } return ret; } int load_bimage(u32 from_flash, u32 to_ddr, int (*flash_read)(uint, uint, void *), u32 *kernel_addr) { int ret; u32 rbytes = 0; u32 rblock = 0; u32 start_block = from_flash; struct andr_img_hdr *fb_hdr; void *addr = (void *)(phys_addr_t)to_ddr; if (flash_read(start_block, (SUNXI_FLASH_READ_FIRST_SIZE / 512), addr)) { printf("Fail to load kernel head\n"); return -1; } fb_hdr = (struct andr_img_hdr *)addr; if (!memcmp(fb_hdr->magic, ANDR_BOOT_MAGIC, 8)) { kernel_dbg("kernel magic is ok\n"); kernel_dbg("kernel_size = 0x%x\n", fb_hdr->kernel_size); kernel_dbg("ramdisk_size = 0x%x\n", fb_hdr->ramdisk_size); rbytes = fb_hdr->kernel_size + fb_hdr->ramdisk_size + fb_hdr->second_size + 4 * 1024 + 511; } else { printf("kernel magic is error\n"); return -1; } pr_emerg("kernel_addr:%x\n", fb_hdr->kernel_addr); rblock = rbytes / 512 - SUNXI_FLASH_READ_FIRST_SIZE / 512; start_block += SUNXI_FLASH_READ_FIRST_SIZE / 512; addr = (void *)(phys_addr_t)((to_ddr) + SUNXI_FLASH_READ_FIRST_SIZE); kernel_dbg("rblock=%d, start=%d\n", rblock, start_block); ret = flash_read(start_block, rblock, addr); if (ret) { printf("load boot_image fail\n"); return -1; } kernel_dbg("boot:%x %x\n", to_ddr, rbytes); #ifdef CFG_KERNEL_CHECKSUM ret = verify_addsum_for_kernel((void *)to_ddr + KERNEL_CODE_OFFSET_IN_BIMAGE, fb_hdr->kernel_size, fb_hdr->checksum); #endif if (ret == 0) { #define GZIP_MAGIC 0x8b1f if (fb_hdr->kernel_addr != to_ddr + KERNEL_CODE_OFFSET_IN_BIMAGE) { if (sunxi_mem_info((ulong)fb_hdr, rbytes, fb_hdr->kernel_addr, fb_hdr->kernel_size) < 0) { printf("Warning:Please check memory !!!\n"); printf("boot.img:0x%lx-0x%lx\n", (ulong)fb_hdr, (ulong)((ulong)fb_hdr + rbytes)); printf("kernel_code:0x%lx-0x%lx\n", (ulong)fb_hdr->kernel_addr, (ulong)(fb_hdr->kernel_addr + fb_hdr->kernel_size)); } #ifdef CFG_SUNXI_GUNZIP if ((*(unsigned int *)(phys_addr_t)(to_ddr + KERNEL_CODE_OFFSET_IN_BIMAGE) & 0xffff) == GZIP_MAGIC) { int ret = 0; ret = gunzip((char *)(phys_addr_t)fb_hdr->kernel_addr, (fb_hdr->kernel_size * 3), (unsigned char *)(phys_addr_t)(to_ddr + KERNEL_CODE_OFFSET_IN_BIMAGE), (unsigned long *)&fb_hdr->kernel_size); if (ret) { printf("Error: gunzip returned %d\n", ret); return -1; } } else #endif { memcpy((void *)(phys_addr_t)fb_hdr->kernel_addr, (void *)(phys_addr_t)( to_ddr + KERNEL_CODE_OFFSET_IN_BIMAGE), fb_hdr->kernel_size); } printf("kernel:%x %x\n", fb_hdr->kernel_addr, fb_hdr->kernel_size); } #ifdef CFG_LOAD_DTB_FROM_KERNEL kernel_dbg("dtb_size = 0x%x\n", fb_hdr->dtb_size); kernel_dbg("dtb_addr = 0x%x\n", fb_hdr->dtb_addr); working_fdt = (struct fdt_header *)CFG_SUNXI_FDT_ADDR; if (fb_hdr->dtb_size) { ulong dtb_data = 0, dtb_len = 0; android_image_get_dtb(fb_hdr, &dtb_data, &dtb_len); ret = flash_read(from_flash + (dtb_data - (unsigned long)fb_hdr)/512, ALIGN(fb_hdr->dtb_size, 512)/512, (void *)CFG_SUNXI_FDT_ADDR); if (ret) { printf("load dtb fail\n"); return -1; } #ifdef CFG_SUNXI_FDT_ADDR #ifdef CFG_RESERVE_FDT_SIZE u32 fdt_ext_size = ALIGN(CFG_RESERVE_FDT_SIZE, 32); u32 new_fdt_totalsize = fdt_totalsize(working_fdt); if (new_fdt_totalsize > fdt_ext_size) { printf("new fdt(0x%08x) biger than now fdt(0x%08x)\n", new_fdt_totalsize, fdt_ext_size); } else { fdt_set_totalsize(working_fdt, fdt_ext_size); } #endif #endif } #endif #ifdef CFG_SUNXI_SUPPORT_RAMDISK ulong rd_data, rd_len; fb_hdr->ramdisk_addr = (ulong)CFG_RAMDISK_ADDR; if (fb_hdr->ramdisk_size) { android_image_get_ramdisk(fb_hdr, &rd_data, &rd_len); if (sunxi_mem_info((ulong)fb_hdr, rbytes, fb_hdr->ramdisk_addr, fb_hdr->ramdisk_size) < 0) { printf("Warning:Please check memory !!!\n"); printf("boot.img:0x%lx-0x%lx\n", (ulong)fb_hdr, (ulong)((ulong)fb_hdr + rbytes)); printf("ramdisk:0x%lx-0x%lx\n", (ulong)fb_hdr->ramdisk_addr, (ulong)(fb_hdr->ramdisk_addr + fb_hdr->ramdisk_size)); } pr_emerg("load ramdisk from %0x to %x\n", rd_data, fb_hdr->ramdisk_addr); memcpy((void *)(long)fb_hdr->ramdisk_addr, (const void *)rd_data, rd_len); /* ramdisk need to update dts, so load ramdisk after dtb*/ int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end); ret = fdt_initrd((void *)CFG_SUNXI_FDT_ADDR, (ulong)fb_hdr->ramdisk_addr, (ulong)(fb_hdr->ramdisk_addr + rd_len)); if (ret) { pr_emerg("update initrd fail\n"); return -1; } } #endif } *kernel_addr = fb_hdr->kernel_addr; return ret == 0 ? 0 : -1; } #ifdef CFG_KERNEL_UIMAGE int load_uimage(u32 from_flash, u32 to_ddr, u32 image_size_KB, int (*flash_read)(uint, uint, void *), u32 *kernel_addr) { int ret; u32 rbytes = (image_size_KB * 1024); u32 rblock = 0; u32 start_block = from_flash; void *addr = (void *)(phys_addr_t)(to_ddr); if (flash_read(start_block, (SUNXI_FLASH_READ_FIRST_SIZE / 512), addr)) { printf("Fail to load kernel head\n"); return -1; } rblock = rbytes / 512 - SUNXI_FLASH_READ_FIRST_SIZE / 512; start_block += SUNXI_FLASH_READ_FIRST_SIZE / 512; addr = (void *)(phys_addr_t)((to_ddr) + SUNXI_FLASH_READ_FIRST_SIZE); kernel_dbg("rblock=%d, start=%d\n", rblock, start_block); ret = flash_read(start_block, rblock, addr); *kernel_addr = to_ddr + KERNEL_CODE_OFFSET_IN_UIMAGE; return ret == 0 ? 0 : -1; } #endif