xref: /aosp_15_r20/external/coreboot/util/cbfstool/cbfstool.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* cbfstool, CLI utility for CBFS file manipulation */
2 /* SPDX-License-Identifier: GPL-2.0-only */
3 
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <strings.h>
8 #include <ctype.h>
9 #include <unistd.h>
10 #include <getopt.h>
11 #include "common.h"
12 #include "cbfs.h"
13 #include "cbfs_image.h"
14 #include "cbfs_sections.h"
15 #include "elfparsing.h"
16 #include "partitioned_file.h"
17 #include "lz4/lib/xxhash.h"
18 #include <commonlib/bsd/cbfs_private.h>
19 #include <commonlib/bsd/compression.h>
20 #include <commonlib/bsd/metadata_hash.h>
21 #include <commonlib/fsp.h>
22 #include <commonlib/endian.h>
23 #include <commonlib/helpers.h>
24 #include <commonlib/region.h>
25 #include <vboot_host.h>
26 
27 struct command {
28 	const char *name;
29 	const char *optstring;
30 	int (*function) (void);
31 	// Whether to populate param.image_region before invoking function
32 	bool accesses_region;
33 	// This set to true means two things:
34 	// - in case of a command operating on a region, the region's contents
35 	//   will be written back to image_file at the end
36 	// - write access to the file is required
37 	bool modifies_region;
38 };
39 
40 static struct param {
41 	partitioned_file_t *image_file;
42 	struct buffer *image_region;
43 	const char *name;
44 	const char *filename;
45 	const char *fmap;
46 	const char *region_name;
47 	const char *source_region;
48 	const char *bootblock;
49 	const char *ignore_sections;
50 	const char *ucode_region;
51 	uint64_t u64val;
52 	uint32_t type;
53 	uint32_t baseaddress;
54 	/*
55 	 * Input can be negative. It will be transformed to offset from start of region (if
56 	 * negative) and stored in baseaddress.
57 	 */
58 	long long int baseaddress_input;
59 	uint32_t baseaddress_assigned;
60 	uint64_t loadaddress;
61 	uint32_t headeroffset;
62 	/*
63 	 * Input can be negative. It will be transformed to offset from start of region (if
64 	 * negative) and stored in baseaddress.
65 	 */
66 	long long int headeroffset_input;
67 	uint32_t headeroffset_assigned;
68 	uint64_t entrypoint;
69 	uint32_t size;
70 	uint32_t alignment;
71 	uint32_t pagesize;
72 	uint32_t cbfsoffset;
73 	/*
74 	 * Input can be negative. It will be transformed to corresponding region offset (if
75 	 * negative) and stored in baseaddress.
76 	 */
77 	long long int cbfsoffset_input;
78 	uint32_t cbfsoffset_assigned;
79 	uint32_t arch;
80 	uint32_t padding;
81 	uint32_t topswap_size;
82 	bool u64val_assigned;
83 	bool fill_partial_upward;
84 	bool fill_partial_downward;
85 	bool show_immutable;
86 	bool stage_xip;
87 	bool force_pow2_pagesize;
88 	bool autogen_attr;
89 	bool machine_parseable;
90 	bool unprocessed;
91 	bool ibb;
92 	enum cbfs_compression compression;
93 	int precompression;
94 	enum vb2_hash_algorithm hash;
95 	/* For linux payloads */
96 	char *initrd;
97 	char *cmdline;
98 	int force;
99 	/*
100 	 * Base and size of extended window for decoding SPI flash greater than 16MiB in host
101 	 * address space on x86 platforms. The assumptions here are:
102 	 * 1. Top 16MiB is still decoded in the fixed decode window just below 4G boundary.
103 	 * 2. Rest of the SPI flash below the top 16MiB is mapped at the top of extended
104 	 * window. Even though the platform might support a larger extended window, the SPI
105 	 * flash part used by the mainboard might not be large enough to be mapped in the entire
106 	 * window. In such cases, the mapping is assumed to be in the top part of the extended
107 	 * window with the bottom part remaining unused.
108 	 */
109 	uint32_t ext_win_base;
110 	uint32_t ext_win_size;
111 } param = {
112 	/* All variables not listed are initialized as zero. */
113 	.arch = CBFS_ARCHITECTURE_UNKNOWN,
114 	.compression = CBFS_COMPRESS_NONE,
115 	.hash = VB2_HASH_INVALID,
116 	.headeroffset = HEADER_OFFSET_UNKNOWN,
117 	.region_name = SECTION_NAME_PRIMARY_CBFS,
118 	.u64val = -1,
119 };
120 
121 /*
122  * This "metadata_hash cache" caches the value and location of the CBFS metadata
123  * hash embedded in the bootblock when CBFS verification is enabled. The first
124  * call to get_mh_cache() searches for the cache by scanning the whole bootblock
125  * for its 8-byte signature, later calls will just return the previously found
126  * information again. If the cbfs_hash.algo member in the result is
127  * VB2_HASH_INVALID, that means no metadata hash was found and this image does
128  * not use CBFS verification.
129  */
130 struct mh_cache {
131 	const char *region;
132 	size_t offset;
133 	struct vb2_hash cbfs_hash;
134 	platform_fixup_func fixup;
135 	bool initialized;
136 };
137 
get_mh_cache(void)138 static struct mh_cache *get_mh_cache(void)
139 {
140 	static struct mh_cache mhc;
141 
142 	if (mhc.initialized)
143 		return &mhc;
144 
145 	mhc.initialized = true;
146 
147 	const struct fmap *fmap = partitioned_file_get_fmap(param.image_file);
148 	if (!fmap)
149 		goto no_metadata_hash;
150 
151 	/* Find the metadata_hash container. If there is a "BOOTBLOCK" FMAP section, it's
152 	   there. If not, it's a normal file in the primary CBFS section. */
153 	size_t offset, size;
154 	struct buffer buffer;
155 	if (fmap_find_area(fmap, SECTION_NAME_BOOTBLOCK)) {
156 		if (!partitioned_file_read_region(&buffer, param.image_file,
157 						  SECTION_NAME_BOOTBLOCK))
158 			goto no_metadata_hash;
159 		mhc.region = SECTION_NAME_BOOTBLOCK;
160 		offset = 0;
161 		size = buffer.size;
162 	} else {
163 		struct cbfs_image cbfs;
164 		struct cbfs_file *mh_container;
165 		if (!partitioned_file_read_region(&buffer, param.image_file,
166 						  SECTION_NAME_PRIMARY_CBFS))
167 			goto no_metadata_hash;
168 		mhc.region = SECTION_NAME_PRIMARY_CBFS;
169 		if (cbfs_image_from_buffer(&cbfs, &buffer, param.headeroffset))
170 			goto no_metadata_hash;
171 		mh_container = cbfs_get_entry(&cbfs, "bootblock");
172 		if (!mh_container || be32toh(mh_container->type) != CBFS_TYPE_BOOTBLOCK) {
173 			/* Check for apu/amdfw file */
174 			mh_container = cbfs_get_entry(&cbfs, "apu/amdfw");
175 			if (!mh_container || be32toh(mh_container->type) != CBFS_TYPE_AMDFW)
176 				goto no_metadata_hash;
177 		}
178 
179 		offset = (void *)mh_container + be32toh(mh_container->offset) -
180 			 buffer_get(&cbfs.buffer);
181 		size = be32toh(mh_container->len);
182 	}
183 
184 	/* Find and validate the metadata hash anchor inside the containing file and
185 	   record its exact byte offset from the start of the FMAP region. */
186 	struct metadata_hash_anchor *anchor = memmem(buffer_get(&buffer) + offset,
187 			size, METADATA_HASH_ANCHOR_MAGIC, sizeof(anchor->magic));
188 	if (anchor) {
189 		if (!vb2_digest_size(anchor->cbfs_hash.algo)) {
190 			ERROR("Unknown CBFS metadata hash type: %d\n",
191 			      anchor->cbfs_hash.algo);
192 			goto no_metadata_hash;
193 		}
194 		mhc.cbfs_hash = anchor->cbfs_hash;
195 		mhc.offset = (void *)anchor - buffer_get(&buffer);
196 		mhc.fixup = platform_fixups_probe(&buffer, mhc.offset,
197 						  mhc.region);
198 		return &mhc;
199 	}
200 
201 no_metadata_hash:
202 	mhc.cbfs_hash.algo = VB2_HASH_INVALID;
203 	return &mhc;
204 }
205 
update_and_info(const char * name,void * dst,void * src,size_t size)206 static void update_and_info(const char *name, void *dst, void *src, size_t size)
207 {
208 	if (!memcmp(dst, src, size))
209 		return;
210 	char *src_str = bintohex(src, size);
211 	char *dst_str = bintohex(dst, size);
212 	INFO("Updating %s from %s to %s\n", name, dst_str, src_str);
213 	memcpy(dst, src, size);
214 	free(src_str);
215 	free(dst_str);
216 }
217 
update_anchor(struct mh_cache * mhc,uint8_t * fmap_hash)218 static int update_anchor(struct mh_cache *mhc, uint8_t *fmap_hash)
219 {
220 	struct buffer buffer;
221 	if (!partitioned_file_read_region(&buffer, param.image_file,
222 					  mhc->region))
223 		return -1;
224 	struct metadata_hash_anchor *anchor = buffer_get(&buffer) + mhc->offset;
225 	/* The metadata hash anchor should always still be where we left it. */
226 	assert(!memcmp(anchor->magic, METADATA_HASH_ANCHOR_MAGIC,
227 		      sizeof(anchor->magic)) &&
228 	       anchor->cbfs_hash.algo == mhc->cbfs_hash.algo);
229 	update_and_info("CBFS metadata hash", anchor->cbfs_hash.raw,
230 		mhc->cbfs_hash.raw, vb2_digest_size(anchor->cbfs_hash.algo));
231 	if (fmap_hash) {
232 		update_and_info("FMAP hash",
233 				metadata_hash_anchor_fmap_hash(anchor), fmap_hash,
234 				vb2_digest_size(anchor->cbfs_hash.algo));
235 	}
236 	if (mhc->fixup && mhc->fixup(&buffer, mhc->offset) != 0)
237 		return -1;
238 	if (!partitioned_file_write_region(param.image_file, &buffer))
239 		return -1;
240 	return 0;
241 
242 }
243 
244 /* This should be called after every time CBFS metadata might have changed. It
245    will recalculate and update the metadata hash in the bootblock if needed. */
maybe_update_metadata_hash(struct cbfs_image * cbfs)246 static int maybe_update_metadata_hash(struct cbfs_image *cbfs)
247 {
248 	if (strcmp(param.region_name, SECTION_NAME_PRIMARY_CBFS))
249 		return 0;  /* Metadata hash only embedded in primary CBFS. */
250 
251 	struct mh_cache *mhc = get_mh_cache();
252 	if (mhc->cbfs_hash.algo == VB2_HASH_INVALID)
253 		return 0;
254 
255 	enum cb_err err = cbfs_walk(cbfs, NULL, NULL, &mhc->cbfs_hash,
256 				    CBFS_WALK_WRITEBACK_HASH);
257 	if (err != CB_CBFS_NOT_FOUND) {
258 		ERROR("Unexpected cbfs_walk() error %d\n", err);
259 		return -1;
260 	}
261 
262 	return update_anchor(mhc, NULL);
263 }
264 
265 /* This should be called after every time the FMAP or the bootblock itself might
266    have changed, and will write the new FMAP hash into the metadata hash anchor
267    in the bootblock if required (usually when the bootblock is first added). */
maybe_update_fmap_hash(void)268 static int maybe_update_fmap_hash(void)
269 {
270 	if (strcmp(param.region_name, SECTION_NAME_BOOTBLOCK) &&
271 	    strcmp(param.region_name, SECTION_NAME_FMAP) &&
272 	    param.type != CBFS_TYPE_BOOTBLOCK &&
273 	    param.type != CBFS_TYPE_AMDFW)
274 		return 0;	/* FMAP and bootblock didn't change. */
275 
276 	struct mh_cache *mhc = get_mh_cache();
277 	if (mhc->cbfs_hash.algo == VB2_HASH_INVALID)
278 		return 0;
279 
280 	struct vb2_hash fmap_hash;
281 	const struct fmap *fmap = partitioned_file_get_fmap(param.image_file);
282 	if (!fmap || vb2_hash_calculate(false, fmap, fmap_size(fmap),
283 					mhc->cbfs_hash.algo, &fmap_hash))
284 		return -1;
285 	return update_anchor(mhc, fmap_hash.raw);
286 }
287 
verification_exclude(enum cbfs_type type)288 static bool verification_exclude(enum cbfs_type type)
289 {
290 	switch (type) {
291 	case CBFS_TYPE_BOOTBLOCK:
292 	case CBFS_TYPE_CBFSHEADER:
293 	case CBFS_TYPE_INTEL_FIT:
294 	case CBFS_TYPE_AMDFW:
295 		return true;
296 	default:
297 		return false;
298 	}
299 }
300 
region_is_flashmap(const char * region)301 static bool region_is_flashmap(const char *region)
302 {
303 	return partitioned_file_region_check_magic(param.image_file, region,
304 					FMAP_SIGNATURE, strlen(FMAP_SIGNATURE));
305 }
306 
307 /* @return Same as cbfs_is_valid_cbfs(), but for a named region. */
region_is_modern_cbfs(const char * region)308 static bool region_is_modern_cbfs(const char *region)
309 {
310 	return partitioned_file_region_check_magic(param.image_file, region,
311 				CBFS_FILE_MAGIC, strlen(CBFS_FILE_MAGIC));
312 }
313 
314 /* This describes a window from the SPI flash address space into the host address space. */
315 struct mmap_window {
316 	struct region flash_space;
317 	struct region host_space;
318 };
319 
320 /* Should be enough for now */
321 #define MMAP_MAX_WINDOWS 3
322 
323 /* Table of all the decode windows supported by the platform. */
324 static int mmap_window_table_size;
325 static struct mmap_window mmap_window_table[MMAP_MAX_WINDOWS];
326 
add_mmap_window(size_t flash_offset,size_t host_offset,size_t window_size)327 static void add_mmap_window(size_t flash_offset, size_t host_offset,
328 			    size_t window_size)
329 {
330 	if (mmap_window_table_size >= MMAP_MAX_WINDOWS) {
331 		ERROR("Too many memory map windows\n");
332 		return;
333 	}
334 
335 	mmap_window_table[mmap_window_table_size].flash_space.offset = flash_offset;
336 	mmap_window_table[mmap_window_table_size].host_space.offset = host_offset;
337 	mmap_window_table[mmap_window_table_size].flash_space.size = window_size;
338 	mmap_window_table[mmap_window_table_size].host_space.size = window_size;
339 	mmap_window_table_size++;
340 }
341 
342 
decode_mmap_arg(char * arg)343 static int decode_mmap_arg(char *arg)
344 {
345 	if (arg == NULL)
346 		return 1;
347 
348 	union {
349 		unsigned long int array[3];
350 		struct {
351 			unsigned long int flash_base;
352 			unsigned long int mmap_base;
353 			unsigned long int mmap_size;
354 		};
355 	} mmap_args;
356 	char *suffix = NULL;
357 	char *substring = strtok(arg, ":");
358 	for (size_t i = 0; i < ARRAY_SIZE(mmap_args.array); i++) {
359 		if (!substring) {
360 			ERROR("Invalid mmap arguments '%s'.\n",
361 			      arg);
362 			return 1;
363 		}
364 		mmap_args.array[i] = strtol(substring, &suffix, 0);
365 		if (suffix && *suffix) {
366 			ERROR("Invalid mmap arguments '%s'.\n",
367 			      arg);
368 			return 1;
369 		}
370 		substring = strtok(NULL, ":");
371 	}
372 
373 	if (substring != NULL) {
374 		ERROR("Invalid argument, too many substrings '%s'.\n",
375 		      arg);
376 
377 		return 1;
378 	}
379 
380 	add_mmap_window(mmap_args.flash_base, mmap_args.mmap_base, mmap_args.mmap_size);
381 	return 0;
382 }
383 
384 #define DEFAULT_DECODE_WINDOW_TOP	(4ULL * GiB)
385 #define DEFAULT_DECODE_WINDOW_MAX_SIZE	(16 * MiB)
386 
create_mmap_windows(void)387 static bool create_mmap_windows(void)
388 {
389 	static bool done;
390 
391 	if (done)
392 		return done;
393 
394 	// No memory map provided, use a default one
395 	if (mmap_window_table_size == 0) {
396 		const size_t image_size = partitioned_file_total_size(param.image_file);
397 		printf("Image SIZE %zu\n", image_size);
398 		const size_t std_window_size = MIN(DEFAULT_DECODE_WINDOW_MAX_SIZE, image_size);
399 		const size_t std_window_flash_offset = image_size - std_window_size;
400 
401 		/*
402 		 * Default decode window lives just below 4G boundary in host space and maps up to a
403 		 * maximum of 16MiB. If the window is smaller than 16MiB, the SPI flash window is mapped
404 		 * at the top of the host window just below 4G.
405 		 */
406 		add_mmap_window(std_window_flash_offset, DEFAULT_DECODE_WINDOW_TOP - std_window_size, std_window_size);
407 	} else {
408 		/*
409 		 * Check provided memory map
410 		 */
411 		for (int i = 0; i < mmap_window_table_size; i++) {
412 			for (int j = i + 1; j < mmap_window_table_size; j++) {
413 				if (region_overlap(&mmap_window_table[i].flash_space,
414 						   &mmap_window_table[j].flash_space)) {
415 					ERROR("Flash space windows (base=0x%zx, limit=0x%zx) and (base=0x%zx, limit=0x%zx) overlap!\n",
416 					      region_offset(&mmap_window_table[i].flash_space),
417 					      region_end(&mmap_window_table[i].flash_space),
418 					      region_offset(&mmap_window_table[j].flash_space),
419 					      region_end(&mmap_window_table[j].flash_space));
420 					return false;
421 				}
422 
423 				if (region_overlap(&mmap_window_table[i].host_space,
424 						   &mmap_window_table[j].host_space)) {
425 					ERROR("Host space windows (base=0x%zx, limit=0x%zx) and (base=0x%zx, limit=0x%zx) overlap!\n",
426 					      region_offset(&mmap_window_table[i].flash_space),
427 					      region_end(&mmap_window_table[i].flash_space),
428 					      region_offset(&mmap_window_table[j].flash_space),
429 					      region_end(&mmap_window_table[j].flash_space));
430 					return false;
431 				}
432 			}
433 		}
434 	}
435 
436 	done = true;
437 	return done;
438 }
439 
convert_address(const struct region * to,const struct region * from,unsigned int addr)440 static unsigned int convert_address(const struct region *to, const struct region *from,
441 				    unsigned int addr)
442 {
443 	/*
444 	 * Calculate the offset in the "from" region and use that offset to calculate
445 	 * corresponding address in the "to" region.
446 	 */
447 	size_t offset = addr - region_offset(from);
448 	return region_offset(to) + offset;
449 }
450 
451 enum mmap_addr_type {
452 	HOST_SPACE_ADDR,
453 	FLASH_SPACE_ADDR,
454 };
455 
find_mmap_window(enum mmap_addr_type addr_type,unsigned int addr)456 static int find_mmap_window(enum mmap_addr_type addr_type, unsigned int addr)
457 {
458 	size_t i;
459 
460 	for (i = 0; i < ARRAY_SIZE(mmap_window_table); i++) {
461 		const struct region *reg;
462 
463 		if (addr_type == HOST_SPACE_ADDR)
464 			reg = &mmap_window_table[i].host_space;
465 		else
466 			reg = &mmap_window_table[i].flash_space;
467 
468 		if (region_offset(reg) <= addr &&
469 		   ((uint64_t)region_offset(reg) + (uint64_t)region_sz(reg) - 1) >= addr)
470 			return i;
471 	}
472 
473 	return -1;
474 }
475 
convert_host_to_flash(const struct buffer * region,unsigned int addr)476 static unsigned int convert_host_to_flash(const struct buffer *region, unsigned int addr)
477 {
478 	int idx;
479 	const struct region *to, *from;
480 
481 	idx = find_mmap_window(HOST_SPACE_ADDR, addr);
482 	if (idx == -1) {
483 		ERROR("Host address(%x) not in any mmap window!\n", addr);
484 		return 0;
485 	}
486 
487 	to = &mmap_window_table[idx].flash_space;
488 	from = &mmap_window_table[idx].host_space;
489 
490 	/* region->offset is subtracted because caller expects offset in the given region. */
491 	return convert_address(to, from, addr) - region->offset;
492 }
493 
convert_flash_to_host(const struct buffer * region,unsigned int addr)494 static unsigned int convert_flash_to_host(const struct buffer *region, unsigned int addr)
495 {
496 	int idx;
497 	const struct region *to, *from;
498 
499 	/*
500 	 * region->offset is added because caller provides offset in the given region. This is
501 	 * converted to an absolute address in the SPI flash space. This is done before the
502 	 * conversion as opposed to after in convert_host_to_flash() above because the address
503 	 * is actually an offset within the region. So, it needs to be converted into an
504 	 * absolute address in the SPI flash space before converting into an address in host
505 	 * space.
506 	 */
507 	addr += region->offset;
508 	idx = find_mmap_window(FLASH_SPACE_ADDR, addr);
509 
510 	if (idx == -1) {
511 		ERROR("SPI flash address(%x) not in any mmap window!\n", addr);
512 		return 0;
513 	}
514 
515 	to = &mmap_window_table[idx].host_space;
516 	from = &mmap_window_table[idx].flash_space;
517 
518 	return convert_address(to, from, addr);
519 }
520 
convert_addr_space(const struct buffer * region,unsigned int addr)521 static unsigned int convert_addr_space(const struct buffer *region, unsigned int addr)
522 {
523 	assert(region);
524 
525 	assert(create_mmap_windows());
526 
527 	if (IS_HOST_SPACE_ADDRESS(addr))
528 		return convert_host_to_flash(region, addr);
529 	else
530 		return convert_flash_to_host(region, addr);
531 }
532 
533 /*
534  * This function takes offset value which represents the offset from one end of the region and
535  * converts it to offset from the other end of the region. offset is expected to be positive.
536  */
convert_region_offset(unsigned int offset,uint32_t * region_offset)537 static int convert_region_offset(unsigned int offset, uint32_t *region_offset)
538 {
539 	size_t size;
540 
541 	if (param.size) {
542 		size = param.size;
543 	} else {
544 		assert(param.image_region);
545 		size = param.image_region->size;
546 	}
547 
548 	if (size < offset) {
549 		ERROR("Cannot convert region offset (size=0x%zx, offset=0x%x)\n", size, offset);
550 		return 1;
551 	}
552 
553 	*region_offset = size - offset;
554 	return 0;
555 }
556 
do_cbfs_locate(uint32_t * cbfs_addr,size_t data_size)557 static int do_cbfs_locate(uint32_t *cbfs_addr, size_t data_size)
558 {
559 	uint32_t metadata_size = 0;
560 
561 	if (!param.name) {
562 		ERROR("You need to specify -n/--name.\n");
563 		return 1;
564 	}
565 
566 	struct cbfs_image image;
567 	if (cbfs_image_from_buffer(&image, param.image_region,
568 							param.headeroffset))
569 		return 1;
570 
571 	if (cbfs_get_entry(&image, param.name))
572 		WARN("'%s' already in CBFS.\n", param.name);
573 
574 	if (!data_size) {
575 		ERROR("File '%s' is empty?\n", param.name);
576 		return 1;
577 	}
578 
579 	/* Compute required page size */
580 	if (param.force_pow2_pagesize) {
581 		param.pagesize = 1;
582 		while (param.pagesize < data_size)
583 			param.pagesize <<= 1;
584 		DEBUG("Page size is %d (0x%x)\n", param.pagesize, param.pagesize);
585 	}
586 
587 	/* Include cbfs_file size along with space for with name. */
588 	metadata_size += cbfs_calculate_file_header_size(param.name);
589 	/* Adjust metadata_size if additional attributes were added */
590 	if (param.autogen_attr) {
591 		if (param.alignment)
592 			metadata_size += sizeof(struct cbfs_file_attr_align);
593 		if (param.baseaddress_assigned || param.stage_xip)
594 			metadata_size += sizeof(struct cbfs_file_attr_position);
595 	}
596 	if (param.precompression || param.compression != CBFS_COMPRESS_NONE)
597 		metadata_size += sizeof(struct cbfs_file_attr_compression);
598 	if (param.type == CBFS_TYPE_STAGE)
599 		metadata_size += sizeof(struct cbfs_file_attr_stageheader);
600 
601 	/* Take care of the hash attribute if it is used */
602 	if (param.hash != VB2_HASH_INVALID)
603 		metadata_size += cbfs_file_attr_hash_size(param.hash);
604 
605 	int32_t address = cbfs_locate_entry(&image, data_size, param.pagesize,
606 						param.alignment, metadata_size);
607 
608 	if (address < 0) {
609 		ERROR("'%s'(%u + %zu) can't fit in CBFS for page-size %#x, align %#x.\n",
610 		      param.name, metadata_size, data_size, param.pagesize, param.alignment);
611 		return 1;
612 	}
613 
614 	*cbfs_addr = address;
615 	return 0;
616 }
617 
618 typedef int (*convert_buffer_t)(struct buffer *buffer, uint32_t *offset,
619 	struct cbfs_file *header);
620 
cbfs_add_integer_component(const char * name,uint64_t u64val,uint32_t offset,uint32_t headeroffset)621 static int cbfs_add_integer_component(const char *name,
622 			      uint64_t u64val,
623 			      uint32_t offset,
624 			      uint32_t headeroffset) {
625 	struct cbfs_image image;
626 	struct cbfs_file *header = NULL;
627 	struct buffer buffer;
628 	int i, ret = 1;
629 
630 	if (!name) {
631 		ERROR("You need to specify -n/--name.\n");
632 		return 1;
633 	}
634 
635 	if (buffer_create(&buffer, 8, name) != 0)
636 		return 1;
637 
638 	for (i = 0; i < 8; i++)
639 		buffer.data[i] = (u64val >> i*8) & 0xff;
640 
641 	if (cbfs_image_from_buffer(&image, param.image_region, headeroffset)) {
642 		ERROR("Selected image region is not a CBFS.\n");
643 		goto done;
644 	}
645 
646 	if (cbfs_get_entry(&image, name)) {
647 		ERROR("'%s' already in ROM image.\n", name);
648 		goto done;
649 	}
650 
651 	header = cbfs_create_file_header(CBFS_TYPE_RAW,
652 		buffer.size, name);
653 	if (!header)
654 		goto done;
655 
656 	enum vb2_hash_algorithm algo = get_mh_cache()->cbfs_hash.algo;
657 	if (algo != VB2_HASH_INVALID)
658 		if (cbfs_add_file_hash(header, &buffer, algo)) {
659 			ERROR("couldn't add hash for '%s'\n", name);
660 			goto done;
661 		}
662 
663 	if (cbfs_add_entry(&image, &buffer, offset, header, 0) != 0) {
664 		ERROR("Failed to add %llu into ROM image as '%s'.\n",
665 					(long long unsigned)u64val, name);
666 		goto done;
667 	}
668 
669 	ret = maybe_update_metadata_hash(&image);
670 
671 done:
672 	free(header);
673 	buffer_delete(&buffer);
674 	return ret;
675 }
676 
is_valid_topswap(void)677 static int is_valid_topswap(void)
678 {
679 	switch (param.topswap_size) {
680 	case (64 * KiB):
681 	case (128 * KiB):
682 	case (256 * KiB):
683 	case (512 * KiB):
684 	case (1 * MiB):
685 		break;
686 	default:
687 		ERROR("Invalid topswap_size %d, topswap can be 64K|128K|256K|512K|1M\n",
688 							param.topswap_size);
689 		return 0;
690 	}
691 	return 1;
692 }
693 
fill_header_offset(void * location,uint32_t offset)694 static void fill_header_offset(void *location, uint32_t offset)
695 {
696 	// TODO: When we have a BE target, we'll need to store this as BE
697 	write_le32(location, offset);
698 }
699 
update_master_header_loc_topswap(struct cbfs_image * image,void * h_loc,uint32_t header_offset)700 static int update_master_header_loc_topswap(struct cbfs_image *image,
701 				void *h_loc, uint32_t header_offset)
702 {
703 	struct cbfs_file *entry;
704 	void *ts_h_loc = h_loc;
705 
706 	entry = cbfs_get_entry(image, "bootblock");
707 	if (entry == NULL) {
708 		ERROR("Bootblock not in ROM image?!?\n");
709 		return 1;
710 	}
711 
712 	/*
713 	 * Check if the existing topswap boundary matches with
714 	 * the one provided.
715 	 */
716 	if (param.topswap_size != be32toh(entry->len)/2) {
717 		ERROR("Top swap boundary does not match\n");
718 		return 1;
719 	}
720 
721 	ts_h_loc -= param.topswap_size;
722 	fill_header_offset(ts_h_loc, header_offset);
723 
724 	return 0;
725 }
726 
cbfs_add_master_header(void)727 static int cbfs_add_master_header(void)
728 {
729 	const char * const name = "cbfs master header";
730 	struct cbfs_image image;
731 	struct cbfs_file *header = NULL;
732 	struct buffer buffer;
733 	int ret = 1;
734 	size_t offset;
735 	size_t size;
736 	void *h_loc;
737 
738 	if (cbfs_image_from_buffer(&image, param.image_region,
739 		param.headeroffset)) {
740 		ERROR("Selected image region is not a CBFS.\n");
741 		return 1;
742 	}
743 
744 	if (cbfs_get_entry(&image, name)) {
745 		ERROR("'%s' already in ROM image.\n", name);
746 		return 1;
747 	}
748 
749 	if (buffer_create(&buffer, sizeof(struct cbfs_header), name) != 0)
750 		return 1;
751 
752 	struct cbfs_header *h = (struct cbfs_header *)buffer.data;
753 	h->magic = htobe32(CBFS_HEADER_MAGIC);
754 	h->version = htobe32(CBFS_HEADER_VERSION);
755 	/* The 4 bytes are left out for two reasons:
756 	 * 1. the cbfs master header pointer resides there
757 	 * 2. some cbfs implementations assume that an image that resides
758 	 *    below 4GB has a bootblock and get confused when the end of the
759 	 *    image is at 4GB == 0.
760 	 */
761 	h->bootblocksize = htobe32(4);
762 	h->align = htobe32(CBFS_ALIGNMENT);
763 	/* The offset and romsize fields within the master header are absolute
764 	 * values within the boot media. As such, romsize needs to relfect
765 	 * the end 'offset' for a CBFS. To achieve that the current buffer
766 	 * representing the CBFS region's size is added to the offset of
767 	 * the region within a larger image.
768 	 */
769 	offset = buffer_get(param.image_region) -
770 		buffer_get_original_backing(param.image_region);
771 	size = buffer_size(param.image_region);
772 	h->romsize = htobe32(size + offset);
773 	h->offset = htobe32(offset);
774 	h->architecture = htobe32(CBFS_ARCHITECTURE_UNKNOWN);
775 
776 	/* Never add a hash attribute to the master header. */
777 	header = cbfs_create_file_header(CBFS_TYPE_CBFSHEADER,
778 		buffer_size(&buffer), name);
779 	if (!header)
780 		goto done;
781 	if (cbfs_add_entry(&image, &buffer, 0, header, 0) != 0) {
782 		ERROR("Failed to add cbfs master header into ROM image.\n");
783 		goto done;
784 	}
785 
786 	struct cbfs_file *entry;
787 	if ((entry = cbfs_get_entry(&image, name)) == NULL) {
788 		ERROR("'%s' not in ROM image?!?\n", name);
789 		goto done;
790 	}
791 
792 	uint32_t header_offset = CBFS_SUBHEADER(entry) -
793 		buffer_get(&image.buffer);
794 	header_offset = -(buffer_size(&image.buffer) - header_offset);
795 
796 	h_loc = (void *)(buffer_get(&image.buffer) +
797 				buffer_size(&image.buffer) - 4);
798 	fill_header_offset(h_loc, header_offset);
799 	/*
800 	 * If top swap present, update the header
801 	 * location in secondary bootblock
802 	 */
803 	if (param.topswap_size) {
804 		if (update_master_header_loc_topswap(&image, h_loc,
805 						     header_offset))
806 			goto done;
807 	}
808 
809 	ret = maybe_update_metadata_hash(&image);
810 
811 done:
812 	free(header);
813 	buffer_delete(&buffer);
814 	return ret;
815 }
816 
add_topswap_bootblock(struct buffer * buffer,uint32_t * offset)817 static int add_topswap_bootblock(struct buffer *buffer, uint32_t *offset)
818 {
819 	size_t bb_buf_size = buffer_size(buffer);
820 
821 	if (bb_buf_size > param.topswap_size) {
822 		ERROR("Bootblock bigger than the topswap boundary\n");
823 		ERROR("size = %zd, ts = %d\n", bb_buf_size,
824 							param.topswap_size);
825 		return 1;
826 	}
827 
828 	/*
829 	 * Allocate topswap_size*2 bytes for bootblock to
830 	 * accommodate the second bootblock.
831 	 */
832 	struct buffer new_bootblock, bb1, bb2;
833 	if (buffer_create(&new_bootblock, 2 * param.topswap_size,
834 							buffer->name))
835 		return 1;
836 
837 	buffer_splice(&bb1, &new_bootblock, param.topswap_size - bb_buf_size,
838 							bb_buf_size);
839 	buffer_splice(&bb2, &new_bootblock,
840 				buffer_size(&new_bootblock) - bb_buf_size,
841 							bb_buf_size);
842 
843 	/* Copy to first bootblock */
844 	memcpy(buffer_get(&bb1), buffer_get(buffer), bb_buf_size);
845 	/* Copy to second bootblock */
846 	memcpy(buffer_get(&bb2), buffer_get(buffer), bb_buf_size);
847 
848 	buffer_delete(buffer);
849 	buffer_clone(buffer, &new_bootblock);
850 
851 	 /* Update the location (offset) of bootblock in the region */
852 	return convert_region_offset(buffer_size(buffer), offset);
853 }
854 
cbfs_add_component(const char * filename,const char * name,uint32_t headeroffset,convert_buffer_t convert)855 static int cbfs_add_component(const char *filename,
856 			      const char *name,
857 			      uint32_t headeroffset,
858 			      convert_buffer_t convert)
859 {
860 	/*
861 	 * The steps used to determine the final placement offset in CBFS, in order:
862 	 *
863 	 * 1. If --base-address was passed, that value is used. If it was passed in the host
864 	 *    address space, convert it to flash address space. (After that, |*offset| is always
865 	 *    in the flash address space.)
866 	 *
867 	 * 2. The convert() function may write a location back to |offset|, usually by calling
868 	 *    do_cbfs_locate(). In this case, it needs to ensure that the location found can fit
869 	 *    the CBFS file in its final form (after any compression and conversion).
870 	 *
871 	 * 3. If --align was passed and the offset is still undecided at this point,
872 	 *    do_cbfs_locate() is called to find an appropriately aligned location.
873 	 *
874 	 * 4. If |offset| is still 0 at the end, cbfs_add_entry() will find the first available
875 	 *    location that fits.
876 	 */
877 	uint32_t offset = param.baseaddress_assigned ? param.baseaddress : 0;
878 	size_t len_align = 0;
879 
880 	if (param.alignment && param.baseaddress_assigned) {
881 		ERROR("Cannot specify both alignment and base address\n");
882 		return 1;
883 	}
884 
885 	if (param.stage_xip && param.compression != CBFS_COMPRESS_NONE) {
886 		ERROR("Cannot specify compression for XIP.\n");
887 		return 1;
888 	}
889 
890 	if (!filename) {
891 		ERROR("You need to specify -f/--filename.\n");
892 		return 1;
893 	}
894 
895 	if (!name) {
896 		ERROR("You need to specify -n/--name.\n");
897 		return 1;
898 	}
899 
900 	if (param.type == 0) {
901 		ERROR("You need to specify a valid -t/--type.\n");
902 		return 1;
903 	}
904 
905 	struct cbfs_image image;
906 	if (cbfs_image_from_buffer(&image, param.image_region, headeroffset))
907 		return 1;
908 
909 	if (cbfs_get_entry(&image, name)) {
910 		ERROR("'%s' already in ROM image.\n", name);
911 		return 1;
912 	}
913 
914 	struct buffer buffer;
915 	if (buffer_from_file(&buffer, filename) != 0) {
916 		ERROR("Could not load file '%s'.\n", filename);
917 		return 1;
918 	}
919 
920 	struct cbfs_file *header =
921 		cbfs_create_file_header(param.type, buffer.size, name);
922 	if (!header)
923 		goto error;
924 
925 	/* Bootblock and CBFS header should never have file hashes. When adding
926 	   the bootblock it is important that we *don't* look up the metadata
927 	   hash yet (before it is added) or we'll cache an outdated result. */
928 	if (!verification_exclude(param.type)) {
929 		enum vb2_hash_algorithm mh_algo = get_mh_cache()->cbfs_hash.algo;
930 		if (mh_algo != VB2_HASH_INVALID && param.hash != mh_algo) {
931 			if (param.hash == VB2_HASH_INVALID) {
932 				param.hash = mh_algo;
933 			} else {
934 				ERROR("Cannot specify hash %s that's different from metadata hash algorithm %s\n",
935 				      vb2_get_hash_algorithm_name(param.hash),
936 				      vb2_get_hash_algorithm_name(mh_algo));
937 				goto error;
938 			}
939 		}
940 	}
941 
942 	/*
943 	 * Check if Intel CPU topswap is specified this will require a
944 	 * second bootblock to be added.
945 	 */
946 	if (param.type == CBFS_TYPE_BOOTBLOCK && param.topswap_size)
947 		if (add_topswap_bootblock(&buffer, &offset))
948 			goto error;
949 
950 	/* With --base-address we allow host space addresses -- if so, convert it here. */
951 	if (IS_HOST_SPACE_ADDRESS(offset))
952 		offset = convert_addr_space(param.image_region, offset);
953 
954 	if (convert && convert(&buffer, &offset, header) != 0) {
955 		ERROR("Failed to parse file '%s'.\n", filename);
956 		goto error;
957 	}
958 
959 	/* This needs to run after convert() to take compression into account. */
960 	if (!offset && param.alignment)
961 		if (do_cbfs_locate(&offset, buffer_size(&buffer)))
962 			goto error;
963 
964 	/* This needs to run after convert() to hash the actual final file data. */
965 	if (param.hash != VB2_HASH_INVALID &&
966 	    cbfs_add_file_hash(header, &buffer, param.hash) == -1) {
967 		ERROR("couldn't add hash for '%s'\n", name);
968 		goto error;
969 	}
970 
971 	if (param.autogen_attr) {
972 		/* Add position attribute if assigned */
973 		if (param.baseaddress_assigned || param.stage_xip) {
974 			struct cbfs_file_attr_position *attrs =
975 				(struct cbfs_file_attr_position *)
976 				cbfs_add_file_attr(header,
977 					CBFS_FILE_ATTR_TAG_POSITION,
978 					sizeof(struct cbfs_file_attr_position));
979 			if (attrs == NULL)
980 				goto error;
981 			attrs->position = htobe32(offset);
982 		}
983 		/* Add alignment attribute if used */
984 		if (param.alignment) {
985 			struct cbfs_file_attr_align *attrs =
986 				(struct cbfs_file_attr_align *)
987 				cbfs_add_file_attr(header,
988 					CBFS_FILE_ATTR_TAG_ALIGNMENT,
989 					sizeof(struct cbfs_file_attr_align));
990 			if (attrs == NULL)
991 				goto error;
992 			attrs->alignment = htobe32(param.alignment);
993 		}
994 	}
995 
996 	if (param.ibb) {
997 		/* Mark as Initial Boot Block */
998 		struct cbfs_file_attribute *attrs = cbfs_add_file_attr(header,
999 				CBFS_FILE_ATTR_TAG_IBB,
1000 				sizeof(struct cbfs_file_attribute));
1001 		if (attrs == NULL)
1002 			goto error;
1003 		/* For Intel TXT minimum align is 16 */
1004 		len_align = 16;
1005 	}
1006 
1007 	if (param.padding) {
1008 		const uint32_t hs = sizeof(struct cbfs_file_attribute);
1009 		uint32_t size = ALIGN_UP(MAX(hs, param.padding),
1010 					 CBFS_ATTRIBUTE_ALIGN);
1011 		INFO("Padding %d bytes\n", size);
1012 		struct cbfs_file_attribute *attr =
1013 			(struct cbfs_file_attribute *)cbfs_add_file_attr(
1014 					header, CBFS_FILE_ATTR_TAG_PADDING,
1015 					size);
1016 		if (attr == NULL)
1017 			goto error;
1018 	}
1019 
1020 	if (cbfs_add_entry(&image, &buffer, offset, header, len_align) != 0) {
1021 		ERROR("Failed to add '%s' into ROM image.\n", filename);
1022 		goto error;
1023 	}
1024 
1025 	free(header);
1026 	buffer_delete(&buffer);
1027 
1028 	return maybe_update_metadata_hash(&image) || maybe_update_fmap_hash();
1029 
1030 error:
1031 	free(header);
1032 	buffer_delete(&buffer);
1033 	return 1;
1034 }
1035 
cbfstool_convert_raw(struct buffer * buffer,unused uint32_t * offset,struct cbfs_file * header)1036 static int cbfstool_convert_raw(struct buffer *buffer,
1037 	unused uint32_t *offset, struct cbfs_file *header)
1038 {
1039 	char *compressed;
1040 	int decompressed_size, compressed_size;
1041 	comp_func_ptr compress;
1042 
1043 	decompressed_size = buffer->size;
1044 	if (param.precompression) {
1045 		param.compression = read_le32(buffer->data);
1046 		decompressed_size = read_le32(buffer->data + sizeof(uint32_t));
1047 		compressed_size = buffer->size - 8;
1048 		compressed = malloc(compressed_size);
1049 		if (!compressed)
1050 			return -1;
1051 		memcpy(compressed, buffer->data + 8, compressed_size);
1052 	} else {
1053 		if (param.compression == CBFS_COMPRESS_NONE)
1054 			goto out;
1055 
1056 		compress = compression_function(param.compression);
1057 		if (!compress)
1058 			return -1;
1059 		compressed = calloc(buffer->size, 1);
1060 		if (!compressed)
1061 			return -1;
1062 
1063 		if (compress(buffer->data, buffer->size,
1064 			     compressed, &compressed_size)) {
1065 			WARN("Compression failed - disabled\n");
1066 			free(compressed);
1067 			goto out;
1068 		}
1069 	}
1070 
1071 	struct cbfs_file_attr_compression *attrs =
1072 		(struct cbfs_file_attr_compression *)
1073 		cbfs_add_file_attr(header,
1074 			CBFS_FILE_ATTR_TAG_COMPRESSION,
1075 			sizeof(struct cbfs_file_attr_compression));
1076 	if (attrs == NULL) {
1077 		free(compressed);
1078 		return -1;
1079 	}
1080 	attrs->compression = htobe32(param.compression);
1081 	attrs->decompressed_size = htobe32(decompressed_size);
1082 
1083 	free(buffer->data);
1084 	buffer->data = compressed;
1085 	buffer->size = compressed_size;
1086 
1087 out:
1088 	header->len = htobe32(buffer->size);
1089 	return 0;
1090 }
1091 
cbfstool_convert_fsp(struct buffer * buffer,uint32_t * offset,struct cbfs_file * header)1092 static int cbfstool_convert_fsp(struct buffer *buffer,
1093 				uint32_t *offset, struct cbfs_file *header)
1094 {
1095 	uint32_t address;
1096 	struct buffer fsp;
1097 
1098 	/*
1099 	 * There are 4 different cases here:
1100 	 *
1101 	 * 1. --xip and --base-address: we need to place the binary at the given base address
1102 	 *    in the CBFS image and relocate it to that address. *offset was already filled in,
1103 	 *    but we need to convert it to the host address space for relocation.
1104 	 *
1105 	 * 2. --xip but no --base-address: we implicitly force a 4K minimum alignment so that
1106 	 *    relocation can occur. Call do_cbfs_locate() here to find an appropriate *offset.
1107 	 *    This also needs to be converted to the host address space for relocation.
1108 	 *
1109 	 * 3. No --xip but a --base-address: special case where --base-address does not have its
1110 	 *    normal meaning, instead we use it as the relocation target address. We explicitly
1111 	 *    reset *offset to 0 so that the file will be placed wherever it fits in CBFS.
1112 	 *
1113 	 * 4. No --xip and no --base-address: this means that the FSP was pre-linked and should
1114 	 *    not be relocated. Just chain directly to convert_raw() for compression.
1115 	 */
1116 
1117 	if (param.stage_xip) {
1118 		if (!param.baseaddress_assigned) {
1119 			param.alignment = 4*1024;
1120 			if (do_cbfs_locate(offset, buffer_size(buffer)))
1121 				return -1;
1122 		}
1123 		assert(!IS_HOST_SPACE_ADDRESS(*offset));
1124 		address = convert_addr_space(param.image_region, *offset);
1125 	} else {
1126 		if (param.baseaddress_assigned == 0) {
1127 			INFO("Honoring pre-linked FSP module, no relocation.\n");
1128 			return cbfstool_convert_raw(buffer, offset, header);
1129 		} else {
1130 			address = param.baseaddress;
1131 			*offset = 0;
1132 		}
1133 	}
1134 
1135 	/* Create a copy of the buffer to attempt relocation. */
1136 	if (buffer_create(&fsp, buffer_size(buffer), "fsp"))
1137 		return -1;
1138 
1139 	memcpy(buffer_get(&fsp), buffer_get(buffer), buffer_size(buffer));
1140 
1141 	/* Replace the buffer contents w/ the relocated ones on success. */
1142 	if (fsp_component_relocate(address, buffer_get(&fsp), buffer_size(&fsp))
1143 	    > 0) {
1144 		buffer_delete(buffer);
1145 		buffer_clone(buffer, &fsp);
1146 	} else {
1147 		buffer_delete(&fsp);
1148 		WARN("Invalid FSP variant.\n");
1149 	}
1150 
1151 	/* Let the raw path handle all the cbfs metadata logic. */
1152 	return cbfstool_convert_raw(buffer, offset, header);
1153 }
1154 
cbfstool_convert_mkstage(struct buffer * buffer,uint32_t * offset,struct cbfs_file * header)1155 static int cbfstool_convert_mkstage(struct buffer *buffer, uint32_t *offset,
1156 	struct cbfs_file *header)
1157 {
1158 	struct buffer output;
1159 	int ret;
1160 
1161 	/*
1162 	 * We need a final location for XIP parsing, so we need to call do_cbfs_locate() early
1163 	 * here. That is okay because XIP stages may not be compressed, so their size cannot
1164 	 * change anymore at a later point.
1165 	 */
1166 	if (param.stage_xip) {
1167 		size_t data_size, alignment;
1168 		if (elf_program_file_size_align(buffer, &data_size, &alignment) < 0) {
1169 			ERROR("Could not obtain ELF size & alignment\n");
1170 			return 1;
1171 		}
1172 
1173 		param.alignment = MAX(alignment, param.alignment);
1174 
1175 		if (do_cbfs_locate(offset, data_size)) {
1176 			ERROR("Could not find location for stage.\n");
1177 			return 1;
1178 		}
1179 	}
1180 
1181 	struct cbfs_file_attr_stageheader *stageheader = (void *)
1182 		cbfs_add_file_attr(header, CBFS_FILE_ATTR_TAG_STAGEHEADER,
1183 				   sizeof(struct cbfs_file_attr_stageheader));
1184 	if (!stageheader)
1185 		return -1;
1186 
1187 	if (param.stage_xip) {
1188 		uint32_t host_space_address = convert_addr_space(param.image_region, *offset);
1189 		assert(IS_HOST_SPACE_ADDRESS(host_space_address));
1190 		ret = parse_elf_to_xip_stage(buffer, &output, host_space_address,
1191 					     param.ignore_sections, stageheader);
1192 	} else {
1193 		ret = parse_elf_to_stage(buffer, &output, param.ignore_sections,
1194 					 stageheader);
1195 	}
1196 	if (ret != 0)
1197 		return -1;
1198 
1199 	/* Store a hash of original uncompressed stage to compare later. */
1200 	size_t decmp_size = buffer_size(&output);
1201 	uint32_t decmp_hash = XXH32(buffer_get(&output), decmp_size, 0);
1202 
1203 	/* Chain to base conversion routine to handle compression. */
1204 	ret = cbfstool_convert_raw(&output, offset, header);
1205 	if (ret != 0)
1206 		goto fail;
1207 
1208 	/* Special care must be taken for LZ4-compressed stages that the BSS is
1209 	   large enough to provide scratch space for in-place decompression. */
1210 	if (!param.precompression && param.compression == CBFS_COMPRESS_LZ4) {
1211 		size_t memlen = be32toh(stageheader->memlen);
1212 		size_t compressed_size = buffer_size(&output);
1213 		uint8_t *compare_buffer = malloc(memlen);
1214 		uint8_t *start = compare_buffer + memlen - compressed_size;
1215 		if (!compare_buffer) {
1216 			ERROR("Out of memory\n");
1217 			goto fail;
1218 		}
1219 		memcpy(start, buffer_get(&output), compressed_size);
1220 		ret = ulz4fn(start, compressed_size, compare_buffer, memlen);
1221 		if  (ret == 0) {
1222 			ERROR("Not enough scratch space to decompress LZ4 in-place -- increase BSS size or disable compression!\n");
1223 			free(compare_buffer);
1224 			goto fail;
1225 		} else if (ret != (int)decmp_size ||
1226 			   decmp_hash != XXH32(compare_buffer, decmp_size, 0)) {
1227 			ERROR("LZ4 compression BUG! Report to mailing list.\n");
1228 			free(compare_buffer);
1229 			goto fail;
1230 		}
1231 		free(compare_buffer);
1232 	}
1233 
1234 	buffer_delete(buffer);
1235 	buffer_clone(buffer, &output);
1236 	return 0;
1237 
1238 fail:
1239 	buffer_delete(&output);
1240 	return -1;
1241 }
1242 
cbfstool_convert_mkpayload(struct buffer * buffer,unused uint32_t * offset,struct cbfs_file * header)1243 static int cbfstool_convert_mkpayload(struct buffer *buffer,
1244 	unused uint32_t *offset, struct cbfs_file *header)
1245 {
1246 	struct buffer output;
1247 	int ret;
1248 	/* Per default, try and see if payload is an ELF binary */
1249 	ret = parse_elf_to_payload(buffer, &output, param.compression);
1250 
1251 	/* If it's not an ELF, see if it's a FIT */
1252 	if (ret != 0) {
1253 		ret = parse_fit_to_payload(buffer, &output, param.compression);
1254 		if (ret == 0)
1255 			header->type = htobe32(CBFS_TYPE_FIT_PAYLOAD);
1256 	}
1257 
1258 	/* If it's not an FIT, see if it's a UEFI FV */
1259 	if (ret != 0)
1260 		ret = parse_fv_to_payload(buffer, &output, param.compression);
1261 
1262 	/* If it's neither ELF nor UEFI Fv, try bzImage */
1263 	if (ret != 0)
1264 		ret = parse_bzImage_to_payload(buffer, &output,
1265 				param.initrd, param.cmdline, param.compression);
1266 
1267 	/* Not a supported payload type */
1268 	if (ret != 0) {
1269 		ERROR("Not a supported payload type (ELF / FV).\n");
1270 		buffer_delete(buffer);
1271 		return -1;
1272 	}
1273 
1274 	buffer_delete(buffer);
1275 	// Direct assign, no dupe.
1276 	memcpy(buffer, &output, sizeof(*buffer));
1277 	header->len = htobe32(output.size);
1278 	return 0;
1279 }
1280 
cbfstool_convert_mkflatpayload(struct buffer * buffer,unused uint32_t * offset,struct cbfs_file * header)1281 static int cbfstool_convert_mkflatpayload(struct buffer *buffer,
1282 	unused uint32_t *offset, struct cbfs_file *header)
1283 {
1284 	struct buffer output;
1285 	if (parse_flat_binary_to_payload(buffer, &output,
1286 					 param.loadaddress,
1287 					 param.entrypoint,
1288 					 param.compression) != 0) {
1289 		return -1;
1290 	}
1291 	buffer_delete(buffer);
1292 	// Direct assign, no dupe.
1293 	memcpy(buffer, &output, sizeof(*buffer));
1294 	header->len = htobe32(output.size);
1295 	return 0;
1296 }
1297 
cbfs_add(void)1298 static int cbfs_add(void)
1299 {
1300 	convert_buffer_t convert = cbfstool_convert_raw;
1301 
1302 	if (param.type == CBFS_TYPE_FSP) {
1303 		convert = cbfstool_convert_fsp;
1304 	} else if (param.type == CBFS_TYPE_STAGE) {
1305 		ERROR("stages can only be added with cbfstool add-stage\n");
1306 		return 1;
1307 	} else if (param.stage_xip) {
1308 		ERROR("cbfstool add supports xip only for FSP component type\n");
1309 		return 1;
1310 	}
1311 
1312 	return cbfs_add_component(param.filename,
1313 				  param.name,
1314 				  param.headeroffset,
1315 				  convert);
1316 }
1317 
cbfs_add_stage(void)1318 static int cbfs_add_stage(void)
1319 {
1320 	if (param.stage_xip && param.baseaddress_assigned) {
1321 		ERROR("Cannot specify base address for XIP.\n");
1322 		return 1;
1323 	}
1324 	param.type = CBFS_TYPE_STAGE;
1325 
1326 	return cbfs_add_component(param.filename,
1327 				  param.name,
1328 				  param.headeroffset,
1329 				  cbfstool_convert_mkstage);
1330 }
1331 
cbfs_add_payload(void)1332 static int cbfs_add_payload(void)
1333 {
1334 	param.type = CBFS_TYPE_SELF;
1335 	return cbfs_add_component(param.filename,
1336 				  param.name,
1337 				  param.headeroffset,
1338 				  cbfstool_convert_mkpayload);
1339 }
1340 
cbfs_add_flat_binary(void)1341 static int cbfs_add_flat_binary(void)
1342 {
1343 	if (param.loadaddress == 0) {
1344 		ERROR("You need to specify a valid "
1345 			"-l/--load-address.\n");
1346 		return 1;
1347 	}
1348 	if (param.entrypoint == 0) {
1349 		ERROR("You need to specify a valid "
1350 			"-e/--entry-point.\n");
1351 		return 1;
1352 	}
1353 	param.type = CBFS_TYPE_SELF;
1354 	return cbfs_add_component(param.filename,
1355 				  param.name,
1356 				  param.headeroffset,
1357 				  cbfstool_convert_mkflatpayload);
1358 }
1359 
cbfs_add_integer(void)1360 static int cbfs_add_integer(void)
1361 {
1362 	if (!param.u64val_assigned) {
1363 		ERROR("You need to specify a value to write.\n");
1364 		return 1;
1365 	}
1366 	return cbfs_add_integer_component(param.name,
1367 				  param.u64val,
1368 				  param.baseaddress,
1369 				  param.headeroffset);
1370 }
1371 
cbfs_remove(void)1372 static int cbfs_remove(void)
1373 {
1374 	if (!param.name) {
1375 		ERROR("You need to specify -n/--name.\n");
1376 		return 1;
1377 	}
1378 
1379 	struct cbfs_image image;
1380 	if (cbfs_image_from_buffer(&image, param.image_region,
1381 							param.headeroffset))
1382 		return 1;
1383 
1384 	if (cbfs_remove_entry(&image, param.name) != 0) {
1385 		ERROR("Removing file '%s' failed.\n",
1386 		      param.name);
1387 		return 1;
1388 	}
1389 
1390 	return maybe_update_metadata_hash(&image);
1391 }
1392 
cbfs_create(void)1393 static int cbfs_create(void)
1394 {
1395 	struct cbfs_image image;
1396 	memset(&image, 0, sizeof(image));
1397 	buffer_clone(&image.buffer, param.image_region);
1398 
1399 	if (param.fmap) {
1400 		if (param.arch != CBFS_ARCHITECTURE_UNKNOWN || param.size ||
1401 						param.baseaddress_assigned ||
1402 						param.headeroffset_assigned ||
1403 						param.cbfsoffset_assigned ||
1404 							param.bootblock) {
1405 			ERROR("Since -M was provided, -m, -s, -b, -o, -H, and -B should be omitted\n");
1406 			return 1;
1407 		}
1408 
1409 		return cbfs_image_create(&image, image.buffer.size);
1410 	}
1411 
1412 	if (param.arch == CBFS_ARCHITECTURE_UNKNOWN) {
1413 		ERROR("You need to specify -m/--machine arch.\n");
1414 		return 1;
1415 	}
1416 
1417 	struct buffer bootblock;
1418 	if (!param.bootblock) {
1419 		DEBUG("-B not given, creating image without bootblock.\n");
1420 		if (buffer_create(&bootblock, 0, "(dummy)") != 0)
1421 			return 1;
1422 	} else if (buffer_from_file(&bootblock, param.bootblock)) {
1423 		return 1;
1424 	}
1425 
1426 	if (!param.alignment)
1427 		param.alignment = CBFS_ALIGNMENT;
1428 
1429 	// Set default offsets. x86, as usual, needs to be a special snowflake.
1430 	if (!param.baseaddress_assigned) {
1431 		if (param.arch == CBFS_ARCHITECTURE_X86) {
1432 			// Make sure there's at least enough room for rel_offset
1433 			param.baseaddress = param.size -
1434 					MAX(bootblock.size, sizeof(int32_t));
1435 			DEBUG("x86 -> bootblock lies at end of ROM (%#x).\n",
1436 			      param.baseaddress);
1437 		} else {
1438 			param.baseaddress = 0;
1439 			DEBUG("bootblock starts at address 0x0.\n");
1440 		}
1441 	}
1442 	if (!param.headeroffset_assigned) {
1443 		if (param.arch == CBFS_ARCHITECTURE_X86) {
1444 			param.headeroffset = param.baseaddress -
1445 					     sizeof(struct cbfs_header);
1446 			DEBUG("x86 -> CBFS header before bootblock (%#x).\n",
1447 				param.headeroffset);
1448 		} else {
1449 			param.headeroffset = align_up(param.baseaddress +
1450 				bootblock.size, sizeof(uint32_t));
1451 			DEBUG("CBFS header placed behind bootblock (%#x).\n",
1452 				param.headeroffset);
1453 		}
1454 	}
1455 	if (!param.cbfsoffset_assigned) {
1456 		if (param.arch == CBFS_ARCHITECTURE_X86) {
1457 			param.cbfsoffset = 0;
1458 			DEBUG("x86 -> CBFS entries start at address 0x0.\n");
1459 		} else {
1460 			param.cbfsoffset = align_up(param.headeroffset +
1461 						    sizeof(struct cbfs_header),
1462 						    CBFS_ALIGNMENT);
1463 			DEBUG("CBFS entries start beind master header (%#x).\n",
1464 			      param.cbfsoffset);
1465 		}
1466 	}
1467 
1468 	int ret = cbfs_legacy_image_create(&image,
1469 					   param.arch,
1470 					   CBFS_ALIGNMENT,
1471 					   &bootblock,
1472 					   param.baseaddress,
1473 					   param.headeroffset,
1474 					   param.cbfsoffset);
1475 	buffer_delete(&bootblock);
1476 	return ret;
1477 }
1478 
cbfs_layout(void)1479 static int cbfs_layout(void)
1480 {
1481 	const struct fmap *fmap = partitioned_file_get_fmap(param.image_file);
1482 	if (!fmap) {
1483 		LOG("This is a legacy image composed entirely of a single CBFS.\n");
1484 		return 1;
1485 	}
1486 
1487 	printf("This image contains the following sections that can be %s with this tool:\n",
1488 			param.show_immutable ? "accessed" : "manipulated");
1489 	puts("");
1490 	for (unsigned i = 0; i < fmap->nareas; ++i) {
1491 		const struct fmap_area *current = fmap->areas + i;
1492 
1493 		bool readonly = partitioned_file_fmap_count(param.image_file,
1494 			partitioned_file_fmap_select_children_of, current) ||
1495 				region_is_flashmap((const char *)current->name);
1496 		if (!param.show_immutable && readonly)
1497 			continue;
1498 
1499 		printf("'%s'", current->name);
1500 
1501 		// Detect consecutive sections that describe the same region and
1502 		// show them as aliases. This cannot find equivalent entries
1503 		// that aren't adjacent; however, fmaptool doesn't generate
1504 		// FMAPs with such sections, so this convenience feature works
1505 		// for all but the strangest manually created FMAP binaries.
1506 		// TODO: This could be done by parsing the FMAP into some kind
1507 		// of tree that had duplicate lists in addition to child lists,
1508 		// which would allow covering that weird, unlikely case as well.
1509 		unsigned lookahead;
1510 		for (lookahead = 1; i + lookahead < fmap->nareas;
1511 								++lookahead) {
1512 			const struct fmap_area *consecutive =
1513 					fmap->areas + i + lookahead;
1514 			if (consecutive->offset != current->offset ||
1515 					consecutive->size != current->size)
1516 				break;
1517 			printf(", '%s'", consecutive->name);
1518 		}
1519 		if (lookahead > 1)
1520 			fputs(" are aliases for the same region", stdout);
1521 
1522 		const char *qualifier = "";
1523 		if (readonly)
1524 			qualifier = "read-only, ";
1525 		else if (region_is_modern_cbfs((const char *)current->name))
1526 			qualifier = "CBFS, ";
1527 		else if (current->flags & FMAP_AREA_PRESERVE)
1528 			qualifier = "preserve, ";
1529 		printf(" (%ssize %u, offset %u)\n", qualifier, current->size,
1530 				current->offset);
1531 
1532 		i += lookahead - 1;
1533 	}
1534 	puts("");
1535 
1536 	if (param.show_immutable) {
1537 		puts("It is at least possible to perform the read action on every section listed above.");
1538 	} else {
1539 		puts("It is possible to perform either the write action or the CBFS add/remove actions on every section listed above.");
1540 		puts("To see the image's read-only sections as well, rerun with the -w option.");
1541 	}
1542 
1543 	return 0;
1544 }
1545 
verify_walker(__always_unused cbfs_dev_t dev,size_t offset,const union cbfs_mdata * mdata,size_t already_read,void * arg)1546 static enum cb_err verify_walker(__always_unused cbfs_dev_t dev, size_t offset,
1547 				 const union cbfs_mdata *mdata, size_t already_read, void *arg)
1548 {
1549 	uint32_t type = be32toh(mdata->h.type);
1550 	uint32_t data_offset = be32toh(mdata->h.offset);
1551 	if (verification_exclude(type))
1552 		return CB_CBFS_NOT_FOUND;
1553 	assert(already_read == data_offset);
1554 	const struct vb2_hash *hash = cbfs_file_hash(mdata);
1555 	if (!hash)
1556 		return CB_ERR;
1557 	void *file_data = arg + offset + data_offset;
1558 	if (vb2_hash_verify(false, file_data, be32toh(mdata->h.len), hash) != VB2_SUCCESS)
1559 		return CB_CBFS_HASH_MISMATCH;
1560 	return CB_CBFS_NOT_FOUND;
1561 }
1562 
cbfs_print(void)1563 static int cbfs_print(void)
1564 {
1565 	struct cbfs_image image;
1566 	if (cbfs_image_from_buffer(&image, param.image_region,
1567 							param.headeroffset))
1568 		return 1;
1569 	if (param.machine_parseable) {
1570 		if (verbose)
1571 			printf("[FMAP REGION]\t%s\n", param.region_name);
1572 		cbfs_print_parseable_directory(&image);
1573 	} else {
1574 		printf("FMAP REGION: %s\n", param.region_name);
1575 		cbfs_print_directory(&image);
1576 	}
1577 
1578 	if (verbose) {
1579 		const char *verification_state = "fully valid";
1580 		struct mh_cache *mhc = get_mh_cache();
1581 		if (mhc->cbfs_hash.algo == VB2_HASH_INVALID)
1582 			return 0;
1583 
1584 		struct vb2_hash real_hash = { .algo = mhc->cbfs_hash.algo };
1585 		enum cb_err err = cbfs_walk(&image, verify_walker, buffer_get(&image.buffer),
1586 					    &real_hash, CBFS_WALK_WRITEBACK_HASH);
1587 		if (err == CB_CBFS_HASH_MISMATCH)
1588 			verification_state = "invalid file hashes";
1589 		else if (err != CB_CBFS_NOT_FOUND)
1590 			verification_state = "missing file hashes";
1591 		char *hash_str = bintohex(real_hash.raw,
1592 				vb2_digest_size(real_hash.algo));
1593 		printf("[METADATA HASH]\t%s:%s",
1594 		       vb2_get_hash_algorithm_name(real_hash.algo), hash_str);
1595 		if (!strcmp(param.region_name, SECTION_NAME_PRIMARY_CBFS)) {
1596 			if (!memcmp(mhc->cbfs_hash.raw, real_hash.raw,
1597 				    vb2_digest_size(real_hash.algo))) {
1598 				printf(":valid");
1599 			} else {
1600 				printf(":invalid");
1601 				verification_state = "invalid metadata hash";
1602 			}
1603 		}
1604 		printf("\n");
1605 		printf("[CBFS VERIFICATION (%s)]\t%s\n", param.region_name, verification_state);
1606 		free(hash_str);
1607 	}
1608 
1609 	return 0;
1610 }
1611 
cbfs_extract(void)1612 static int cbfs_extract(void)
1613 {
1614 	if (!param.filename) {
1615 		ERROR("You need to specify -f/--filename.\n");
1616 		return 1;
1617 	}
1618 
1619 	if (!param.name) {
1620 		ERROR("You need to specify -n/--name.\n");
1621 		return 1;
1622 	}
1623 
1624 	struct cbfs_image image;
1625 	if (cbfs_image_from_buffer(&image, param.image_region,
1626 							param.headeroffset))
1627 		return 1;
1628 
1629 	return cbfs_export_entry(&image, param.name, param.filename,
1630 				param.arch, !param.unprocessed);
1631 }
1632 
cbfs_write(void)1633 static int cbfs_write(void)
1634 {
1635 	if (!param.filename) {
1636 		ERROR("You need to specify a valid input -f/--file.\n");
1637 		return 1;
1638 	}
1639 	if (!partitioned_file_is_partitioned(param.image_file)) {
1640 		ERROR("This operation isn't valid on legacy images having CBFS master headers\n");
1641 		return 1;
1642 	}
1643 
1644 	if (!param.force && region_is_modern_cbfs(param.region_name)) {
1645 		ERROR("Target image region '%s' is a CBFS and must be manipulated using add and remove\n",
1646 							param.region_name);
1647 		return 1;
1648 	}
1649 
1650 	struct buffer new_content;
1651 	if (buffer_from_file(&new_content, param.filename))
1652 		return 1;
1653 
1654 	if (buffer_check_magic(&new_content, FMAP_SIGNATURE,
1655 						strlen(FMAP_SIGNATURE))) {
1656 		ERROR("File '%s' appears to be an FMAP and cannot be added to an existing image\n",
1657 								param.filename);
1658 		buffer_delete(&new_content);
1659 		return 1;
1660 	}
1661 	if (!param.force && buffer_check_magic(&new_content, CBFS_FILE_MAGIC,
1662 						strlen(CBFS_FILE_MAGIC))) {
1663 		ERROR("File '%s' appears to be a CBFS and cannot be inserted into a raw region\n",
1664 								param.filename);
1665 		buffer_delete(&new_content);
1666 		return 1;
1667 	}
1668 
1669 	unsigned offset = 0;
1670 	if (param.fill_partial_upward && param.fill_partial_downward) {
1671 		ERROR("You may only specify one of -u and -d.\n");
1672 		buffer_delete(&new_content);
1673 		return 1;
1674 	} else if (!param.fill_partial_upward && !param.fill_partial_downward) {
1675 		if (new_content.size != param.image_region->size) {
1676 			ERROR("File to add is %zu bytes and would not fill %zu-byte target region (did you mean to pass either -u or -d?)\n",
1677 				new_content.size, param.image_region->size);
1678 			buffer_delete(&new_content);
1679 			return 1;
1680 		}
1681 	} else {
1682 		if (new_content.size > param.image_region->size) {
1683 			ERROR("File to add is %zu bytes and would overflow %zu-byte target region\n",
1684 				new_content.size, param.image_region->size);
1685 			buffer_delete(&new_content);
1686 			return 1;
1687 		}
1688 		if (param.u64val == (uint64_t)-1) {
1689 			WARN("Written area will abut %s of target region: any unused space will keep its current contents\n",
1690 					param.fill_partial_upward ? "bottom" : "top");
1691 		} else if (param.u64val > 0xff) {
1692 			ERROR("given fill value (%x) is larger than a byte\n", (unsigned)(param.u64val & 0xff));
1693 			buffer_delete(&new_content);
1694 			return 1;
1695 		} else {
1696 			memset(buffer_get(param.image_region),
1697 				param.u64val & 0xff,
1698 				buffer_size(param.image_region));
1699 		}
1700 		if (param.fill_partial_downward)
1701 			offset = param.image_region->size - new_content.size;
1702 	}
1703 
1704 	memcpy(param.image_region->data + offset, new_content.data,
1705 							new_content.size);
1706 	buffer_delete(&new_content);
1707 
1708 	return maybe_update_fmap_hash();
1709 }
1710 
cbfs_read(void)1711 static int cbfs_read(void)
1712 {
1713 	if (!param.filename) {
1714 		ERROR("You need to specify a valid output -f/--file.\n");
1715 		return 1;
1716 	}
1717 	if (!partitioned_file_is_partitioned(param.image_file)) {
1718 		ERROR("This operation isn't valid on legacy images having CBFS master headers\n");
1719 		return 1;
1720 	}
1721 
1722 	return buffer_write_file(param.image_region, param.filename);
1723 }
1724 
cbfs_copy(void)1725 static int cbfs_copy(void)
1726 {
1727 	struct cbfs_image src_image;
1728 	struct buffer src_buf;
1729 
1730 	if (!param.source_region) {
1731 		ERROR("You need to specify -R/--source-region.\n");
1732 		return 1;
1733 	}
1734 
1735 	/* Obtain the source region and convert it to a cbfs_image. */
1736 	if (!partitioned_file_read_region(&src_buf, param.image_file,
1737 						param.source_region)) {
1738 		ERROR("Region not found in image: %s\n", param.source_region);
1739 		return 1;
1740 	}
1741 
1742 	if (cbfs_image_from_buffer(&src_image, &src_buf, param.headeroffset))
1743 		return 1;
1744 
1745 	return cbfs_copy_instance(&src_image, param.image_region);
1746 }
1747 
cbfs_compact(void)1748 static int cbfs_compact(void)
1749 {
1750 	struct cbfs_image image;
1751 	if (cbfs_image_from_buffer(&image, param.image_region,
1752 							param.headeroffset))
1753 		return 1;
1754 	WARN("Compacting a CBFS doesn't honor alignment or fixed addresses!\n");
1755 	return cbfs_compact_instance(&image);
1756 }
1757 
cbfs_expand(void)1758 static int cbfs_expand(void)
1759 {
1760 	struct buffer src_buf;
1761 
1762 	/* Obtain the source region. */
1763 	if (!partitioned_file_read_region(&src_buf, param.image_file,
1764 						param.region_name)) {
1765 		ERROR("Region not found in image: %s\n", param.source_region);
1766 		return 1;
1767 	}
1768 
1769 	return cbfs_expand_to_region(param.image_region);
1770 }
1771 
cbfs_truncate(void)1772 static int cbfs_truncate(void)
1773 {
1774 	struct buffer src_buf;
1775 
1776 	/* Obtain the source region. */
1777 	if (!partitioned_file_read_region(&src_buf, param.image_file,
1778 						param.region_name)) {
1779 		ERROR("Region not found in image: %s\n", param.source_region);
1780 		return 1;
1781 	}
1782 
1783 	uint32_t size;
1784 	int result = cbfs_truncate_space(param.image_region, &size);
1785 	if (!result)
1786 		printf("0x%x\n", size);
1787 	return result;
1788 }
1789 
1790 static const struct command commands[] = {
1791 	{"add", "H:r:f:n:t:c:b:a:p:yvA:j:gh?", cbfs_add, true, true},
1792 	{"add-flat-binary", "H:r:f:n:l:e:c:b:p:vA:gh?", cbfs_add_flat_binary,
1793 				true, true},
1794 	{"add-payload", "H:r:f:n:c:b:a:C:I:p:vA:gh?", cbfs_add_payload,
1795 				true, true},
1796 	{"add-stage", "a:H:r:f:n:t:c:b:P:QS:p:yvA:gh?", cbfs_add_stage,
1797 				true, true},
1798 	{"add-int", "H:r:i:n:b:vgh?", cbfs_add_integer, true, true},
1799 	{"add-master-header", "H:r:vh?j:", cbfs_add_master_header, true, true},
1800 	{"compact", "r:h?", cbfs_compact, true, true},
1801 	{"copy", "r:R:h?", cbfs_copy, true, true},
1802 	{"create", "M:r:s:B:b:H:o:m:vh?", cbfs_create, true, true},
1803 	{"extract", "H:r:m:n:f:Uvh?", cbfs_extract, true, false},
1804 	{"layout", "wvh?", cbfs_layout, false, false},
1805 	{"print", "H:r:vkh?", cbfs_print, true, false},
1806 	{"read", "r:f:vh?", cbfs_read, true, false},
1807 	{"remove", "H:r:n:vh?", cbfs_remove, true, true},
1808 	{"write", "r:f:i:Fudvh?", cbfs_write, true, true},
1809 	{"expand", "r:h?", cbfs_expand, true, true},
1810 	{"truncate", "r:h?", cbfs_truncate, true, true},
1811 };
1812 
1813 enum {
1814 	/* begin after ASCII characters */
1815 	LONGOPT_START = 256,
1816 	LONGOPT_IBB = LONGOPT_START,
1817 	LONGOPT_MMAP,
1818 	LONGOPT_END,
1819 };
1820 
1821 static struct option long_options[] = {
1822 	{"alignment",     required_argument, 0, 'a' },
1823 	{"base-address",  required_argument, 0, 'b' },
1824 	{"bootblock",     required_argument, 0, 'B' },
1825 	{"cmdline",       required_argument, 0, 'C' },
1826 	{"compression",   required_argument, 0, 'c' },
1827 	{"topswap-size",  required_argument, 0, 'j' },
1828 	{"empty-fits",    required_argument, 0, 'x' },
1829 	{"entry-point",   required_argument, 0, 'e' },
1830 	{"file",          required_argument, 0, 'f' },
1831 	{"fill-downward", no_argument,       0, 'd' },
1832 	{"fill-upward",   no_argument,       0, 'u' },
1833 	{"flashmap",      required_argument, 0, 'M' },
1834 	{"fmap-regions",  required_argument, 0, 'r' },
1835 	{"force",         no_argument,       0, 'F' },
1836 	{"source-region", required_argument, 0, 'R' },
1837 	{"hash-algorithm",required_argument, 0, 'A' },
1838 	{"header-offset", required_argument, 0, 'H' },
1839 	{"help",          no_argument,       0, 'h' },
1840 	{"ignore-sec",    required_argument, 0, 'S' },
1841 	{"initrd",        required_argument, 0, 'I' },
1842 	{"int",           required_argument, 0, 'i' },
1843 	{"load-address",  required_argument, 0, 'l' },
1844 	{"machine",       required_argument, 0, 'm' },
1845 	{"name",          required_argument, 0, 'n' },
1846 	{"offset",        required_argument, 0, 'o' },
1847 	{"padding",       required_argument, 0, 'p' },
1848 	{"pow2page",      no_argument,       0, 'Q' },
1849 	{"ucode-region",  required_argument, 0, 'q' },
1850 	{"size",          required_argument, 0, 's' },
1851 	{"type",          required_argument, 0, 't' },
1852 	{"verbose",       no_argument,       0, 'v' },
1853 	{"with-readonly", no_argument,       0, 'w' },
1854 	{"xip",           no_argument,       0, 'y' },
1855 	{"gen-attribute", no_argument,       0, 'g' },
1856 	{"mach-parseable",no_argument,       0, 'k' },
1857 	{"unprocessed",   no_argument,       0, 'U' },
1858 	{"ibb",           no_argument,       0, LONGOPT_IBB },
1859 	{"mmap",          required_argument, 0, LONGOPT_MMAP },
1860 	{NULL,            0,                 0,  0  }
1861 };
1862 
get_region_offset(long long int offset,uint32_t * region_offset)1863 static int get_region_offset(long long int offset, uint32_t *region_offset)
1864 {
1865 	/* If offset is not negative, no transformation required. */
1866 	if (offset >= 0) {
1867 		*region_offset = offset;
1868 		return 0;
1869 	}
1870 
1871 	/* Calculate offset from start of region. */
1872 	return convert_region_offset(-offset, region_offset);
1873 }
1874 
calculate_region_offsets(void)1875 static int calculate_region_offsets(void)
1876 {
1877 	int ret = 0;
1878 
1879 	if (param.baseaddress_assigned)
1880 		ret |= get_region_offset(param.baseaddress_input, &param.baseaddress);
1881 	if (param.headeroffset_assigned)
1882 		ret |= get_region_offset(param.headeroffset_input, &param.headeroffset);
1883 	if (param.cbfsoffset_assigned)
1884 		ret |= get_region_offset(param.cbfsoffset_input, &param.cbfsoffset);
1885 
1886 	return ret;
1887 }
1888 
dispatch_command(struct command command)1889 static int dispatch_command(struct command command)
1890 {
1891 	if (command.accesses_region) {
1892 		assert(param.image_file);
1893 
1894 		if (partitioned_file_is_partitioned(param.image_file)) {
1895 			INFO("Performing operation on '%s' region...\n",
1896 					param.region_name);
1897 		}
1898 		if (!partitioned_file_read_region(param.image_region,
1899 					param.image_file, param.region_name)) {
1900 			ERROR("The image will be left unmodified.\n");
1901 			return 1;
1902 		}
1903 
1904 		if (command.modifies_region) {
1905 			// We (intentionally) don't support overwriting the FMAP
1906 			// section. If you find yourself wanting to do this,
1907 			// consider creating a new image rather than performing
1908 			// whatever hacky transformation you were planning.
1909 			if (region_is_flashmap(param.region_name)) {
1910 				ERROR("Image region '%s' is read-only because it contains the FMAP.\n",
1911 							param.region_name);
1912 				ERROR("The image will be left unmodified.\n");
1913 				return 1;
1914 			}
1915 			// We don't allow writing raw data to regions that
1916 			// contain nested regions, since doing so would
1917 			// overwrite all such subregions.
1918 			if (partitioned_file_region_contains_nested(
1919 					param.image_file, param.region_name)) {
1920 				ERROR("Image region '%s' is read-only because it contains nested regions.\n",
1921 							param.region_name);
1922 				ERROR("The image will be left unmodified.\n");
1923 				return 1;
1924 			}
1925 		}
1926 
1927 		/*
1928 		 * Once image region is read, input offsets can be adjusted accordingly if the
1929 		 * inputs are provided as negative integers i.e. offsets from end of region.
1930 		 */
1931 		if (calculate_region_offsets())
1932 			return 1;
1933 	}
1934 
1935 	if (command.function()) {
1936 		if (partitioned_file_is_partitioned(param.image_file)) {
1937 			ERROR("Failed while operating on '%s' region!\n",
1938 							param.region_name);
1939 			ERROR("The image will be left unmodified.\n");
1940 		}
1941 		return 1;
1942 	}
1943 
1944 	return 0;
1945 }
1946 
usage(char * name)1947 static void usage(char *name)
1948 {
1949 	printf
1950 	    ("cbfstool: Management utility for CBFS formatted ROM images\n\n"
1951 	     "USAGE:\n" " %s [-h]\n"
1952 	     " %s FILE COMMAND [-v] [PARAMETERS]...\n\n" "OPTIONs:\n"
1953 	     "  -H header_offset Do not search for header; use this offset*\n"
1954 	     "  -T               Output top-aligned memory address\n"
1955 	     "  -u               Accept short data; fill upward/from bottom\n"
1956 	     "  -d               Accept short data; fill downward/from top\n"
1957 	     "  -F               Force action\n"
1958 	     "  -g               Generate position and alignment arguments\n"
1959 	     "  -U               Unprocessed; don't decompress or make ELF\n"
1960 	     "  -v               Provide verbose output (-v=INFO -vv=DEBUG output)\n"
1961 	     "  -h               Display this help message\n\n"
1962 	     "  --ext-win-base   Base of extended decode window in host address\n"
1963 	     "                   space(x86 only)\n"
1964 	     "  --ext-win-size   Size of extended decode window in host address\n"
1965 	     "                   space(x86 only)\n"
1966 	     "COMMANDs:\n"
1967 	     " add [-r image,regions] -f FILE -n NAME -t TYPE [-A hash] \\\n"
1968 	     "        [-c compression] [-b base-address | -a alignment] \\\n"
1969 	     "        [-p padding size] [-y|--xip if TYPE is FSP]       \\\n"
1970 	     "        [-j topswap-size] (Intel CPUs only) [--ibb]       \\\n"
1971 	     "        [--ext-win-base win-base --ext-win-size win-size]     "
1972 			"Add a component\n"
1973 	     "                                                         "
1974 	     "    -j valid size: 0x10000 0x20000 0x40000 0x80000 0x100000 \n"
1975 	     " add-payload [-r image,regions] -f FILE -n NAME [-A hash] \\\n"
1976 	     "        [-c compression] [-b base-address] \\\n"
1977 	     "        (linux specific: [-C cmdline] [-I initrd])           "
1978 			"Add a payload to the ROM\n"
1979 	     " add-stage [-r image,regions] -f FILE -n NAME [-A hash] \\\n"
1980 	     "        [-c compression] [-b base] \\\n"
1981 	     "        [-S comma-separated-section(s)-to-ignore] \\\n"
1982 	     "        [-a alignment] [-Q|--pow2page] \\\n"
1983 	     "        [-y|--xip] [--ibb]                                \\\n"
1984 	     "        [--ext-win-base win-base --ext-win-size win-size]     "
1985 			"Add a stage to the ROM\n"
1986 	     " add-flat-binary [-r image,regions] -f FILE -n NAME \\\n"
1987 	     "        [-A hash] -l load-address -e entry-point \\\n"
1988 	     "        [-c compression] [-b base]                           "
1989 			"Add a 32bit flat mode binary\n"
1990 	     " add-int [-r image,regions] -i INTEGER -n NAME [-b base]     "
1991 			"Add a raw 64-bit integer value\n"
1992 	     " add-master-header [-r image,regions] \\                   \n"
1993 	     "        [-j topswap-size] (Intel CPUs only)                  "
1994 			"Add a legacy CBFS master header\n"
1995 	     " remove [-r image,regions] -n NAME                           "
1996 			"Remove a component\n"
1997 	     " compact -r image,regions                                    "
1998 			"Defragment CBFS image.\n"
1999 	     " copy -r image,regions -R source-region                      "
2000 			"Create a copy (duplicate) cbfs instance in fmap\n"
2001 	     " create -m ARCH -s size [-b bootblock offset] \\\n"
2002 	     "        [-o CBFS offset] [-H header offset] [-B bootblock]   "
2003 			"Create a legacy ROM file with CBFS master header*\n"
2004 	     " create -M flashmap [-r list,of,regions,containing,cbfses]   "
2005 			"Create a new-style partitioned firmware image\n"
2006 	     " layout [-w]                                                 "
2007 			"List mutable (or, with -w, readable) image regions\n"
2008 	     " print [-r image,regions] [-k]                               "
2009 			"Show the contents of the ROM\n"
2010 	     " extract [-r image,regions] [-m ARCH] -n NAME -f FILE [-U]   "
2011 			"Extracts a file from ROM\n"
2012 	     " write [-F] -r image,regions -f file [-u | -d] [-i int]      "
2013 			"Write file into same-size [or larger] raw region\n"
2014 	     " read [-r fmap-region] -f file                               "
2015 			"Extract raw region contents into binary file\n"
2016 	     " truncate [-r fmap-region]                                   "
2017 			"Truncate CBFS and print new size on stdout\n"
2018 	     " expand [-r fmap-region]                                     "
2019 			"Expand CBFS to span entire region\n"
2020 	     "OFFSETs:\n"
2021 	     "  Numbers accompanying -b, -H, and -o switches* may be provided\n"
2022 	     "  in two possible formats: if their value is greater than\n"
2023 	     "  0x80000000, they are interpreted as a top-aligned x86 memory\n"
2024 	     "  address; otherwise, they are treated as an offset into flash.\n"
2025 	     "ARCHes:\n", name, name
2026 	    );
2027 	print_supported_architectures();
2028 
2029 	printf("TYPEs:\n");
2030 	print_supported_filetypes();
2031 	printf(
2032 	     "\n* Note that these actions and switches are only valid when\n"
2033 	     "  working with legacy images whose structure is described\n"
2034 	     "  primarily by a CBFS master header. New-style images, in\n"
2035 	     "  contrast, exclusively make use of an FMAP to describe their\n"
2036 	     "  layout: this must minimally contain an '%s' section\n"
2037 	     "  specifying the location of this FMAP itself and a '%s'\n"
2038 	     "  section describing the primary CBFS. It should also be noted\n"
2039 	     "  that, when working with such images, the -F and -r switches\n"
2040 	     "  default to '%s' for convenience, and the -b switch becomes\n"
2041 	     "  relative to the selected CBFS region's lowest address.\n"
2042 	     "  The one exception to this rule is the top-aligned address,\n"
2043 	     "  which is always relative to the end of the entire image\n"
2044 	     "  rather than relative to the local region; this is true for\n"
2045 	     "  for both input (sufficiently large) and output (-T) data.\n",
2046 	     SECTION_NAME_FMAP, SECTION_NAME_PRIMARY_CBFS,
2047 	     SECTION_NAME_PRIMARY_CBFS
2048 	     );
2049 }
2050 
valid_opt(size_t i,int c)2051 static bool valid_opt(size_t i, int c)
2052 {
2053 	/* Check if it is one of the optstrings supported by the command. */
2054 	if (strchr(commands[i].optstring, c))
2055 		return true;
2056 
2057 	/*
2058 	 * Check if it is one of the non-ASCII characters. Currently, the
2059 	 * non-ASCII characters are only checked against the valid list
2060 	 * irrespective of the command.
2061 	 */
2062 	if (c >= LONGOPT_START && c < LONGOPT_END)
2063 		return true;
2064 
2065 	return false;
2066 }
2067 
main(int argc,char ** argv)2068 int main(int argc, char **argv)
2069 {
2070 	size_t i;
2071 	int c;
2072 
2073 	if (argc < 3) {
2074 		usage(argv[0]);
2075 		return 1;
2076 	}
2077 
2078 	char *image_name = argv[1];
2079 	char *cmd = argv[2];
2080 	optind += 2;
2081 
2082 	for (i = 0; i < ARRAY_SIZE(commands); i++) {
2083 		if (strcmp(cmd, commands[i].name) != 0)
2084 			continue;
2085 
2086 		while (1) {
2087 			char *suffix = NULL;
2088 			int option_index = 0;
2089 
2090 			c = getopt_long(argc, argv, commands[i].optstring,
2091 						long_options, &option_index);
2092 			if (c == -1) {
2093 				if (optind < argc) {
2094 					ERROR("%s: excessive argument -- '%s'"
2095 						"\n", argv[0], argv[optind]);
2096 					return 1;
2097 				}
2098 				break;
2099 			}
2100 
2101 			/* Filter out illegal long options */
2102 			if (!valid_opt(i, c)) {
2103 				ERROR("%s: invalid option -- '%d'\n",
2104 				      argv[0], c);
2105 				c = '?';
2106 			}
2107 
2108 			switch(c) {
2109 			case 'n':
2110 				param.name = optarg;
2111 				break;
2112 			case 't':
2113 				if (intfiletype(optarg) != ((uint64_t) - 1))
2114 					param.type = intfiletype(optarg);
2115 				else
2116 					param.type = strtoul(optarg, NULL, 0);
2117 				if (param.type == 0)
2118 					WARN("Unknown type '%s' ignored\n",
2119 							optarg);
2120 				break;
2121 			case 'c': {
2122 				if (strcmp(optarg, "precompression") == 0) {
2123 					param.precompression = 1;
2124 					break;
2125 				}
2126 				int algo = cbfs_parse_comp_algo(optarg);
2127 				if (algo >= 0)
2128 					param.compression = algo;
2129 				else
2130 					WARN("Unknown compression '%s' ignored.\n",
2131 									optarg);
2132 				break;
2133 			}
2134 			case 'A': {
2135 				if (!vb2_lookup_hash_alg(optarg, &param.hash)) {
2136 					ERROR("Unknown hash algorithm '%s'.\n",
2137 						optarg);
2138 					return 1;
2139 				}
2140 				break;
2141 			}
2142 			case 'M':
2143 				param.fmap = optarg;
2144 				break;
2145 			case 'r':
2146 				param.region_name = optarg;
2147 				break;
2148 			case 'R':
2149 				param.source_region = optarg;
2150 				break;
2151 			case 'b':
2152 				param.baseaddress_input = strtoll(optarg, &suffix, 0);
2153 				if (!*optarg || (suffix && *suffix)) {
2154 					ERROR("Invalid base address '%s'.\n",
2155 						optarg);
2156 					return 1;
2157 				}
2158 				// baseaddress may be zero on non-x86, so we
2159 				// need an explicit "baseaddress_assigned".
2160 				param.baseaddress_assigned = 1;
2161 				break;
2162 			case 'l':
2163 				param.loadaddress = strtoull(optarg, &suffix, 0);
2164 				if (!*optarg || (suffix && *suffix)) {
2165 					ERROR("Invalid load address '%s'.\n",
2166 						optarg);
2167 					return 1;
2168 				}
2169 				break;
2170 			case 'e':
2171 				param.entrypoint = strtoull(optarg, &suffix, 0);
2172 				if (!*optarg || (suffix && *suffix)) {
2173 					ERROR("Invalid entry point '%s'.\n",
2174 						optarg);
2175 					return 1;
2176 				}
2177 				break;
2178 			case 's':
2179 				param.size = strtoul(optarg, &suffix, 0);
2180 				if (!*optarg) {
2181 					ERROR("Empty size specified.\n");
2182 					return 1;
2183 				}
2184 				switch (tolower((int)suffix[0])) {
2185 				case 'k':
2186 					param.size *= 1024;
2187 					break;
2188 				case 'm':
2189 					param.size *= 1024 * 1024;
2190 					break;
2191 				case '\0':
2192 					break;
2193 				default:
2194 					ERROR("Invalid suffix for size '%s'.\n",
2195 						optarg);
2196 					return 1;
2197 				}
2198 				break;
2199 			case 'B':
2200 				param.bootblock = optarg;
2201 				break;
2202 			case 'H':
2203 				param.headeroffset_input = strtoll(optarg, &suffix, 0);
2204 				if (!*optarg || (suffix && *suffix)) {
2205 					ERROR("Invalid header offset '%s'.\n",
2206 						optarg);
2207 					return 1;
2208 				}
2209 				param.headeroffset_assigned = 1;
2210 				break;
2211 			case 'a':
2212 				param.alignment = strtoul(optarg, &suffix, 0);
2213 				if (!*optarg || (suffix && *suffix)) {
2214 					ERROR("Invalid alignment '%s'.\n",
2215 						optarg);
2216 					return 1;
2217 				}
2218 				break;
2219 			case 'p':
2220 				param.padding = strtoul(optarg, &suffix, 0);
2221 				if (!*optarg || (suffix && *suffix)) {
2222 					ERROR("Invalid pad size '%s'.\n",
2223 						optarg);
2224 					return 1;
2225 				}
2226 				break;
2227 			case 'Q':
2228 				param.force_pow2_pagesize = 1;
2229 				break;
2230 			case 'o':
2231 				param.cbfsoffset_input = strtoll(optarg, &suffix, 0);
2232 				if (!*optarg || (suffix && *suffix)) {
2233 					ERROR("Invalid cbfs offset '%s'.\n",
2234 						optarg);
2235 					return 1;
2236 				}
2237 				param.cbfsoffset_assigned = 1;
2238 				break;
2239 			case 'f':
2240 				param.filename = optarg;
2241 				break;
2242 			case 'F':
2243 				param.force = 1;
2244 				break;
2245 			case 'i':
2246 				param.u64val = strtoull(optarg, &suffix, 0);
2247 				param.u64val_assigned = 1;
2248 				if (!*optarg || (suffix && *suffix)) {
2249 					ERROR("Invalid int parameter '%s'.\n",
2250 						optarg);
2251 					return 1;
2252 				}
2253 				break;
2254 			case 'u':
2255 				param.fill_partial_upward = true;
2256 				break;
2257 			case 'd':
2258 				param.fill_partial_downward = true;
2259 				break;
2260 			case 'w':
2261 				param.show_immutable = true;
2262 				break;
2263 			case 'j':
2264 				param.topswap_size = strtol(optarg, NULL, 0);
2265 				if (!is_valid_topswap())
2266 					return 1;
2267 				break;
2268 			case 'q':
2269 				param.ucode_region = optarg;
2270 				break;
2271 			case 'v':
2272 				verbose++;
2273 				break;
2274 			case 'm':
2275 				param.arch = string_to_arch(optarg);
2276 				break;
2277 			case 'I':
2278 				param.initrd = optarg;
2279 				break;
2280 			case 'C':
2281 				param.cmdline = optarg;
2282 				break;
2283 			case 'S':
2284 				param.ignore_sections = optarg;
2285 				break;
2286 			case 'y':
2287 				param.stage_xip = true;
2288 				break;
2289 			case 'g':
2290 				param.autogen_attr = true;
2291 				break;
2292 			case 'k':
2293 				param.machine_parseable = true;
2294 				break;
2295 			case 'U':
2296 				param.unprocessed = true;
2297 				break;
2298 			case LONGOPT_IBB:
2299 				param.ibb = true;
2300 				break;
2301 			case LONGOPT_MMAP:
2302 				if (decode_mmap_arg(optarg))
2303 					return 1;
2304 				break;
2305 			case 'h':
2306 			case '?':
2307 				usage(argv[0]);
2308 				return 1;
2309 			default:
2310 				break;
2311 			}
2312 		}
2313 
2314 		if (commands[i].function == cbfs_create) {
2315 			if (param.fmap) {
2316 				struct buffer flashmap;
2317 				if (buffer_from_file(&flashmap, param.fmap))
2318 					return 1;
2319 				param.image_file = partitioned_file_create(
2320 							image_name, &flashmap);
2321 				buffer_delete(&flashmap);
2322 			} else if (param.size) {
2323 				param.image_file = partitioned_file_create_flat(
2324 							image_name, param.size);
2325 			} else {
2326 				ERROR("You need to specify a valid -M/--flashmap or -s/--size.\n");
2327 				return 1;
2328 			}
2329 		} else {
2330 			bool write_access = commands[i].modifies_region;
2331 
2332 			param.image_file =
2333 				partitioned_file_reopen(image_name,
2334 							write_access);
2335 		}
2336 		if (!param.image_file)
2337 			return 1;
2338 
2339 		unsigned num_regions = 1;
2340 		for (const char *list = strchr(param.region_name, ','); list;
2341 						list = strchr(list + 1, ','))
2342 			++num_regions;
2343 
2344 		// If the action needs to read an image region, as indicated by
2345 		// having accesses_region set in its command struct, that
2346 		// region's buffer struct will be stored here and the client
2347 		// will receive a pointer to it via param.image_region. It
2348 		// need not write the buffer back to the image file itself,
2349 		// since this behavior can be requested via its modifies_region
2350 		// field. Additionally, it should never free the region buffer,
2351 		// as that is performed automatically once it completes.
2352 		struct buffer image_regions[num_regions];
2353 		memset(image_regions, 0, sizeof(image_regions));
2354 
2355 		bool seen_primary_cbfs = false;
2356 		char region_name_scratch[strlen(param.region_name) + 1];
2357 		strcpy(region_name_scratch, param.region_name);
2358 		param.region_name = strtok(region_name_scratch, ",");
2359 		for (unsigned region = 0; region < num_regions; ++region) {
2360 			if (!param.region_name) {
2361 				ERROR("Encountered illegal degenerate region name in -r list\n");
2362 				ERROR("The image will be left unmodified.\n");
2363 				partitioned_file_close(param.image_file);
2364 				return 1;
2365 			}
2366 
2367 			if (strcmp(param.region_name, SECTION_NAME_PRIMARY_CBFS)
2368 									== 0)
2369 				seen_primary_cbfs = true;
2370 
2371 			param.image_region = image_regions + region;
2372 			if (dispatch_command(commands[i])) {
2373 				partitioned_file_close(param.image_file);
2374 				return 1;
2375 			}
2376 
2377 			param.region_name = strtok(NULL, ",");
2378 		}
2379 
2380 		if (commands[i].function == cbfs_create && !seen_primary_cbfs) {
2381 			ERROR("The creation -r list must include the mandatory '%s' section.\n",
2382 						SECTION_NAME_PRIMARY_CBFS);
2383 			ERROR("The image will be left unmodified.\n");
2384 			partitioned_file_close(param.image_file);
2385 			return 1;
2386 		}
2387 
2388 		if (commands[i].modifies_region) {
2389 			assert(param.image_file);
2390 			for (unsigned region = 0; region < num_regions;
2391 								++region) {
2392 
2393 				if (!partitioned_file_write_region(
2394 							param.image_file,
2395 						image_regions + region)) {
2396 					partitioned_file_close(
2397 							param.image_file);
2398 					return 1;
2399 				}
2400 			}
2401 		}
2402 
2403 		partitioned_file_close(param.image_file);
2404 		return 0;
2405 	}
2406 
2407 	ERROR("Unknown command '%s'.\n", cmd);
2408 	usage(argv[0]);
2409 	return 1;
2410 }
2411