xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/resource_img.c (revision a66fd6dcbc6344967fabd3e7a5f8ec6bb585d0e2)
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