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