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 goto out; 204 } 205 andr_hdr = (void *)hdr; 206 ret = blk_dread(dev_desc, part_info.start, 1, andr_hdr); 207 if (ret != 1) { 208 printf("%s read fail\n", __func__); 209 goto out; 210 } 211 ret = android_image_check_header(andr_hdr); 212 if (!ret) { 213 debug("%s Load resource from %s senond pos\n", 214 __func__, part_info.name); 215 /* Read resource from second offset */ 216 offset = part_info.start * RK_BLK_SIZE; 217 offset += andr_hdr->page_size; 218 offset += ALIGN(andr_hdr->kernel_size, andr_hdr->page_size); 219 offset += ALIGN(andr_hdr->ramdisk_size, andr_hdr->page_size); 220 offset = offset / RK_BLK_SIZE; 221 } else { 222 /* Set mode to 0 in for recovery is not valid AOSP img */ 223 mode = 0; 224 } 225 #endif 226 if (!mode) { 227 /* Read resource from Rockchip Resource partition */ 228 ret = part_get_info_by_name(dev_desc, PART_RESOURCE, 229 &part_info); 230 if (ret < 0) { 231 printf("fail to get %s part\n", PART_RESOURCE); 232 goto out; 233 } 234 offset = part_info.start; 235 debug("%s Load resource from %s\n", __func__, part_info.name); 236 } 237 238 ret = blk_dread(dev_desc, offset, 1, hdr); 239 if (ret != 1) 240 goto out; 241 ret = resource_image_check_header(hdr); 242 if (ret < 0) 243 goto out; 244 content = memalign(ARCH_DMA_MINALIGN, 245 hdr->e_blks * hdr->e_nums * RK_BLK_SIZE); 246 if (!content) { 247 printf("alloc memory for content failed\n"); 248 goto out; 249 } 250 ret = blk_dread(dev_desc, offset + hdr->c_offset, 251 hdr->e_blks * hdr->e_nums, content); 252 if (ret != (hdr->e_blks * hdr->e_nums)) 253 goto err; 254 255 for (e_num = 0; e_num < hdr->e_nums; e_num++) { 256 size = e_num * hdr->e_blks * RK_BLK_SIZE; 257 entry = (struct resource_entry *)(content + size); 258 add_file_to_list(entry, offset); 259 } 260 261 err: 262 free(content); 263 out: 264 free(hdr); 265 266 return 0; 267 } 268 269 static struct resource_file *get_file_info(struct resource_img_hdr *hdr, 270 const char *name) 271 { 272 struct resource_file *file; 273 struct list_head *node; 274 275 if (list_empty(&entrys_head)) 276 init_resource_list(hdr); 277 278 list_for_each(node, &entrys_head) { 279 file = list_entry(node, struct resource_file, link); 280 if (!strcmp(file->name, name)) 281 return file; 282 } 283 284 return NULL; 285 } 286 287 int rockchip_get_resource_file(void *buf, const char *name) 288 { 289 struct resource_file *file; 290 291 file = get_file_info(buf, name); 292 293 return file->f_offset; 294 } 295 296 /* 297 * read file from resource partition 298 * @buf: destination buf to store file data; 299 * @name: file name 300 * @offset: blocks offset in the file, 1 block = 512 bytes 301 * @len: the size(by bytes) of file to read. 302 */ 303 int rockchip_read_resource_file(void *buf, const char *name, 304 int offset, int len) 305 { 306 struct resource_file *file; 307 int ret = 0; 308 int blks; 309 struct blk_desc *dev_desc; 310 311 file = get_file_info(NULL, name); 312 if (!file) { 313 printf("Can't find file:%s\n", name); 314 return -ENOENT; 315 } 316 317 if (len <= 0 || len > file->f_size) 318 len = file->f_size; 319 blks = DIV_ROUND_UP(len, RK_BLK_SIZE); 320 dev_desc = rockchip_get_bootdev(); 321 ret = blk_dread(dev_desc, file->rsce_base + file->f_offset + offset, 322 blks, buf); 323 if (ret != blks) 324 ret = -EIO; 325 else 326 ret = len; 327 328 return ret; 329 } 330