19ace3fc8SSebastian Siewior /* 29ace3fc8SSebastian Siewior * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de> 39ace3fc8SSebastian Siewior * 49ace3fc8SSebastian Siewior * SPDX-License-Identifier: GPL-2.0+ 59ace3fc8SSebastian Siewior */ 69ace3fc8SSebastian Siewior 79ace3fc8SSebastian Siewior #include <common.h> 89ace3fc8SSebastian Siewior #include <image.h> 99ace3fc8SSebastian Siewior #include <android_image.h> 1086f4695bSAhmad Draidi #include <malloc.h> 1186f4695bSAhmad Draidi #include <errno.h> 129ace3fc8SSebastian Siewior 1387f02d5aSMaxime Ripard #define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR 0x10008000 1487f02d5aSMaxime Ripard 159ace3fc8SSebastian Siewior static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1]; 169ace3fc8SSebastian Siewior 1787f02d5aSMaxime Ripard static ulong android_image_get_kernel_addr(const struct andr_img_hdr *hdr) 1887f02d5aSMaxime Ripard { 1987f02d5aSMaxime Ripard /* 2087f02d5aSMaxime Ripard * All the Android tools that generate a boot.img use this 2187f02d5aSMaxime Ripard * address as the default. 2287f02d5aSMaxime Ripard * 2387f02d5aSMaxime Ripard * Even though it doesn't really make a lot of sense, and it 2487f02d5aSMaxime Ripard * might be valid on some platforms, we treat that adress as 2587f02d5aSMaxime Ripard * the default value for this field, and try to execute the 2687f02d5aSMaxime Ripard * kernel in place in such a case. 2787f02d5aSMaxime Ripard * 2887f02d5aSMaxime Ripard * Otherwise, we will return the actual value set by the user. 2987f02d5aSMaxime Ripard */ 3087f02d5aSMaxime Ripard if (hdr->kernel_addr == ANDROID_IMAGE_DEFAULT_KERNEL_ADDR) 3187f02d5aSMaxime Ripard return (ulong)hdr + hdr->page_size; 3287f02d5aSMaxime Ripard 3387f02d5aSMaxime Ripard return hdr->kernel_addr; 3487f02d5aSMaxime Ripard } 3587f02d5aSMaxime Ripard 3686f4695bSAhmad Draidi /** 3786f4695bSAhmad Draidi * android_image_get_kernel() - processes kernel part of Android boot images 3886f4695bSAhmad Draidi * @hdr: Pointer to image header, which is at the start 3986f4695bSAhmad Draidi * of the image. 4086f4695bSAhmad Draidi * @verify: Checksum verification flag. Currently unimplemented. 4186f4695bSAhmad Draidi * @os_data: Pointer to a ulong variable, will hold os data start 4286f4695bSAhmad Draidi * address. 4386f4695bSAhmad Draidi * @os_len: Pointer to a ulong variable, will hold os data length. 4486f4695bSAhmad Draidi * 4586f4695bSAhmad Draidi * This function returns the os image's start address and length. Also, 4686f4695bSAhmad Draidi * it appends the kernel command line to the bootargs env variable. 4786f4695bSAhmad Draidi * 4886f4695bSAhmad Draidi * Return: Zero, os start address and length on success, 4986f4695bSAhmad Draidi * otherwise on failure. 5086f4695bSAhmad Draidi */ 519ace3fc8SSebastian Siewior int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify, 529ace3fc8SSebastian Siewior ulong *os_data, ulong *os_len) 539ace3fc8SSebastian Siewior { 5487f02d5aSMaxime Ripard u32 kernel_addr = android_image_get_kernel_addr(hdr); 5587f02d5aSMaxime Ripard 569ace3fc8SSebastian Siewior /* 579ace3fc8SSebastian Siewior * Not all Android tools use the id field for signing the image with 589ace3fc8SSebastian Siewior * sha1 (or anything) so we don't check it. It is not obvious that the 599ace3fc8SSebastian Siewior * string is null terminated so we take care of this. 609ace3fc8SSebastian Siewior */ 619ace3fc8SSebastian Siewior strncpy(andr_tmp_str, hdr->name, ANDR_BOOT_NAME_SIZE); 629ace3fc8SSebastian Siewior andr_tmp_str[ANDR_BOOT_NAME_SIZE] = '\0'; 639ace3fc8SSebastian Siewior if (strlen(andr_tmp_str)) 649ace3fc8SSebastian Siewior printf("Android's image name: %s\n", andr_tmp_str); 659ace3fc8SSebastian Siewior 669ace3fc8SSebastian Siewior printf("Kernel load addr 0x%08x size %u KiB\n", 6787f02d5aSMaxime Ripard kernel_addr, DIV_ROUND_UP(hdr->kernel_size, 1024)); 6886f4695bSAhmad Draidi 6986f4695bSAhmad Draidi int len = 0; 7086f4695bSAhmad Draidi if (*hdr->cmdline) { 7186f4695bSAhmad Draidi printf("Kernel command line: %s\n", hdr->cmdline); 7286f4695bSAhmad Draidi len += strlen(hdr->cmdline); 739ace3fc8SSebastian Siewior } 7486f4695bSAhmad Draidi 7586f4695bSAhmad Draidi char *bootargs = getenv("bootargs"); 7686f4695bSAhmad Draidi if (bootargs) 7786f4695bSAhmad Draidi len += strlen(bootargs); 7886f4695bSAhmad Draidi 7986f4695bSAhmad Draidi char *newbootargs = malloc(len + 2); 8086f4695bSAhmad Draidi if (!newbootargs) { 8186f4695bSAhmad Draidi puts("Error: malloc in android_image_get_kernel failed!\n"); 8286f4695bSAhmad Draidi return -ENOMEM; 8386f4695bSAhmad Draidi } 8486f4695bSAhmad Draidi *newbootargs = '\0'; 8586f4695bSAhmad Draidi 8686f4695bSAhmad Draidi if (bootargs) { 8786f4695bSAhmad Draidi strcpy(newbootargs, bootargs); 8886f4695bSAhmad Draidi strcat(newbootargs, " "); 8986f4695bSAhmad Draidi } 9086f4695bSAhmad Draidi if (*hdr->cmdline) 9186f4695bSAhmad Draidi strcat(newbootargs, hdr->cmdline); 9286f4695bSAhmad Draidi 93*382bee57SSimon Glass env_set("bootargs", newbootargs); 949ace3fc8SSebastian Siewior 959ace3fc8SSebastian Siewior if (os_data) { 969ace3fc8SSebastian Siewior *os_data = (ulong)hdr; 979ace3fc8SSebastian Siewior *os_data += hdr->page_size; 989ace3fc8SSebastian Siewior } 999ace3fc8SSebastian Siewior if (os_len) 1009ace3fc8SSebastian Siewior *os_len = hdr->kernel_size; 1019ace3fc8SSebastian Siewior return 0; 1029ace3fc8SSebastian Siewior } 1039ace3fc8SSebastian Siewior 1049ace3fc8SSebastian Siewior int android_image_check_header(const struct andr_img_hdr *hdr) 1059ace3fc8SSebastian Siewior { 1069ace3fc8SSebastian Siewior return memcmp(ANDR_BOOT_MAGIC, hdr->magic, ANDR_BOOT_MAGIC_SIZE); 1079ace3fc8SSebastian Siewior } 1089ace3fc8SSebastian Siewior 1099ace3fc8SSebastian Siewior ulong android_image_get_end(const struct andr_img_hdr *hdr) 1109ace3fc8SSebastian Siewior { 11186f4695bSAhmad Draidi ulong end; 1129ace3fc8SSebastian Siewior /* 1139ace3fc8SSebastian Siewior * The header takes a full page, the remaining components are aligned 1149ace3fc8SSebastian Siewior * on page boundary 1159ace3fc8SSebastian Siewior */ 11686f4695bSAhmad Draidi end = (ulong)hdr; 11786f4695bSAhmad Draidi end += hdr->page_size; 11886f4695bSAhmad Draidi end += ALIGN(hdr->kernel_size, hdr->page_size); 11986f4695bSAhmad Draidi end += ALIGN(hdr->ramdisk_size, hdr->page_size); 12086f4695bSAhmad Draidi end += ALIGN(hdr->second_size, hdr->page_size); 1219ace3fc8SSebastian Siewior 12286f4695bSAhmad Draidi return end; 1239ace3fc8SSebastian Siewior } 1249ace3fc8SSebastian Siewior 1259ace3fc8SSebastian Siewior ulong android_image_get_kload(const struct andr_img_hdr *hdr) 1269ace3fc8SSebastian Siewior { 12787f02d5aSMaxime Ripard return android_image_get_kernel_addr(hdr); 1289ace3fc8SSebastian Siewior } 1299ace3fc8SSebastian Siewior 1309ace3fc8SSebastian Siewior int android_image_get_ramdisk(const struct andr_img_hdr *hdr, 1319ace3fc8SSebastian Siewior ulong *rd_data, ulong *rd_len) 1329ace3fc8SSebastian Siewior { 1339950098eSRob Herring if (!hdr->ramdisk_size) { 1349950098eSRob Herring *rd_data = *rd_len = 0; 1359ace3fc8SSebastian Siewior return -1; 1369950098eSRob Herring } 13786f4695bSAhmad Draidi 13886f4695bSAhmad Draidi printf("RAM disk load addr 0x%08x size %u KiB\n", 13986f4695bSAhmad Draidi hdr->ramdisk_addr, DIV_ROUND_UP(hdr->ramdisk_size, 1024)); 14086f4695bSAhmad Draidi 1419ace3fc8SSebastian Siewior *rd_data = (unsigned long)hdr; 1429ace3fc8SSebastian Siewior *rd_data += hdr->page_size; 1439ace3fc8SSebastian Siewior *rd_data += ALIGN(hdr->kernel_size, hdr->page_size); 1449ace3fc8SSebastian Siewior 1459ace3fc8SSebastian Siewior *rd_len = hdr->ramdisk_size; 1469ace3fc8SSebastian Siewior return 0; 1479ace3fc8SSebastian Siewior } 1484f1318b2SMichael Trimarchi 1494f1318b2SMichael Trimarchi #if !defined(CONFIG_SPL_BUILD) 1504f1318b2SMichael Trimarchi /** 1514f1318b2SMichael Trimarchi * android_print_contents - prints out the contents of the Android format image 1524f1318b2SMichael Trimarchi * @hdr: pointer to the Android format image header 1534f1318b2SMichael Trimarchi * 1544f1318b2SMichael Trimarchi * android_print_contents() formats a multi line Android image contents 1554f1318b2SMichael Trimarchi * description. 1564f1318b2SMichael Trimarchi * The routine prints out Android image properties 1574f1318b2SMichael Trimarchi * 1584f1318b2SMichael Trimarchi * returns: 1594f1318b2SMichael Trimarchi * no returned results 1604f1318b2SMichael Trimarchi */ 1614f1318b2SMichael Trimarchi void android_print_contents(const struct andr_img_hdr *hdr) 1624f1318b2SMichael Trimarchi { 1634f1318b2SMichael Trimarchi const char * const p = IMAGE_INDENT_STRING; 164210a7176SAlex Deymo /* os_version = ver << 11 | lvl */ 165210a7176SAlex Deymo u32 os_ver = hdr->os_version >> 11; 166210a7176SAlex Deymo u32 os_lvl = hdr->os_version & ((1U << 11) - 1); 1674f1318b2SMichael Trimarchi 1684f1318b2SMichael Trimarchi printf("%skernel size: %x\n", p, hdr->kernel_size); 1694f1318b2SMichael Trimarchi printf("%skernel address: %x\n", p, hdr->kernel_addr); 1704f1318b2SMichael Trimarchi printf("%sramdisk size: %x\n", p, hdr->ramdisk_size); 1714f1318b2SMichael Trimarchi printf("%sramdisk addrress: %x\n", p, hdr->ramdisk_addr); 1724f1318b2SMichael Trimarchi printf("%ssecond size: %x\n", p, hdr->second_size); 1734f1318b2SMichael Trimarchi printf("%ssecond address: %x\n", p, hdr->second_addr); 1744f1318b2SMichael Trimarchi printf("%stags address: %x\n", p, hdr->tags_addr); 1754f1318b2SMichael Trimarchi printf("%spage size: %x\n", p, hdr->page_size); 176210a7176SAlex Deymo /* ver = A << 14 | B << 7 | C (7 bits for each of A, B, C) 177210a7176SAlex Deymo * lvl = ((Y - 2000) & 127) << 4 | M (7 bits for Y, 4 bits for M) */ 178210a7176SAlex Deymo printf("%sos_version: %x (ver: %u.%u.%u, level: %u.%u)\n", 179210a7176SAlex Deymo p, hdr->os_version, 180210a7176SAlex Deymo (os_ver >> 7) & 0x7F, (os_ver >> 14) & 0x7F, os_ver & 0x7F, 181210a7176SAlex Deymo (os_lvl >> 4) + 2000, os_lvl & 0x0F); 1824f1318b2SMichael Trimarchi printf("%sname: %s\n", p, hdr->name); 1834f1318b2SMichael Trimarchi printf("%scmdline: %s\n", p, hdr->cmdline); 1844f1318b2SMichael Trimarchi } 1854f1318b2SMichael Trimarchi #endif 186