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