1 /* 2 * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de> 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <image.h> 9 #include <android_image.h> 10 #include <malloc.h> 11 #include <mapmem.h> 12 #include <errno.h> 13 #ifdef CONFIG_RKIMG_BOOTLOADER 14 #include <asm/arch/resource_img.h> 15 #endif 16 17 DECLARE_GLOBAL_DATA_PTR; 18 19 #define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR 0x10008000 20 #define ANDROID_ARG_FDT_FILENAME "rk-kernel.dtb" 21 22 static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1]; 23 static u32 android_kernel_comp_type = IH_COMP_NONE; 24 25 static ulong android_image_get_kernel_addr(const struct andr_img_hdr *hdr) 26 { 27 /* 28 * All the Android tools that generate a boot.img use this 29 * address as the default. 30 * 31 * Even though it doesn't really make a lot of sense, and it 32 * might be valid on some platforms, we treat that adress as 33 * the default value for this field, and try to execute the 34 * kernel in place in such a case. 35 * 36 * Otherwise, we will return the actual value set by the user. 37 */ 38 if (hdr->kernel_addr == ANDROID_IMAGE_DEFAULT_KERNEL_ADDR) 39 return (ulong)hdr + hdr->page_size; 40 41 return hdr->kernel_addr; 42 } 43 44 void android_image_set_comp(struct andr_img_hdr *hdr, u32 comp) 45 { 46 android_kernel_comp_type = comp; 47 } 48 49 u32 android_image_get_comp(const struct andr_img_hdr *hdr) 50 { 51 return android_kernel_comp_type; 52 } 53 54 int android_image_parse_kernel_comp(const struct andr_img_hdr *hdr) 55 { 56 ulong kaddr = android_image_get_kernel_addr(hdr); 57 return bootm_parse_comp((const unsigned char *)kaddr); 58 } 59 60 /** 61 * android_image_get_kernel() - processes kernel part of Android boot images 62 * @hdr: Pointer to image header, which is at the start 63 * of the image. 64 * @verify: Checksum verification flag. Currently unimplemented. 65 * @os_data: Pointer to a ulong variable, will hold os data start 66 * address. 67 * @os_len: Pointer to a ulong variable, will hold os data length. 68 * 69 * This function returns the os image's start address and length. Also, 70 * it appends the kernel command line to the bootargs env variable. 71 * 72 * Return: Zero, os start address and length on success, 73 * otherwise on failure. 74 */ 75 int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify, 76 ulong *os_data, ulong *os_len) 77 { 78 u32 kernel_addr = android_image_get_kernel_addr(hdr); 79 80 /* 81 * Not all Android tools use the id field for signing the image with 82 * sha1 (or anything) so we don't check it. It is not obvious that the 83 * string is null terminated so we take care of this. 84 */ 85 strncpy(andr_tmp_str, hdr->name, ANDR_BOOT_NAME_SIZE); 86 andr_tmp_str[ANDR_BOOT_NAME_SIZE] = '\0'; 87 if (strlen(andr_tmp_str)) 88 printf("Android's image name: %s\n", andr_tmp_str); 89 90 printf("Kernel load addr 0x%08x size %u KiB\n", 91 kernel_addr, DIV_ROUND_UP(hdr->kernel_size, 1024)); 92 93 int len = 0; 94 if (*hdr->cmdline) { 95 debug("Kernel command line: %s\n", hdr->cmdline); 96 len += strlen(hdr->cmdline); 97 } 98 99 char *bootargs = env_get("bootargs"); 100 if (bootargs) 101 len += strlen(bootargs); 102 103 char *newbootargs = malloc(len + 2); 104 if (!newbootargs) { 105 puts("Error: malloc in android_image_get_kernel failed!\n"); 106 return -ENOMEM; 107 } 108 *newbootargs = '\0'; 109 110 if (bootargs) { 111 strcpy(newbootargs, bootargs); 112 strcat(newbootargs, " "); 113 } 114 if (*hdr->cmdline) 115 strcat(newbootargs, hdr->cmdline); 116 117 env_set("bootargs", newbootargs); 118 119 if (os_data) { 120 *os_data = (ulong)hdr; 121 *os_data += hdr->page_size; 122 } 123 if (os_len) 124 *os_len = hdr->kernel_size; 125 return 0; 126 } 127 128 int android_image_check_header(const struct andr_img_hdr *hdr) 129 { 130 return memcmp(ANDR_BOOT_MAGIC, hdr->magic, ANDR_BOOT_MAGIC_SIZE); 131 } 132 133 ulong android_image_get_end(const struct andr_img_hdr *hdr) 134 { 135 ulong end; 136 /* 137 * The header takes a full page, the remaining components are aligned 138 * on page boundary 139 */ 140 end = (ulong)hdr; 141 end += hdr->page_size; 142 end += ALIGN(hdr->kernel_size, hdr->page_size); 143 end += ALIGN(hdr->ramdisk_size, hdr->page_size); 144 end += ALIGN(hdr->second_size, hdr->page_size); 145 146 if (hdr->header_version >= 1) 147 end += ALIGN(hdr->recovery_dtbo_size, hdr->page_size); 148 149 return end; 150 } 151 152 u32 android_image_get_ksize(const struct andr_img_hdr *hdr) 153 { 154 return hdr->kernel_size; 155 } 156 157 void android_image_set_kload(struct andr_img_hdr *hdr, u32 load_address) 158 { 159 hdr->kernel_addr = load_address; 160 } 161 162 ulong android_image_get_kload(const struct andr_img_hdr *hdr) 163 { 164 return android_image_get_kernel_addr(hdr); 165 } 166 167 int android_image_get_ramdisk(const struct andr_img_hdr *hdr, 168 ulong *rd_data, ulong *rd_len) 169 { 170 if (!hdr->ramdisk_size) { 171 *rd_data = *rd_len = 0; 172 return -1; 173 } 174 175 printf("RAM disk load addr 0x%08x size %u KiB\n", 176 hdr->ramdisk_addr, DIV_ROUND_UP(hdr->ramdisk_size, 1024)); 177 178 *rd_data = (unsigned long)hdr; 179 *rd_data += hdr->page_size; 180 *rd_data += ALIGN(hdr->kernel_size, hdr->page_size); 181 182 *rd_len = hdr->ramdisk_size; 183 return 0; 184 } 185 186 int android_image_get_fdt(const struct andr_img_hdr *hdr, 187 ulong *rd_data) 188 { 189 if (!hdr->second_size) { 190 *rd_data = 0; 191 return -1; 192 } 193 194 printf("FDT load addr 0x%08x size %u KiB\n", 195 hdr->second_addr, DIV_ROUND_UP(hdr->second_size, 1024)); 196 /* 197 * Actually we have read kernel dtb in init_kernel_dtb() and do overlay 198 * when CONFIG_USING_KERNEL_DTB is enbled, and we also didn't update it at all. 199 * So that we pass current fdt blob to kernel, otherwise we have to do overlay 200 * again which wastes time. 201 */ 202 #if defined(CONFIG_OF_LIBFDT_OVERLAY) && defined(CONFIG_USING_KERNEL_DTB) 203 *rd_data = (ulong)gd->fdt_blob; 204 #else 205 *rd_data = (unsigned long)hdr; 206 *rd_data += hdr->page_size; 207 *rd_data += ALIGN(hdr->kernel_size, hdr->page_size); 208 *rd_data += ALIGN(hdr->ramdisk_size, hdr->page_size); 209 #ifdef CONFIG_RKIMG_BOOTLOADER 210 *rd_data += (rockchip_get_resource_file((void *)*rd_data, 211 ANDROID_ARG_FDT_FILENAME)) 212 * 512; 213 #endif 214 #endif 215 216 return 0; 217 } 218 219 long android_image_load(struct blk_desc *dev_desc, 220 const disk_partition_t *part_info, 221 unsigned long load_address, 222 unsigned long max_size) { 223 void *buf; 224 long blk_cnt = 0; 225 long blk_read = 0; 226 u32 comp; 227 u32 kload_addr; 228 229 if (max_size < part_info->blksz) 230 return -1; 231 232 /* We don't know the size of the Android image before reading the header 233 * so we don't limit the size of the mapped memory. 234 */ 235 buf = map_sysmem(load_address, 0 /* size */); 236 237 /* Read the Android boot.img header and a few parts of 238 * the head of kernel image. 239 */ 240 if (blk_dread(dev_desc, part_info->start, 8, buf) != 8) 241 blk_read = -1; 242 243 if (!blk_read && android_image_check_header(buf) != 0) { 244 printf("** Invalid Android Image header **\n"); 245 blk_read = -1; 246 } 247 248 249 if (!blk_read) { 250 blk_cnt = (android_image_get_end(buf) - (ulong)buf + 251 part_info->blksz - 1) / part_info->blksz; 252 comp = android_image_parse_kernel_comp(buf); 253 /* 254 * We should load a compressed kernel Image 255 * to high memory 256 */ 257 if (comp != IH_COMP_NONE) { 258 load_address += android_image_get_ksize(buf) * 3; 259 load_address = env_get_ulong("kernel_addr_c", 16, load_address); 260 unmap_sysmem(buf); 261 buf = map_sysmem(load_address, 0 /* size */); 262 } 263 264 if (blk_cnt * part_info->blksz > max_size) { 265 debug("Android Image too big (%lu bytes, max %lu)\n", 266 android_image_get_end(buf) - (ulong)buf, 267 max_size); 268 blk_read = -1; 269 } else { 270 debug("Loading Android Image (%lu blocks) to 0x%lx... ", 271 blk_cnt, load_address); 272 blk_read = blk_dread(dev_desc, part_info->start, 273 blk_cnt, buf); 274 } 275 276 /* 277 * zImage is not need to decompress 278 * kernel will handle decompress itself 279 */ 280 if (comp != IH_COMP_NONE && comp != IH_COMP_ZIMAGE) { 281 kload_addr = env_get_ulong("kernel_addr_r", 16, 0x02080000); 282 android_image_set_kload(buf, kload_addr); 283 android_image_set_comp(buf, comp); 284 } else { 285 android_image_set_comp(buf, IH_COMP_NONE); 286 } 287 288 } 289 290 unmap_sysmem(buf); 291 292 debug("%lu blocks read: %s\n", 293 blk_read, (blk_read == blk_cnt) ? "OK" : "ERROR"); 294 if (blk_read != blk_cnt) 295 return -1; 296 297 return load_address; 298 } 299 300 #if !defined(CONFIG_SPL_BUILD) 301 /** 302 * android_print_contents - prints out the contents of the Android format image 303 * @hdr: pointer to the Android format image header 304 * 305 * android_print_contents() formats a multi line Android image contents 306 * description. 307 * The routine prints out Android image properties 308 * 309 * returns: 310 * no returned results 311 */ 312 void android_print_contents(const struct andr_img_hdr *hdr) 313 { 314 const char * const p = IMAGE_INDENT_STRING; 315 /* os_version = ver << 11 | lvl */ 316 u32 os_ver = hdr->os_version >> 11; 317 u32 os_lvl = hdr->os_version & ((1U << 11) - 1); 318 u32 header_version = hdr->header_version; 319 320 printf("%skernel size: %x\n", p, hdr->kernel_size); 321 printf("%skernel address: %x\n", p, hdr->kernel_addr); 322 printf("%sramdisk size: %x\n", p, hdr->ramdisk_size); 323 printf("%sramdisk addrress: %x\n", p, hdr->ramdisk_addr); 324 printf("%ssecond size: %x\n", p, hdr->second_size); 325 printf("%ssecond address: %x\n", p, hdr->second_addr); 326 printf("%stags address: %x\n", p, hdr->tags_addr); 327 printf("%spage size: %x\n", p, hdr->page_size); 328 printf("%sheader_version: %x\n", p, header_version); 329 /* ver = A << 14 | B << 7 | C (7 bits for each of A, B, C) 330 * lvl = ((Y - 2000) & 127) << 4 | M (7 bits for Y, 4 bits for M) */ 331 printf("%sos_version: %x (ver: %u.%u.%u, level: %u.%u)\n", 332 p, hdr->os_version, 333 (os_ver >> 7) & 0x7F, (os_ver >> 14) & 0x7F, os_ver & 0x7F, 334 (os_lvl >> 4) + 2000, os_lvl & 0x0F); 335 printf("%sname: %s\n", p, hdr->name); 336 printf("%scmdline: %s\n", p, hdr->cmdline); 337 338 if (header_version >= 1) { 339 printf("%srecovery dtbo size: %x\n", p, hdr->recovery_dtbo_size); 340 printf("%srecovery dtbo offset: %llx\n", p, hdr->recovery_dtbo_offset); 341 printf("%sheader size: %x\n", p, hdr->header_size); 342 } 343 } 344 #endif 345