xref: /OK3568_Linux_fs/u-boot/arch/arm/mach-rockchip/resource_img.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6 #include <common.h>
7 #include <boot_rkimg.h>
8 #include <bmp_layout.h>
9 #include <malloc.h>
10 #include <asm/unaligned.h>
11 #include <linux/libfdt.h>
12 #include <linux/list.h>
13 #include <asm/arch/resource_img.h>
14 #include <asm/arch/uimage.h>
15 #include <asm/arch/fit.h>
16 
17 DECLARE_GLOBAL_DATA_PTR;
18 
19 #define PART_RESOURCE			"resource"
20 #define RESOURCE_MAGIC			"RSCE"
21 #define RESOURCE_MAGIC_SIZE		4
22 #define ENTRY_TAG			"ENTR"
23 #define ENTRY_TAG_SIZE			4
24 #define MAX_FILE_NAME_LEN		220
25 #define MAX_HASH_LEN			32
26 #define DEFAULT_DTB_FILE		"rk-kernel.dtb"
27 
28 /*
29  *         resource image structure
30  * ----------------------------------------------
31  * |                                            |
32  * |    header  (1 block)                       |
33  * |                                            |
34  * ---------------------------------------------|
35  * |                      |                     |
36  * |    entry0  (1 block) |                     |
37  * |                      |                     |
38  * ------------------------                     |
39  * |                      |                     |
40  * |    entry1  (1 block) | contents (n blocks) |
41  * |                      |                     |
42  * ------------------------                     |
43  * |    ......            |                     |
44  * ------------------------                     |
45  * |                      |                     |
46  * |    entryn  (1 block) |                     |
47  * |                      |                     |
48  * ----------------------------------------------
49  * |                                            |
50  * |    file0  (x blocks)                       |
51  * |                                            |
52  * ----------------------------------------------
53  * |                                            |
54  * |    file1  (y blocks)                       |
55  * |                                            |
56  * ----------------------------------------------
57  * |                   ......                   |
58  * |---------------------------------------------
59  * |                                            |
60  * |    filen  (z blocks)                       |
61  * |                                            |
62  * ----------------------------------------------
63  */
64 
65 /**
66  * struct resource_img_hdr
67  *
68  * @magic: should be "RSCE"
69  * @version: resource image version, current is 0
70  * @c_version: content version, current is 0
71  * @blks: the size of the header ( 1 block = 512 bytes)
72  * @c_offset: contents offset(by block) in the image
73  * @e_blks: the size(by block) of the entry in the contents
74  * @e_num: numbers of the entrys.
75  */
76 struct resource_img_hdr {
77 	char		magic[4];
78 	uint16_t	version;
79 	uint16_t	c_version;
80 	uint8_t		blks;
81 	uint8_t		c_offset;
82 	uint8_t		e_blks;
83 	uint32_t	e_nums;
84 };
85 
86 struct resource_entry {
87 	char		tag[4];
88 	char		name[MAX_FILE_NAME_LEN];
89 	char		hash[MAX_HASH_LEN];
90 	uint32_t	hash_size;
91 	uint32_t	blk_offset;
92 	uint32_t	size;		/* in byte */
93 };
94 
95 LIST_HEAD(entry_head);
96 
resource_check_header(struct resource_img_hdr * hdr)97 static int resource_check_header(struct resource_img_hdr *hdr)
98 {
99 	return memcmp(RESOURCE_MAGIC, hdr->magic, RESOURCE_MAGIC_SIZE);
100 }
101 
resource_dump(struct resource_file * f)102 static void resource_dump(struct resource_file *f)
103 {
104 	printf("%s\n", f->name);
105 	printf("  blk_start:  0x%08lx\n", (ulong)f->blk_start);
106 	printf("  blk_offset: 0x%08lx\n", (ulong)f->blk_offset);
107 	printf("  size:       0x%08x\n", f->size);
108 	printf("  in_ram:     %d\n", f->in_ram);
109 	printf("  hash_size:  %d\n\n", f->hash_size);
110 }
111 
resource_add_file(const char * name,u32 size,u32 blk_start,u32 blk_offset,char * hash,u32 hash_size,bool in_ram)112 static int resource_add_file(const char *name, u32 size,
113 			     u32 blk_start,  u32 blk_offset,
114 			     char *hash, u32 hash_size,
115 			     bool in_ram)
116 {
117 	struct resource_file *f;
118 	struct list_head *node;
119 	bool _new = true;
120 
121 	/* old one ? */
122 	list_for_each(node, &entry_head) {
123 		f = list_entry(node, struct resource_file, link);
124 		if (!strcmp(f->name, name)) {
125 			_new = false;
126 			break;
127 		}
128 	}
129 
130 	if (_new) {
131 		f = calloc(1, sizeof(*f));
132 		if (!f)
133 			return -ENOMEM;
134 
135 		list_add_tail(&f->link, &entry_head);
136 	}
137 
138 	strcpy(f->name, name);
139 	f->size       = size;
140 	f->in_ram     = in_ram;
141 	f->blk_start  = blk_start;
142 	f->blk_offset = blk_offset;
143 	f->hash_size  = hash_size;
144 	memcpy(f->hash, hash, hash_size);
145 #ifdef DEBUG
146 	resource_dump(f);
147 #endif
148 	return 0;
149 }
150 
resource_setup_list(struct blk_desc * desc,ulong blk_start,void * resc_hdr,bool in_ram)151 static int resource_setup_list(struct blk_desc *desc, ulong blk_start,
152 			       void *resc_hdr, bool in_ram)
153 {
154 	struct resource_img_hdr *hdr = resc_hdr;
155 	struct resource_entry *et;
156 	u32 i, stride;
157 	void *pos;
158 
159 	pos = (void *)hdr + hdr->c_offset * desc->blksz;
160 	stride = hdr->e_blks * desc->blksz;
161 
162 	for (i = 0; i < hdr->e_nums; i++) {
163 		et = pos + (i * stride);
164 		if (memcmp(et->tag, ENTRY_TAG, ENTRY_TAG_SIZE))
165 			continue;
166 
167 		resource_add_file(et->name, et->size,
168 				  blk_start, et->blk_offset,
169 				  et->hash, et->hash_size, in_ram);
170 	}
171 
172 	return 0;
173 }
174 
resource_setup_ram_list(struct blk_desc * desc,void * hdr)175 int resource_setup_ram_list(struct blk_desc *desc, void *hdr)
176 {
177 	if (!desc)
178 		return -ENODEV;
179 
180 	if (resource_check_header(hdr)) {
181 		printf("RESC: invalid\n");
182 		return -EINVAL;
183 	}
184 
185 	/* @blk_start: set as 'hdr' point addr, to be used in byte */
186 	return resource_setup_list(desc, (ulong)hdr, hdr, true);
187 }
188 
189 #ifdef CONFIG_ANDROID_BOOT_IMAGE
190 /*
191  * Add logo.bmp and logo_kernel.bmp from "logo" parititon
192  *
193  * Provide a "logo" partition for user to store logo.bmp and
194  * logo_kernel.bmp, so that the user can update them from
195  * kernel or user-space dynamically.
196  *
197  * "logo" partition layout, do not change order:
198  *
199  *   |----------------------| 0x00
200  *   | raw logo.bmp	    |
201  *   |----------------------| -> 512-byte aligned
202  *   | raw logo_kernel.bmp  |
203  *   |----------------------|
204  *
205  * N: the sector count of logo.bmp
206  *
207  * How to generate:
208  * 	cat logo.bmp > logo.img && truncate -s %512 logo.img && cat logo_kernel.bmp >> logo.img
209  */
resource_setup_logo_bmp(struct blk_desc * desc)210 static int resource_setup_logo_bmp(struct blk_desc *desc)
211 {
212 	struct bmp_header *header;
213 	const char *name[] = { "logo.bmp", "logo_kernel.bmp" };
214 	disk_partition_t part;
215 	u32 blk_offset = 0;
216 	u32 filesz;
217 	int ret, i;
218 
219 	if (part_get_info_by_name(desc, PART_LOGO, &part) < 0)
220 		return 0;
221 
222 	header = memalign(ARCH_DMA_MINALIGN, desc->blksz);
223 	if (!header)
224 		return -ENOMEM;
225 
226 	for (i = 0; i < ARRAY_SIZE(name); i++) {
227 		if (blk_dread(desc, part.start + blk_offset, 1, header) != 1) {
228 			ret = -EIO;
229 			break;
230 		}
231 
232 		if (header->signature[0] != 'B' || header->signature[1] != 'M') {
233 			ret = -EINVAL;
234 			break;
235 		}
236 
237 		filesz = get_unaligned_le32(&header->file_size);
238 		ret = resource_add_file(name[i], filesz, part.start, blk_offset,
239 					NULL, 0, false);
240 		if (ret)
241 			break;
242 
243 		/* move to next file */
244 		blk_offset += DIV_ROUND_UP(filesz, desc->blksz);
245 
246 		printf("LOGO: %s\n", name[i]);
247 
248 	}
249 
250 	free(header);
251 
252 	return ret;
253 }
254 
resource_setup_blk_list(struct blk_desc * desc,ulong blk_start)255 static int resource_setup_blk_list(struct blk_desc *desc, ulong blk_start)
256 {
257 	struct resource_img_hdr *hdr;
258 	int blk_cnt;
259 	int ret = 0;
260 	void *buf;
261 
262 	hdr = memalign(ARCH_DMA_MINALIGN, desc->blksz);
263 	if (!hdr)
264 		return -ENOMEM;
265 
266 	if (blk_dread(desc, blk_start, 1, hdr) != 1) {
267 		ret = -EIO;
268 		goto out;
269 	}
270 
271 	if (resource_check_header(hdr)) {
272 		printf("RESC: invalid\n");
273 		if (fdt_check_header(hdr)) {
274 			ret = -EINVAL;
275 			goto out;
276 		} else {
277 			/* this is a dtb file */
278 			printf("RESC: this is dtb\n");
279 			ret = resource_add_file(DEFAULT_DTB_FILE,
280 						fdt_totalsize(hdr),
281 						blk_start, 0, NULL, 0, false);
282 			goto out;
283 		}
284 	}
285 
286 	blk_cnt = hdr->e_blks * hdr->e_nums;
287 	hdr = realloc(hdr, (1 + blk_cnt) * desc->blksz);
288 	if (!hdr) {
289 		ret = -ENOMEM;
290 		goto out;
291 	}
292 
293 	buf = (void *)hdr + desc->blksz;
294 	if (blk_dread(desc, blk_start + hdr->c_offset, blk_cnt, buf) != blk_cnt) {
295 		ret = -EIO;
296 		goto out;
297 	}
298 
299 	resource_setup_list(desc, blk_start, hdr, false);
300 	resource_setup_logo_bmp(desc);
301 out:
302 	free(hdr);
303 
304 	return ret;
305 }
306 
resource_init(struct blk_desc * desc,disk_partition_t * part,ulong blk_offset)307 static int resource_init(struct blk_desc *desc,
308 			 disk_partition_t *part,
309 			 ulong blk_offset)
310 {
311 	printf("RESC: '%s', blk@0x%08lx\n", part->name, part->start + blk_offset);
312 
313 #ifdef CONFIG_ANDROID_AVB
314 	char hdr[512];
315 	ulong resc_buf = 0;
316 	int ret;
317 
318 	if (blk_dread(desc, part->start, 1, hdr) != 1)
319 		return -EIO;
320 
321 	/* only handle android boot/recovery.img and resource.img, ignore fit */
322 	if (!android_image_check_header((void *)hdr) ||
323 	    !resource_check_header((void *)hdr)) {
324 		ret = android_image_verify_resource((const char *)part->name, &resc_buf);
325 		if (ret) {
326 			printf("RESC: '%s', avb verify fail: %d\n", part->name, ret);
327 			return ret;
328 		}
329 
330 		/*
331 		 * unlock=0: resc_buf is valid and file was already full load in ram.
332 		 * unlock=1: resc_buf is 0.
333 		 */
334 		if (resc_buf && !resource_check_header((void *)resc_buf))
335 			return resource_setup_ram_list(desc, (void *)resc_buf);
336 	}
337 #endif
338 
339 	return resource_setup_blk_list(desc, part->start + blk_offset);
340 }
341 
resource_default(struct blk_desc * desc,disk_partition_t * out_part,ulong * out_blk_offset)342 static int resource_default(struct blk_desc *desc,
343 			    disk_partition_t *out_part,
344 			    ulong *out_blk_offset)
345 {
346 	disk_partition_t part;
347 
348 	if (part_get_info_by_name(desc, PART_RESOURCE, &part) < 0)
349 		return -ENODEV;
350 
351 	*out_part = part;
352 	*out_blk_offset = 0;
353 
354 	return 0;
355 }
356 #endif
357 
resource_scan(void)358 static int resource_scan(void)
359 {
360 	struct blk_desc *desc = rockchip_get_bootdev();
361 	__maybe_unused int ret;
362 
363 	if (!desc) {
364 		printf("RESC: No bootdev\n");
365 		return -ENODEV;
366 	}
367 
368 	if (!list_empty(&entry_head))
369 		return 0;
370 
371 #ifdef CONFIG_ROCKCHIP_FIT_IMAGE
372 	ret = fit_image_init_resource(desc);
373 	if (!ret || ret != -EAGAIN)
374 		return ret;
375 #endif
376 #ifdef CONFIG_ROCKCHIP_UIMAGE
377 	ret = uimage_init_resource(desc);
378 	if (!ret || ret != -EAGAIN)
379 		return ret;
380 #endif
381 #ifdef CONFIG_ANDROID_BOOT_IMAGE
382 	disk_partition_t part;
383 	ulong blk_offset;
384 	char hdr[512];
385 	char name[32];
386 
387 	/* partition priority: boot/recovery > resource */
388 	if (!android_image_init_resource(desc, &part, &blk_offset)) {
389 		if (blk_dread(desc, part.start + blk_offset, 1, hdr) != 1)
390 			return -EIO;
391 
392 		if (resource_check_header((void *)hdr)) {
393 			strcpy(name, (char *)part.name);
394 			if (resource_default(desc, &part, &blk_offset))
395 				return -ENOENT;
396 
397 			printf("RESC: '%s' -> '%s'\n", name, part.name);
398 		}
399 	} else {
400 		if (resource_default(desc, &part, &blk_offset))
401 			return -ENOENT;
402 	}
403 
404 	/* now, 'part' can be boot/recovery/resource */
405 	return resource_init(desc, &part, blk_offset);
406 #endif
407 	return -ENOENT;
408 }
409 
resource_get_file(const char * name)410 static struct resource_file *resource_get_file(const char *name)
411 {
412 	struct resource_file *f;
413 	struct list_head *node;
414 
415 	if (resource_scan())
416 		return NULL;
417 
418 	list_for_each(node, &entry_head) {
419 		f = list_entry(node, struct resource_file, link);
420 		if (!strcmp(f->name, name))
421 			return f;
422 	}
423 
424 	return NULL;
425 }
426 
rockchip_read_resource_file(void * buf,const char * name,int blk_offset,int len)427 int rockchip_read_resource_file(void *buf, const char *name, int blk_offset, int len)
428 {
429 	struct blk_desc *desc = rockchip_get_bootdev();
430 	struct resource_file *f;
431 	int blk_cnt;
432 	ulong pos;
433 
434 	if (!desc)
435 		return -ENODEV;
436 
437 	f = resource_get_file(name);
438 	if (!f) {
439 		printf("No resource file: %s\n", name);
440 		return -ENOENT;
441 	}
442 
443 	if (len <= 0 || len > f->size)
444 		len = f->size;
445 
446 	if (f->in_ram) {
447 		pos = f->blk_start + (f->blk_offset + blk_offset) * desc->blksz;
448 		memcpy(buf, (char *)pos, len);
449 	} else {
450 		blk_cnt = DIV_ROUND_UP(len, desc->blksz);
451 		if (blk_dread(desc,
452 			      f->blk_start + f->blk_offset + blk_offset,
453 			      blk_cnt, buf) != blk_cnt)
454 			len = -EIO;
455 	}
456 
457 	return len;
458 }
459 
460 extern struct resource_file *resource_read_hwid_dtb(void);
461 
rockchip_read_resource_dtb(void * fdt_addr,char ** hash,int * hash_size)462 int rockchip_read_resource_dtb(void *fdt_addr, char **hash, int *hash_size)
463 {
464 	struct resource_file *f = NULL;
465 	int ret;
466 
467 #ifdef CONFIG_ROCKCHIP_HWID_DTB
468 	if (resource_scan())
469 		return -ENOENT;
470 
471 	f = resource_read_hwid_dtb();
472 #endif
473 	/* If no dtb match hardware id(GPIO/ADC), use the default */
474 	if (!f)
475 		f = resource_get_file(DEFAULT_DTB_FILE);
476 
477 	if (!f)
478 		return -ENODEV;
479 
480 	ret = rockchip_read_resource_file(fdt_addr, f->name, 0, 0);
481 	if (ret < 0)
482 		return ret;
483 
484 	if (fdt_check_header(fdt_addr))
485 		return -EBADF;
486 
487 	*hash = f->hash;
488 	*hash_size = f->hash_size;
489 
490 	printf("DTB: %s\n", f->name);
491 
492 	return 0;
493 }
494 
do_dump_resource(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])495 static int do_dump_resource(cmd_tbl_t *cmdtp, int flag,
496 			    int argc, char *const argv[])
497 {
498 	struct resource_file *f;
499 	struct list_head *node;
500 
501 	list_for_each(node, &entry_head) {
502 		f = list_entry(node, struct resource_file, link);
503 		resource_dump(f);
504 	}
505 
506 	return 0;
507 }
508 
509 U_BOOT_CMD(
510 	dump_resource, 1, 1, do_dump_resource,
511 	"dump resource files",
512 	""
513 );
514 
515