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