1 /* 2 * (C) Copyright 2017 Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 #include <common.h> 7 #include <malloc.h> 8 #include <linux/list.h> 9 #include <asm/arch/resource_img.h> 10 #include <boot_rkimg.h> 11 #ifdef CONFIG_ANDROID_AB 12 #include <android_avb/libavb_ab.h> 13 #include <android_avb/rk_avb_ops_user.h> 14 #endif 15 #ifdef CONFIG_ANDROID_BOOT_IMAGE 16 #include <android_bootloader.h> 17 #include <android_image.h> 18 #endif 19 20 #define PART_RESOURCE "resource" 21 #define RESOURCE_MAGIC "RSCE" 22 #define RESOURCE_MAGIC_SIZE 4 23 #define RESOURCE_VERSION 0 24 #define CONTENT_VERSION 0 25 #define ENTRY_TAG "ENTR" 26 #define ENTRY_TAG_SIZE 4 27 #define MAX_FILE_NAME_LEN 256 28 29 /* 30 * resource image structure 31 * ---------------------------------------------- 32 * | | 33 * | header (1 block) | 34 * | | 35 * ---------------------------------------------| 36 * | | | 37 * | entry0 (1 block) | | 38 * | | | 39 * ------------------------ | 40 * | | | 41 * | entry1 (1 block) | contents (n blocks) | 42 * | | | 43 * ------------------------ | 44 * | ...... | | 45 * ------------------------ | 46 * | | | 47 * | entryn (1 block) | | 48 * | | | 49 * ---------------------------------------------- 50 * | | 51 * | file0 (x blocks) | 52 * | | 53 * ---------------------------------------------- 54 * | | 55 * | file1 (y blocks) | 56 * | | 57 * ---------------------------------------------- 58 * | ...... | 59 * |--------------------------------------------- 60 * | | 61 * | filen (z blocks) | 62 * | | 63 * ---------------------------------------------- 64 */ 65 66 /** 67 * struct resource_image_header 68 * 69 * @magic: should be "RSCE" 70 * @version: resource image version, current is 0 71 * @c_version: content version, current is 0 72 * @blks: the size of the header ( 1 block = 512 bytes) 73 * @c_offset: contents offset(by block) in the image 74 * @e_blks: the size(by block) of the entry in the contents 75 * @e_num: numbers of the entrys. 76 */ 77 78 struct resource_img_hdr { 79 char magic[4]; 80 uint16_t version; 81 uint16_t c_version; 82 uint8_t blks; 83 uint8_t c_offset; 84 uint8_t e_blks; 85 uint32_t e_nums; 86 }; 87 88 struct resource_entry { 89 char tag[4]; 90 char name[MAX_FILE_NAME_LEN]; 91 uint32_t f_offset; 92 uint32_t f_size; 93 }; 94 95 struct resource_file { 96 char name[MAX_FILE_NAME_LEN]; 97 uint32_t f_offset; 98 uint32_t f_size; 99 struct list_head link; 100 uint32_t rsce_base; /* Base addr of resource */ 101 }; 102 103 static LIST_HEAD(entrys_head); 104 105 static int resource_image_check_header(const struct resource_img_hdr *hdr) 106 { 107 int ret; 108 109 ret = memcmp(RESOURCE_MAGIC, hdr->magic, RESOURCE_MAGIC_SIZE); 110 if (ret) { 111 printf("bad resource image magic\n"); 112 ret = -EINVAL; 113 } 114 debug("resource image header:\n"); 115 debug("magic:%s\n", hdr->magic); 116 debug("version:%d\n", hdr->version); 117 debug("c_version:%d\n", hdr->c_version); 118 debug("blks:%d\n", hdr->blks); 119 debug("c_offset:%d\n", hdr->c_offset); 120 debug("e_blks:%d\n", hdr->e_blks); 121 debug("e_num:%d\n", hdr->e_nums); 122 123 return ret; 124 } 125 126 static int add_file_to_list(struct resource_entry *entry, int rsce_base) 127 { 128 struct resource_file *file; 129 130 if (memcmp(entry->tag, ENTRY_TAG, ENTRY_TAG_SIZE)) { 131 printf("invalid entry tag\n"); 132 return -ENOENT; 133 } 134 file = malloc(sizeof(*file)); 135 if (!file) { 136 printf("out of memory\n"); 137 return -ENOMEM; 138 } 139 strcpy(file->name, entry->name); 140 file->rsce_base = rsce_base; 141 file->f_offset = entry->f_offset; 142 file->f_size = entry->f_size; 143 list_add_tail(&file->link, &entrys_head); 144 debug("entry:%p %s offset:%d size:%d\n", 145 entry, file->name, file->f_offset, file->f_size); 146 147 return 0; 148 } 149 150 static int init_resource_list(struct resource_img_hdr *hdr) 151 { 152 struct resource_entry *entry; 153 void *content; 154 int size; 155 int ret; 156 int e_num; 157 int offset = 0; 158 int mode = 0; 159 struct blk_desc *dev_desc; 160 disk_partition_t part_info; 161 #ifdef CONFIG_ANDROID_BOOT_IMAGE 162 struct andr_img_hdr *andr_hdr; 163 char *boot_partname = PART_BOOT; 164 #endif 165 166 if (hdr) { 167 content = (void *)((char *)hdr 168 + (hdr->c_offset) * RK_BLK_SIZE); 169 for (e_num = 0; e_num < hdr->e_nums; e_num++) { 170 size = e_num * hdr->e_blks * RK_BLK_SIZE; 171 entry = (struct resource_entry *)(content + size); 172 add_file_to_list(entry, offset); 173 } 174 return 0; 175 } 176 177 dev_desc = rockchip_get_bootdev(); 178 hdr = memalign(ARCH_DMA_MINALIGN, RK_BLK_SIZE); 179 if (!hdr) { 180 printf("%s out of memory!\n", __func__); 181 return -ENOMEM; 182 } 183 184 #ifdef CONFIG_ANDROID_BOOT_IMAGE 185 /* Get boot mode from misc */ 186 mode = rockchip_get_boot_mode(); 187 if (mode == BOOT_MODE_RECOVERY) 188 boot_partname = PART_RECOVERY; 189 /* Read boot/recovery and chenc if this is an AOSP img */ 190 #ifdef CONFIG_ANDROID_AB 191 char slot_suffix[3] = {0}; 192 193 if (rk_avb_get_current_slot(slot_suffix)) 194 goto out; 195 boot_partname = android_str_append(boot_partname, slot_suffix); 196 if (boot_partname == NULL) 197 goto out; 198 #endif 199 ret = part_get_info_by_name(dev_desc, boot_partname, 200 &part_info); 201 if (ret < 0) { 202 printf("fail to get %s part\n", boot_partname); 203 /* RKIMG can support part table without 'boot' */ 204 mode = 0; 205 goto next; 206 } 207 andr_hdr = (void *)hdr; 208 ret = blk_dread(dev_desc, part_info.start, 1, andr_hdr); 209 if (ret != 1) { 210 printf("%s read fail\n", __func__); 211 goto out; 212 } 213 ret = android_image_check_header(andr_hdr); 214 if (!ret) { 215 debug("%s Load resource from %s senond pos\n", 216 __func__, part_info.name); 217 /* Read resource from second offset */ 218 offset = part_info.start * RK_BLK_SIZE; 219 offset += andr_hdr->page_size; 220 offset += ALIGN(andr_hdr->kernel_size, andr_hdr->page_size); 221 offset += ALIGN(andr_hdr->ramdisk_size, andr_hdr->page_size); 222 offset = offset / RK_BLK_SIZE; 223 } else { 224 /* Set mode to 0 in for recovery is not valid AOSP img */ 225 mode = 0; 226 } 227 next: 228 #endif 229 if (!mode) { 230 /* Read resource from Rockchip Resource partition */ 231 ret = part_get_info_by_name(dev_desc, PART_RESOURCE, 232 &part_info); 233 if (ret < 0) { 234 printf("fail to get %s part\n", PART_RESOURCE); 235 goto out; 236 } 237 offset = part_info.start; 238 debug("%s Load resource from %s\n", __func__, part_info.name); 239 } 240 241 ret = blk_dread(dev_desc, offset, 1, hdr); 242 if (ret != 1) 243 goto out; 244 ret = resource_image_check_header(hdr); 245 if (ret < 0) 246 goto out; 247 content = memalign(ARCH_DMA_MINALIGN, 248 hdr->e_blks * hdr->e_nums * RK_BLK_SIZE); 249 if (!content) { 250 printf("alloc memory for content failed\n"); 251 goto out; 252 } 253 ret = blk_dread(dev_desc, offset + hdr->c_offset, 254 hdr->e_blks * hdr->e_nums, content); 255 if (ret != (hdr->e_blks * hdr->e_nums)) 256 goto err; 257 258 for (e_num = 0; e_num < hdr->e_nums; e_num++) { 259 size = e_num * hdr->e_blks * RK_BLK_SIZE; 260 entry = (struct resource_entry *)(content + size); 261 add_file_to_list(entry, offset); 262 } 263 264 err: 265 free(content); 266 out: 267 free(hdr); 268 269 return 0; 270 } 271 272 static struct resource_file *get_file_info(struct resource_img_hdr *hdr, 273 const char *name) 274 { 275 struct resource_file *file; 276 struct list_head *node; 277 278 if (list_empty(&entrys_head)) 279 init_resource_list(hdr); 280 281 list_for_each(node, &entrys_head) { 282 file = list_entry(node, struct resource_file, link); 283 if (!strcmp(file->name, name)) 284 return file; 285 } 286 287 return NULL; 288 } 289 290 int rockchip_get_resource_file(void *buf, const char *name) 291 { 292 struct resource_file *file; 293 294 file = get_file_info(buf, name); 295 296 return file->f_offset; 297 } 298 299 /* 300 * read file from resource partition 301 * @buf: destination buf to store file data; 302 * @name: file name 303 * @offset: blocks offset in the file, 1 block = 512 bytes 304 * @len: the size(by bytes) of file to read. 305 */ 306 int rockchip_read_resource_file(void *buf, const char *name, 307 int offset, int len) 308 { 309 struct resource_file *file; 310 int ret = 0; 311 int blks; 312 struct blk_desc *dev_desc; 313 314 file = get_file_info(NULL, name); 315 if (!file) { 316 printf("Can't find file:%s\n", name); 317 return -ENOENT; 318 } 319 320 if (len <= 0 || len > file->f_size) 321 len = file->f_size; 322 blks = DIV_ROUND_UP(len, RK_BLK_SIZE); 323 dev_desc = rockchip_get_bootdev(); 324 ret = blk_dread(dev_desc, file->rsce_base + file->f_offset + offset, 325 blks, buf); 326 if (ret != blks) 327 ret = -EIO; 328 else 329 ret = len; 330 331 return ret; 332 } 333