|  | /* | 
|  | * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 
|  | * | 
|  | * SPDX-License-Identifier:	GPL-2.0+ | 
|  | */ | 
|  |  | 
|  | #include <common.h> | 
|  | #include <image.h> | 
|  | #include <android_image.h> | 
|  | #include <malloc.h> | 
|  | #include <errno.h> | 
|  | static const unsigned char lzop_magic[] = { | 
|  | 0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a | 
|  | }; | 
|  |  | 
|  | static const unsigned char gzip_magic[] = { | 
|  | 0x1f, 0x8b | 
|  | }; | 
|  |  | 
|  | static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1]; | 
|  |  | 
|  | #ifdef CONFIG_OF_LIBFDT_OVERLAY | 
|  | static int save_dtbo_idx(const char *cmdline) | 
|  | { | 
|  | char *dtbo_chosen_idx_start = NULL; | 
|  | char *dtbo_chosen_idx_end = NULL; | 
|  | char *dtbo_idx = NULL; | 
|  |  | 
|  | if (!getenv("androidboot.dtbo_idx")) { | 
|  | if (!cmdline) | 
|  | return -1; | 
|  |  | 
|  | dtbo_chosen_idx_start = strstr(cmdline, "androidboot.dtbo_idx"); | 
|  | if (!dtbo_chosen_idx_start) { | 
|  | printf("No androidboot.dtbo_idx configured"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | dtbo_chosen_idx_end = strchr(dtbo_chosen_idx_start, ' '); | 
|  | if (dtbo_chosen_idx_end) { | 
|  | dtbo_idx = malloc(dtbo_chosen_idx_end - | 
|  | dtbo_chosen_idx_start + 1); | 
|  | if (!dtbo_idx) { | 
|  | printf("dtbo out of memory\n"); | 
|  | return -1; | 
|  | } | 
|  | memset(dtbo_idx, 0x00, | 
|  | dtbo_chosen_idx_end - dtbo_chosen_idx_start + 1); | 
|  | strncpy(dtbo_idx, dtbo_chosen_idx_start, | 
|  | dtbo_chosen_idx_end - dtbo_chosen_idx_start); | 
|  | } else | 
|  | strncpy(dtbo_idx, dtbo_chosen_idx_start, | 
|  | strlen(dtbo_chosen_idx_start)); | 
|  |  | 
|  | setenv("androidboot.dtbo_idx", | 
|  | dtbo_idx + strlen("androidboot.dtbo_idx=")); | 
|  | } | 
|  |  | 
|  | free(dtbo_idx); | 
|  | return 0; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | /** | 
|  | * android_image_get_kernel() - processes kernel part of Android boot images | 
|  | * @hdr:	Pointer to image header, which is at the start | 
|  | *			of the image. | 
|  | * @verify:	Checksum verification flag. Currently unimplemented. | 
|  | * @os_data:	Pointer to a ulong variable, will hold os data start | 
|  | *			address. | 
|  | * @os_len:	Pointer to a ulong variable, will hold os data length. | 
|  | * | 
|  | * This function returns the os image's start address and length. Also, | 
|  | * it appends the kernel command line to the bootargs env variable. | 
|  | * | 
|  | * Return: Zero, os start address and length on success, | 
|  | *		otherwise on failure. | 
|  | */ | 
|  | int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify, | 
|  | ulong *os_data, ulong *os_len) | 
|  | { | 
|  | /* | 
|  | * Not all Android tools use the id field for signing the image with | 
|  | * sha1 (or anything) so we don't check it. It is not obvious that the | 
|  | * string is null terminated so we take care of this. | 
|  | */ | 
|  | ulong end; | 
|  | strncpy(andr_tmp_str, hdr->name, ANDR_BOOT_NAME_SIZE); | 
|  | andr_tmp_str[ANDR_BOOT_NAME_SIZE] = '\0'; | 
|  | if (strlen(andr_tmp_str)) | 
|  | printf("Android's image name: %s\n", andr_tmp_str); | 
|  |  | 
|  | debug("Kernel load addr 0x%08x size %u KiB\n", | 
|  | hdr->kernel_addr, DIV_ROUND_UP(hdr->kernel_size, 1024)); | 
|  |  | 
|  | int len = 0; | 
|  | if (*hdr->cmdline) { | 
|  | printf("Kernel command line: %s\n", hdr->cmdline); | 
|  | len += strlen(hdr->cmdline); | 
|  | } | 
|  |  | 
|  | #ifdef CONFIG_OF_LIBFDT_OVERLAY | 
|  | save_dtbo_idx(hdr->cmdline); | 
|  | #endif | 
|  |  | 
|  | char *bootargs = getenv("bootargs"); | 
|  | if (bootargs) | 
|  | len += strlen(bootargs); | 
|  |  | 
|  | char *newbootargs = malloc(len + 2); | 
|  | if (!newbootargs) { | 
|  | puts("Error: malloc in android_image_get_kernel failed!\n"); | 
|  | return -ENOMEM; | 
|  | } | 
|  | *newbootargs = '\0'; | 
|  |  | 
|  | if (bootargs) { | 
|  | strcpy(newbootargs, bootargs); | 
|  | strcat(newbootargs, " "); | 
|  | } | 
|  | if (*hdr->cmdline) | 
|  | strcat(newbootargs, hdr->cmdline); | 
|  |  | 
|  | setenv("bootargs", newbootargs); | 
|  |  | 
|  | if (os_data) { | 
|  | *os_data = (ulong)hdr; | 
|  | *os_data += hdr->page_size; | 
|  | } | 
|  | if (os_len) | 
|  | *os_len = hdr->kernel_size; | 
|  |  | 
|  | #if defined(CONFIG_ANDROID_IMG) | 
|  | images.ft_len = (ulong)(hdr->second_size); | 
|  | end = (ulong)hdr; | 
|  | end += hdr->page_size; | 
|  | end += ALIGN(hdr->kernel_size, hdr->page_size); | 
|  | images.rd_start = end; | 
|  | end += ALIGN(hdr->ramdisk_size, hdr->page_size); | 
|  | images.ft_addr = (char *)end; | 
|  | #endif | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int android_image_check_header(const struct andr_img_hdr *hdr) | 
|  | { | 
|  | return memcmp(ANDR_BOOT_MAGIC, hdr->magic, ANDR_BOOT_MAGIC_SIZE); | 
|  | } | 
|  |  | 
|  | ulong android_image_get_end(const struct andr_img_hdr *hdr) | 
|  | { | 
|  | ulong end; | 
|  | /* | 
|  | * The header takes a full page, the remaining components are aligned | 
|  | * on page boundary | 
|  | */ | 
|  | end = (ulong)hdr; | 
|  | end += hdr->page_size; | 
|  | end += ALIGN(hdr->kernel_size, hdr->page_size); | 
|  | end += ALIGN(hdr->ramdisk_size, hdr->page_size); | 
|  | end += ALIGN(hdr->second_size, hdr->page_size); | 
|  |  | 
|  | return end; | 
|  | } | 
|  |  | 
|  | ulong android_image_get_kload(const struct andr_img_hdr *hdr) | 
|  | { | 
|  | return hdr->kernel_addr; | 
|  | } | 
|  |  | 
|  | int android_image_get_ramdisk(const struct andr_img_hdr *hdr, | 
|  | ulong *rd_data, ulong *rd_len) | 
|  | { | 
|  | if (!hdr->ramdisk_size) | 
|  | return -1; | 
|  |  | 
|  | debug("RAM disk load addr 0x%08x size %u KiB\n", | 
|  | hdr->ramdisk_addr, DIV_ROUND_UP(hdr->ramdisk_size, 1024)); | 
|  |  | 
|  | *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; | 
|  | } | 
|  |  | 
|  | ulong android_image_get_comp(const struct andr_img_hdr *os_hdr) | 
|  | { | 
|  | int i; | 
|  | unsigned char *src = (unsigned char *)os_hdr + os_hdr->page_size; | 
|  | /* read magic: 9 first bytes */ | 
|  | for (i = 0; i < ARRAY_SIZE(lzop_magic); i++) { | 
|  | if (*src++ != lzop_magic[i]) | 
|  | break; | 
|  | } | 
|  | if (i == ARRAY_SIZE(lzop_magic)) | 
|  | return IH_COMP_LZO; | 
|  |  | 
|  | src = (unsigned char *)os_hdr + os_hdr->page_size; | 
|  | for (i = 0; i < ARRAY_SIZE(gzip_magic); i++) { | 
|  | if (*src++ != gzip_magic[i]) | 
|  | break; | 
|  | } | 
|  | if (i == ARRAY_SIZE(gzip_magic)) | 
|  | return IH_COMP_GZIP; | 
|  |  | 
|  | return IH_COMP_NONE; | 
|  | } | 
|  | int android_image_need_move(ulong *img_addr, const struct andr_img_hdr *hdr) | 
|  | { | 
|  | ulong kernel_load_addr = android_image_get_kload(hdr); | 
|  | ulong img_start = *img_addr; | 
|  | ulong val = 0; | 
|  | if (kernel_load_addr > img_start) | 
|  | val = kernel_load_addr - img_start; | 
|  | else | 
|  | val = img_start - kernel_load_addr; | 
|  | if (android_image_get_comp(hdr) == IH_COMP_NONE) | 
|  | return 0; | 
|  | if (val < 32*1024*1024) { | 
|  | ulong total_size = android_image_get_end(hdr)-(ulong)hdr; | 
|  | void *reloc_addr = malloc(total_size); | 
|  | if (!reloc_addr) { | 
|  | puts("Error: malloc in  android_image_need_move failed!\n"); | 
|  | return -ENOMEM; | 
|  | } | 
|  | printf("reloc_addr =%lx\n", (ulong)reloc_addr); | 
|  | memset(reloc_addr, 0, total_size); | 
|  | memmove(reloc_addr, hdr, total_size); | 
|  | *img_addr = (ulong)reloc_addr; | 
|  | printf("copy done\n"); | 
|  | } | 
|  | return 0; | 
|  | } |