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 struct andr_img_hdr *andr_hdr; 157 disk_partition_t part_info; 158 char *boot_partname = PART_BOOT; 159 160 if (hdr) { 161 content = (void *)((char *)hdr 162 + (hdr->c_offset) * RK_BLK_SIZE); 163 for (e_num = 0; e_num < hdr->e_nums; e_num++) { 164 size = e_num * hdr->e_blks * RK_BLK_SIZE; 165 entry = (struct resource_entry *)(content + size); 166 add_file_to_list(entry, offset); 167 } 168 return 0; 169 } 170 171 dev_desc = rockchip_get_bootdev(); 172 hdr = memalign(ARCH_DMA_MINALIGN, RK_BLK_SIZE); 173 if (!hdr) { 174 printf("%s out of memory!\n", __func__); 175 return -ENOMEM; 176 } 177 178 #ifdef CONFIG_ANDROID_BOOT_IMAGE 179 /* Get boot mode from misc */ 180 mode = rockchip_get_boot_mode(); 181 if (mode == BOOT_MODE_RECOVERY) 182 boot_partname = PART_RECOVERY; 183 /* Read boot/recovery and chenc if this is an AOSP img */ 184 ret = part_get_info_by_name(dev_desc, boot_partname, 185 &part_info); 186 if (ret < 0) { 187 printf("fail to get %s part\n", boot_partname); 188 goto out; 189 } 190 andr_hdr = (void *)hdr; 191 ret = blk_dread(dev_desc, part_info.start, 1, andr_hdr); 192 if (ret != 1) { 193 printf("%s read fail\n", __func__); 194 goto out; 195 } 196 ret = android_image_check_header(andr_hdr); 197 if (!ret) { 198 debug("%s Load resource from %s senond pos\n", 199 __func__, part_info.name); 200 /* Read resource from second offset */ 201 offset = part_info.start * RK_BLK_SIZE; 202 offset += andr_hdr->page_size; 203 offset += ALIGN(andr_hdr->kernel_size, andr_hdr->page_size); 204 offset += ALIGN(andr_hdr->ramdisk_size, andr_hdr->page_size); 205 offset = offset / RK_BLK_SIZE; 206 } else { 207 /* Set mode to 0 in for recovery is not valid AOSP img */ 208 mode = 0; 209 } 210 #endif 211 if (!mode) { 212 /* Read resource from Rockchip Resource partition */ 213 ret = part_get_info_by_name(dev_desc, PART_RESOURCE, 214 &part_info); 215 if (ret < 0) { 216 printf("fail to get %s part\n", PART_RESOURCE); 217 goto out; 218 } 219 offset = part_info.start; 220 debug("%s Load resource from %s\n", __func__, part_info.name); 221 } 222 223 hdr = (void *)andr_hdr; 224 ret = blk_dread(dev_desc, offset, 1, hdr); 225 if (ret != 1) 226 goto out; 227 ret = resource_image_check_header(hdr); 228 if (ret < 0) 229 goto out; 230 content = memalign(ARCH_DMA_MINALIGN, 231 hdr->e_blks * hdr->e_nums * RK_BLK_SIZE); 232 if (!content) { 233 printf("alloc memory for content failed\n"); 234 goto out; 235 } 236 ret = blk_dread(dev_desc, offset + hdr->c_offset, 237 hdr->e_blks * hdr->e_nums, content); 238 if (ret != (hdr->e_blks * hdr->e_nums)) 239 goto err; 240 241 for (e_num = 0; e_num < hdr->e_nums; e_num++) { 242 size = e_num * hdr->e_blks * RK_BLK_SIZE; 243 entry = (struct resource_entry *)(content + size); 244 add_file_to_list(entry, offset); 245 } 246 247 err: 248 free(content); 249 out: 250 free(hdr); 251 252 return 0; 253 } 254 255 static struct resource_file *get_file_info(struct resource_img_hdr *hdr, 256 const char *name) 257 { 258 struct resource_file *file; 259 struct list_head *node; 260 261 if (list_empty(&entrys_head)) 262 init_resource_list(hdr); 263 264 list_for_each(node, &entrys_head) { 265 file = list_entry(node, struct resource_file, link); 266 if (!strcmp(file->name, name)) 267 return file; 268 } 269 270 return NULL; 271 } 272 273 int rockchip_get_resource_file(void *buf, const char *name) 274 { 275 struct resource_file *file; 276 277 file = get_file_info(buf, name); 278 279 return file->f_offset; 280 } 281 282 /* 283 * read file from resource partition 284 * @buf: destination buf to store file data; 285 * @name: file name 286 * @offset: blocks offset in the file, 1 block = 512 bytes 287 * @len: the size(by bytes) of file to read. 288 */ 289 int rockchip_read_resource_file(void *buf, const char *name, 290 int offset, int len) 291 { 292 struct resource_file *file; 293 int ret = 0; 294 int blks; 295 struct blk_desc *dev_desc; 296 297 file = get_file_info(NULL, name); 298 if (!file) { 299 printf("Can't find file:%s\n", name); 300 return -ENOENT; 301 } 302 303 if (len <= 0 || len > file->f_size) 304 len = file->f_size; 305 blks = DIV_ROUND_UP(len, RK_BLK_SIZE); 306 dev_desc = rockchip_get_bootdev(); 307 ret = blk_dread(dev_desc, file->rsce_base + file->f_offset + offset, 308 blks, buf); 309 if (ret != blks) 310 ret = -EIO; 311 else 312 ret = len; 313 314 return ret; 315 } 316