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