1 /* CBFS Image Manipulation */
2 /* SPDX-License-Identifier: GPL-2.0-only */
11 #include <commonlib/endian.h>
15 #include "cbfs_image.h"
16 #include "elfparsing.h"
19 /* Even though the file-adding functions---cbfs_add_entry() and
20 * cbfs_add_entry_at()---perform their sizing checks against the beginning of
21 * the subsequent section rather than a stable recorded value such as an empty
22 * file header's len field, it's possible to prove two interesting properties
23 * about their behavior:
24 * - Placing a new file within an empty entry located below an existing file
25 * entry will never leave an aligned flash address containing neither the
26 * beginning of a file header nor part of a file.
27 * - Placing a new file in an empty entry at the very end of the image such
28 * that it fits, but leaves no room for a final header, is guaranteed not to
29 * change the total amount of space for entries, even if that new file is
30 * later removed from the CBFS.
31 * These properties are somewhat nonobvious from the implementation, so the
32 * reader is encouraged to blame this comment and examine the full proofs
33 * in the commit message before making significant changes that would risk
34 * removing said guarantees.
37 static const char *lookup_name_by_type(const struct typedesc_t
*desc
, uint32_t type
,
38 const char *default_value
)
41 for (i
= 0; desc
[i
].name
; i
++)
42 if (desc
[i
].type
== type
)
47 static int lookup_type_by_name(const struct typedesc_t
*desc
, const char *name
)
50 for (i
= 0; desc
[i
].name
&& strcasecmp(name
, desc
[i
].name
); ++i
);
51 return desc
[i
].name
? (int)desc
[i
].type
: -1;
54 static const char *get_cbfs_entry_type_name(uint32_t type
)
56 return lookup_name_by_type(filetypes
, type
, "(unknown)");
59 int cbfs_parse_comp_algo(const char *name
)
61 return lookup_type_by_name(types_cbfs_compression
, name
);
66 size_t cbfs_calculate_file_header_size(const char *name
)
68 return (sizeof(struct cbfs_file
) +
69 align_up(strlen(name
) + 1, CBFS_ATTRIBUTE_ALIGN
));
72 /* Only call on legacy CBFSes possessing a master header. */
73 static int cbfs_fix_legacy_size(struct cbfs_image
*image
, char *hdr_loc
)
76 assert(cbfs_is_legacy_cbfs(image
));
77 // A bug in old cbfstool may produce extra few bytes (by alignment) and
78 // cause cbfstool to overwrite things after free space -- which is
79 // usually CBFS header on x86. We need to workaround that.
80 // Except when we run across a file that contains the actual header,
81 // in which case this image is a safe, new-style
82 // `cbfstool add-master-header` based image.
84 struct cbfs_file
*entry
, *first
= NULL
, *last
= NULL
;
85 for (first
= entry
= cbfs_find_first_entry(image
);
86 entry
&& cbfs_is_valid_entry(image
, entry
);
87 entry
= cbfs_find_next_entry(image
, entry
)) {
88 /* Is the header guarded by a CBFS file entry? Then exit */
89 if (((char *)entry
) + be32toh(entry
->offset
) == hdr_loc
)
93 if ((char *)first
< (char *)hdr_loc
&&
94 (char *)entry
> (char *)hdr_loc
) {
95 WARN("CBFS image was created with old cbfstool with size bug. "
96 "Fixing size in last entry...\n");
97 last
->len
= htobe32(be32toh(last
->len
) - image
->header
.align
);
98 DEBUG("Last entry has been changed from 0x%x to 0x%x.\n",
99 cbfs_get_entry_addr(image
, entry
),
100 cbfs_get_entry_addr(image
,
101 cbfs_find_next_entry(image
, last
)));
106 void cbfs_put_header(void *dest
, const struct cbfs_header
*header
)
108 struct buffer outheader
;
110 outheader
.data
= dest
;
113 xdr_be
.put32(&outheader
, header
->magic
);
114 xdr_be
.put32(&outheader
, header
->version
);
115 xdr_be
.put32(&outheader
, header
->romsize
);
116 xdr_be
.put32(&outheader
, header
->bootblocksize
);
117 xdr_be
.put32(&outheader
, header
->align
);
118 xdr_be
.put32(&outheader
, header
->offset
);
119 xdr_be
.put32(&outheader
, header
->architecture
);
122 static void cbfs_decode_payload_segment(struct cbfs_payload_segment
*output
,
123 struct cbfs_payload_segment
*input
)
125 struct buffer seg
= {
126 .data
= (void *)input
,
127 .size
= sizeof(*input
),
129 output
->type
= xdr_be
.get32(&seg
);
130 output
->compression
= xdr_be
.get32(&seg
);
131 output
->offset
= xdr_be
.get32(&seg
);
132 output
->load_addr
= xdr_be
.get64(&seg
);
133 output
->len
= xdr_be
.get32(&seg
);
134 output
->mem_len
= xdr_be
.get32(&seg
);
135 assert(seg
.size
== 0);
138 static int cbfs_file_get_compression_info(struct cbfs_file
*entry
,
139 uint32_t *decompressed_size
)
141 unsigned int compression
= CBFS_COMPRESS_NONE
;
142 if (decompressed_size
)
143 *decompressed_size
= be32toh(entry
->len
);
144 for (struct cbfs_file_attribute
*attr
= cbfs_file_first_attr(entry
);
146 attr
= cbfs_file_next_attr(entry
, attr
)) {
147 if (be32toh(attr
->tag
) == CBFS_FILE_ATTR_TAG_COMPRESSION
) {
148 struct cbfs_file_attr_compression
*ac
=
149 (struct cbfs_file_attr_compression
*)attr
;
150 compression
= be32toh(ac
->compression
);
151 if (decompressed_size
)
153 be32toh(ac
->decompressed_size
);
159 static struct cbfs_file_attr_hash
*cbfs_file_get_next_hash(
160 struct cbfs_file
*entry
, struct cbfs_file_attr_hash
*cur
)
162 struct cbfs_file_attribute
*attr
= (struct cbfs_file_attribute
*)cur
;
164 attr
= cbfs_file_first_attr(entry
);
167 if (be32toh(attr
->tag
) == CBFS_FILE_ATTR_TAG_HASH
)
168 return (struct cbfs_file_attr_hash
*)attr
;
170 while ((attr
= cbfs_file_next_attr(entry
, attr
)) != NULL
) {
171 if (be32toh(attr
->tag
) == CBFS_FILE_ATTR_TAG_HASH
)
172 return (struct cbfs_file_attr_hash
*)attr
;
177 void cbfs_get_header(struct cbfs_header
*header
, void *src
)
179 struct buffer outheader
;
181 outheader
.data
= src
; /* We're not modifying the data */
184 header
->magic
= xdr_be
.get32(&outheader
);
185 header
->version
= xdr_be
.get32(&outheader
);
186 header
->romsize
= xdr_be
.get32(&outheader
);
187 header
->bootblocksize
= xdr_be
.get32(&outheader
);
188 header
->align
= xdr_be
.get32(&outheader
);
189 header
->offset
= xdr_be
.get32(&outheader
);
190 header
->architecture
= xdr_be
.get32(&outheader
);
193 int cbfs_image_create(struct cbfs_image
*image
, size_t entries_size
)
196 assert(image
->buffer
.data
);
198 size_t empty_header_len
= cbfs_calculate_file_header_size("");
199 uint32_t entries_offset
= 0;
200 uint32_t align
= CBFS_ALIGNMENT
;
201 if (image
->has_header
) {
202 entries_offset
= image
->header
.offset
;
204 if (entries_offset
> image
->buffer
.size
) {
205 ERROR("CBFS file entries are located outside CBFS itself\n");
209 align
= image
->header
.align
;
212 // This attribute must be given in order to prove that this module
213 // correctly preserves certain CBFS properties. See the block comment
214 // near the top of this file (and the associated commit message).
215 if (align
< empty_header_len
) {
216 ERROR("CBFS must be aligned to at least %zu bytes\n",
221 if (entries_size
> image
->buffer
.size
- entries_offset
) {
222 ERROR("CBFS doesn't have enough space to fit its file entries\n");
226 if (empty_header_len
> entries_size
) {
227 ERROR("CBFS is too small to fit any header\n");
230 struct cbfs_file
*entry_header
=
231 (struct cbfs_file
*)(image
->buffer
.data
+ entries_offset
);
232 // This alignment is necessary in order to prove that this module
233 // correctly preserves certain CBFS properties. See the block comment
234 // near the top of this file (and the associated commit message).
235 entries_size
-= entries_size
% align
;
237 size_t capacity
= entries_size
- empty_header_len
;
238 LOG("Created CBFS (capacity = %zu bytes)\n", capacity
);
239 return cbfs_create_empty_entry(entry_header
, CBFS_TYPE_NULL
,
243 int cbfs_legacy_image_create(struct cbfs_image
*image
,
244 uint32_t architecture
,
246 struct buffer
*bootblock
,
247 uint32_t bootblock_offset
,
248 uint32_t header_offset
,
249 uint32_t entries_offset
)
252 assert(image
->buffer
.data
);
258 size_t size
= image
->buffer
.size
;
260 DEBUG("cbfs_image_create: bootblock=0x%x+0x%zx, "
261 "header=0x%x+0x%zx, entries_offset=0x%x\n",
262 bootblock_offset
, bootblock
->size
, header_offset
,
263 sizeof(image
->header
), entries_offset
);
265 DEBUG("cbfs_create_image: (real offset) bootblock=0x%x, "
266 "header=0x%x, entries_offset=0x%x\n",
267 bootblock_offset
, header_offset
, entries_offset
);
270 if (bootblock_offset
+ bootblock
->size
> size
) {
271 ERROR("Bootblock (0x%x+0x%zx) exceed ROM size (0x%zx)\n",
272 bootblock_offset
, bootblock
->size
, size
);
275 if (entries_offset
> bootblock_offset
&&
276 entries_offset
< bootblock
->size
) {
277 ERROR("Bootblock (0x%x+0x%zx) overlap CBFS data (0x%x)\n",
278 bootblock_offset
, bootblock
->size
, entries_offset
);
281 memcpy(image
->buffer
.data
+ bootblock_offset
, bootblock
->data
,
285 if (header_offset
+ sizeof(image
->header
) > size
- sizeof(int32_t)) {
286 ERROR("Header (0x%x+0x%zx) exceed ROM size (0x%zx)\n",
287 header_offset
, sizeof(image
->header
), size
);
290 image
->header
.magic
= CBFS_HEADER_MAGIC
;
291 image
->header
.version
= CBFS_HEADER_VERSION
;
292 image
->header
.romsize
= size
;
293 image
->header
.bootblocksize
= bootblock
->size
;
294 image
->header
.align
= align
;
295 image
->header
.offset
= entries_offset
;
296 image
->header
.architecture
= architecture
;
298 header_loc
= (image
->buffer
.data
+ header_offset
);
299 cbfs_put_header(header_loc
, &image
->header
);
300 image
->has_header
= true;
302 // The last 4 byte of the image contain the relative offset from the end
303 // of the image to the master header as a 32-bit signed integer. x86
304 // relies on this also being its (memory-mapped, top-aligned) absolute
305 // 32-bit address by virtue of how two's complement numbers work.
306 assert(size
% sizeof(int32_t) == 0);
307 rel_offset
= (int32_t *)(image
->buffer
.data
+ size
- sizeof(int32_t));
308 *rel_offset
= header_offset
- size
;
311 if (align_up(entries_offset
, align
) != entries_offset
) {
312 ERROR("Offset (0x%x) must be aligned to 0x%x.\n",
313 entries_offset
, align
);
316 // To calculate available length, find
317 // e = min(bootblock, header, rel_offset) where e > entries_offset.
318 cbfs_len
= size
- sizeof(int32_t);
319 if (bootblock_offset
> entries_offset
&& bootblock_offset
< cbfs_len
)
320 cbfs_len
= bootblock_offset
;
321 if (header_offset
> entries_offset
&& header_offset
< cbfs_len
)
322 cbfs_len
= header_offset
;
324 if (cbfs_image_create(image
, cbfs_len
- entries_offset
))
329 int cbfs_image_from_buffer(struct cbfs_image
*out
, struct buffer
*in
,
336 buffer_clone(&out
->buffer
, in
);
337 out
->has_header
= false;
339 if (cbfs_is_valid_cbfs(out
)) {
343 void *header_loc
= cbfs_find_header(in
->data
, in
->size
, offset
);
345 cbfs_get_header(&out
->header
, header_loc
);
346 out
->has_header
= true;
347 cbfs_fix_legacy_size(out
, header_loc
);
349 } else if (offset
!= HEADER_OFFSET_UNKNOWN
) {
350 ERROR("The -H switch is only valid on legacy images having CBFS master headers.\n");
352 ERROR("Selected image region is not a valid CBFS.\n");
356 int cbfs_copy_instance(struct cbfs_image
*image
, struct buffer
*dst
)
360 struct cbfs_file
*src_entry
, *dst_entry
;
362 ssize_t last_entry_size
;
364 size_t copy_end
= buffer_size(dst
);
366 align
= CBFS_ALIGNMENT
;
368 dst_entry
= (struct cbfs_file
*)buffer_get(dst
);
370 /* Copy non-empty files */
371 for (src_entry
= cbfs_find_first_entry(image
);
372 src_entry
&& cbfs_is_valid_entry(image
, src_entry
);
373 src_entry
= cbfs_find_next_entry(image
, src_entry
)) {
376 if ((src_entry
->type
== htobe32(CBFS_TYPE_NULL
)) ||
377 (src_entry
->type
== htobe32(CBFS_TYPE_CBFSHEADER
)) ||
378 (src_entry
->type
== htobe32(CBFS_TYPE_DELETED
)))
381 entry_size
= htobe32(src_entry
->len
) + htobe32(src_entry
->offset
);
382 memcpy(dst_entry
, src_entry
, entry_size
);
383 dst_entry
= (struct cbfs_file
*)(
384 (uintptr_t)dst_entry
+ align_up(entry_size
, align
));
386 if ((size_t)((uint8_t *)dst_entry
- (uint8_t *)buffer_get(dst
))
388 ERROR("Ran out of room in copy region.\n");
393 /* Last entry size is all the room above it, except for top 4 bytes
394 * which may be used by the master header pointer. This messes with
395 * the ability to stash something "top-aligned" into the region, but
396 * keeps things simpler. */
397 last_entry_size
= copy_end
-
398 ((uint8_t *)dst_entry
- (uint8_t *)buffer_get(dst
)) -
399 cbfs_calculate_file_header_size("") - sizeof(int32_t);
401 if (last_entry_size
< 0)
402 WARN("No room to create the last entry!\n");
404 return cbfs_create_empty_entry(dst_entry
, CBFS_TYPE_NULL
,
405 last_entry_size
, "");
410 int cbfs_expand_to_region(struct buffer
*region
)
412 if (buffer_get(region
) == NULL
)
415 struct cbfs_image image
;
416 memset(&image
, 0, sizeof(image
));
417 if (cbfs_image_from_buffer(&image
, region
, HEADER_OFFSET_UNKNOWN
)) {
418 ERROR("reading CBFS failed!\n");
422 uint32_t region_sz
= buffer_size(region
);
424 struct cbfs_file
*entry
;
425 for (entry
= buffer_get(region
);
426 cbfs_is_valid_entry(&image
, entry
);
427 entry
= cbfs_find_next_entry(&image
, entry
)) {
428 /* just iterate through */
431 /* entry now points to the first aligned address after the last valid
432 * file header. That's either outside the image or exactly the place
433 * where we need to create a new file.
435 int last_entry_size
= region_sz
-
436 ((uint8_t *)entry
- (uint8_t *)buffer_get(region
)) -
437 cbfs_calculate_file_header_size("") - sizeof(int32_t);
439 if (last_entry_size
> 0) {
440 if (cbfs_create_empty_entry(entry
, CBFS_TYPE_NULL
,
441 last_entry_size
, ""))
444 /* If the last entry was an empty file, merge them. */
445 cbfs_legacy_walk(&image
, cbfs_merge_empty_entry
, NULL
);
451 int cbfs_truncate_space(struct buffer
*region
, uint32_t *size
)
453 if (buffer_get(region
) == NULL
)
456 struct cbfs_image image
;
457 memset(&image
, 0, sizeof(image
));
458 if (cbfs_image_from_buffer(&image
, region
, HEADER_OFFSET_UNKNOWN
)) {
459 ERROR("reading CBFS failed!\n");
463 struct cbfs_file
*entry
, *trailer
;
464 for (trailer
= entry
= buffer_get(region
);
465 cbfs_is_valid_entry(&image
, entry
);
467 entry
= cbfs_find_next_entry(&image
, entry
)) {
468 /* just iterate through */
471 /* trailer now points to the last valid CBFS entry's header.
472 * If that file is empty, remove it and report its header's offset as
475 if ((strlen(trailer
->filename
) != 0) &&
476 (trailer
->type
!= htobe32(CBFS_TYPE_NULL
)) &&
477 (trailer
->type
!= htobe32(CBFS_TYPE_DELETED
))) {
478 /* nothing to truncate. Return de-facto CBFS size in case it
479 * was already truncated. */
480 *size
= (uint8_t *)entry
- (uint8_t *)buffer_get(region
);
483 *size
= (uint8_t *)trailer
- (uint8_t *)buffer_get(region
);
484 memset(trailer
, 0xff, buffer_size(region
) - *size
);
489 static size_t cbfs_file_entry_metadata_size(const struct cbfs_file
*f
)
491 return be32toh(f
->offset
);
494 static size_t cbfs_file_entry_data_size(const struct cbfs_file
*f
)
496 return be32toh(f
->len
);
499 static size_t cbfs_file_entry_size(const struct cbfs_file
*f
)
501 return cbfs_file_entry_metadata_size(f
) + cbfs_file_entry_data_size(f
);
504 int cbfs_compact_instance(struct cbfs_image
*image
)
508 struct cbfs_file
*prev
;
509 struct cbfs_file
*cur
;
511 /* The prev entry will always be an empty entry. */
515 * Note: this function does not honor alignment or fixed location files.
516 * It's behavior is akin to cbfs_copy_instance() in that it expects
517 * the caller to understand the ramifications of compacting a
518 * fragmented CBFS image.
521 for (cur
= cbfs_find_first_entry(image
);
522 cur
&& cbfs_is_valid_entry(image
, cur
);
523 cur
= cbfs_find_next_entry(image
, cur
)) {
526 size_t empty_metadata_size
;
529 /* Current entry is empty. Kepp track of it. */
530 if (cur
->type
== CBFS_TYPE_NULL
|| cur
->type
== CBFS_TYPE_DELETED
) {
535 /* Need to ensure the previous entry is an empty one. */
539 /* At this point prev is an empty entry. Put the non-empty
540 * file in prev's location. Then add a new empty entry. This
541 * essentialy bubbles empty entries towards the end. */
543 prev_size
= cbfs_file_entry_size(prev
);
544 cur_size
= cbfs_file_entry_size(cur
);
547 * Adjust the empty file size by the actual space occupied
548 * bewtween the beginning of the empty file and the non-empty
551 prev_size
+= (cbfs_get_entry_addr(image
, cur
) -
552 cbfs_get_entry_addr(image
, prev
)) - prev_size
;
554 /* Move the non-empty file over the empty file. */
555 memmove(prev
, cur
, cur_size
);
558 * Get location of the empty file. Note that since prev was
559 * overwritten with the non-empty file the previously moved
560 * file needs to be used to calculate the empty file's location.
562 cur
= cbfs_find_next_entry(image
, prev
);
565 * The total space to work with for swapping the 2 entries
566 * consists of the 2 files' sizes combined. However, the
567 * cbfs_file entries start on CBFS_ALIGNMENT boundaries.
568 * Because of this the empty file size may end up smaller
569 * because of the non-empty file's metadata and data length.
571 * Calculate the spill size which is the amount of data lost
572 * due to the alignment constraints after moving the non-empty
575 spill_size
= (cbfs_get_entry_addr(image
, cur
) -
576 cbfs_get_entry_addr(image
, prev
)) - cur_size
;
578 empty_metadata_size
= cbfs_calculate_file_header_size("");
580 /* Check if new empty size can contain the metadata. */
581 if (empty_metadata_size
+ spill_size
> prev_size
) {
582 ERROR("Unable to swap '%s' with prev empty entry.\n",
587 /* Update the empty file's size. */
588 prev_size
-= spill_size
+ empty_metadata_size
;
590 /* Create new empty file. */
591 if (cbfs_create_empty_entry(cur
, CBFS_TYPE_NULL
,
595 /* Merge any potential empty entries together. */
596 cbfs_legacy_walk(image
, cbfs_merge_empty_entry
, NULL
);
599 * Since current switched to an empty file keep track of it.
600 * Even if any empty files were merged the empty entry still
601 * starts at previously calculated location.
609 int cbfs_image_delete(struct cbfs_image
*image
)
614 buffer_delete(&image
->buffer
);
618 /* Tries to add an entry with its data (CBFS_SUBHEADER) at given offset. */
619 static int cbfs_add_entry_at(struct cbfs_image
*image
,
620 struct cbfs_file
*entry
,
622 uint32_t content_offset
,
623 const struct cbfs_file
*header
,
624 const size_t len_align
)
626 struct cbfs_file
*next
= cbfs_find_next_entry(image
, entry
);
627 uint32_t addr
= cbfs_get_entry_addr(image
, entry
),
628 addr_next
= cbfs_get_entry_addr(image
, next
);
629 uint32_t min_entry_size
= cbfs_calculate_file_header_size("");
630 uint32_t len
, header_offset
;
631 uint32_t align
= image
->has_header
? image
->header
.align
:
633 uint32_t header_size
= be32toh(header
->offset
);
635 header_offset
= content_offset
- header_size
;
636 if (header_offset
% align
)
637 header_offset
-= header_offset
% align
;
638 if (header_offset
< addr
) {
639 ERROR("No space to hold cbfs_file header.");
643 // Process buffer BEFORE content_offset.
644 if (header_offset
- addr
> min_entry_size
) {
645 DEBUG("|min|...|header|content|... <create new entry>\n");
646 len
= header_offset
- addr
- min_entry_size
;
647 if (cbfs_create_empty_entry(entry
, CBFS_TYPE_NULL
, len
, ""))
649 if (verbose
> 1) cbfs_print_entry_info(image
, entry
, stderr
);
650 entry
= cbfs_find_next_entry(image
, entry
);
651 addr
= cbfs_get_entry_addr(image
, entry
);
654 len
= content_offset
- addr
- header_size
;
655 memcpy(entry
, header
, header_size
);
658 * The header moved backwards a bit to accommodate cbfs_file
659 * alignment requirements, so patch up ->offset to still point
660 * to file data. Move attributes forward so the end of the
661 * attribute list still matches the end of the metadata.
663 uint32_t offset
= be32toh(entry
->offset
);
664 uint32_t attrs
= be32toh(entry
->attributes_offset
);
665 DEBUG("|..|header|content|... <use offset to create entry>\n");
666 DEBUG("before: attr_offset=0x%x, offset=0x%x\n", attrs
, offset
);
668 memset((uint8_t *)entry
+ offset
, 0, len
);
670 uint8_t *p
= (uint8_t *)entry
+ attrs
;
671 memmove(p
+ len
, p
, offset
- attrs
);
674 entry
->attributes_offset
= htobe32(attrs
);
677 entry
->offset
= htobe32(offset
);
678 DEBUG("after: attr_offset=0x%x, offset=0x%x\n", attrs
, offset
);
681 // Ready to fill data into entry.
682 DEBUG("content_offset: 0x%x, entry location: %x\n",
683 content_offset
, (int)((char*)CBFS_SUBHEADER(entry
) -
684 image
->buffer
.data
));
685 assert((char*)CBFS_SUBHEADER(entry
) - image
->buffer
.data
==
686 (ptrdiff_t)content_offset
);
687 memcpy(CBFS_SUBHEADER(entry
), data
, be32toh(entry
->len
));
688 if (verbose
> 1) cbfs_print_entry_info(image
, entry
, stderr
);
690 // Align the length to a multiple of len_align
692 ((be32toh(entry
->offset
) + be32toh(entry
->len
)) % len_align
)) {
693 size_t off
= (be32toh(entry
->offset
) + be32toh(entry
->len
)) % len_align
;
694 entry
->len
= htobe32(be32toh(entry
->len
) + len_align
- off
);
697 // Process buffer AFTER entry.
698 entry
= cbfs_find_next_entry(image
, entry
);
699 addr
= cbfs_get_entry_addr(image
, entry
);
700 if (addr
== addr_next
)
703 assert(addr
< addr_next
);
704 if (addr_next
- addr
< min_entry_size
) {
705 DEBUG("No need for new \"empty\" entry\n");
706 /* No need to increase the size of the just
707 * stored file to extend to next file. Alignment
708 * of next file takes care of this.
713 len
= addr_next
- addr
- min_entry_size
;
714 /* keep space for master header pointer */
715 if ((uint8_t *)entry
+ min_entry_size
+ len
>
716 (uint8_t *)buffer_get(&image
->buffer
) +
717 buffer_size(&image
->buffer
) - sizeof(int32_t)) {
718 len
-= sizeof(int32_t);
720 if (cbfs_create_empty_entry(entry
, CBFS_TYPE_NULL
, len
, ""))
722 if (verbose
> 1) cbfs_print_entry_info(image
, entry
, stderr
);
726 int cbfs_add_entry(struct cbfs_image
*image
, struct buffer
*buffer
,
727 uint32_t content_offset
,
728 struct cbfs_file
*header
,
729 const size_t len_align
)
733 assert(buffer
->data
);
734 assert(!IS_HOST_SPACE_ADDRESS(content_offset
));
736 const char *name
= header
->filename
;
738 /* This is so special rows in cbfstool print -k -v output stay unambiguous. */
739 if (name
[0] == '[') {
740 ERROR("CBFS file name `%s` must not start with `[`\n", name
);
745 uint32_t addr
, addr_next
;
746 struct cbfs_file
*entry
, *next
;
748 uint32_t header_size
= be32toh(header
->offset
);
750 need_size
= header_size
+ buffer
->size
;
751 DEBUG("cbfs_add_entry('%s'@0x%x) => need_size = %u+%zu=%u\n",
752 name
, content_offset
, header_size
, buffer
->size
, need_size
);
754 // Merge empty entries.
755 DEBUG("(trying to merge empty entries...)\n");
756 cbfs_legacy_walk(image
, cbfs_merge_empty_entry
, NULL
);
758 for (entry
= cbfs_find_first_entry(image
);
759 entry
&& cbfs_is_valid_entry(image
, entry
);
760 entry
= cbfs_find_next_entry(image
, entry
)) {
762 entry_type
= be32toh(entry
->type
);
763 if (entry_type
!= CBFS_TYPE_NULL
)
766 addr
= cbfs_get_entry_addr(image
, entry
);
767 next
= cbfs_find_next_entry(image
, entry
);
768 addr_next
= cbfs_get_entry_addr(image
, next
);
770 DEBUG("cbfs_add_entry: space at 0x%x+0x%x(%d) bytes\n",
771 addr
, addr_next
- addr
, addr_next
- addr
);
773 /* Will the file fit? Don't yet worry if we have space for a new
774 * "empty" entry. We take care of that later.
776 if (addr
+ need_size
> addr_next
)
779 // Test for complicated cases
780 if (content_offset
> 0) {
781 if (addr_next
< content_offset
) {
782 DEBUG("Not for specified offset yet");
784 } else if (addr
> content_offset
) {
785 DEBUG("Exceed specified content_offset.");
787 } else if (addr
+ header_size
> content_offset
) {
788 ERROR("Not enough space for header.\n");
790 } else if (content_offset
+ buffer
->size
> addr_next
) {
791 ERROR("Not enough space for content.\n");
796 // TODO there are more few tricky cases that we may
797 // want to fit by altering offset.
799 if (content_offset
== 0) {
800 // we tested every condition earlier under which
801 // placing the file there might fail
802 content_offset
= addr
+ header_size
;
805 DEBUG("section 0x%x+0x%x for content_offset 0x%x.\n",
806 addr
, addr_next
- addr
, content_offset
);
808 if (cbfs_add_entry_at(image
, entry
, buffer
->data
,
809 content_offset
, header
, len_align
) == 0) {
815 ERROR("Could not add [%s, %zd bytes (%zd KB)@0x%x]; too big?\n",
816 buffer
->name
, buffer
->size
, buffer
->size
/ 1024, content_offset
);
820 struct cbfs_file
*cbfs_get_entry(struct cbfs_image
*image
, const char *name
)
822 struct cbfs_file
*entry
;
823 for (entry
= cbfs_find_first_entry(image
);
824 entry
&& cbfs_is_valid_entry(image
, entry
);
825 entry
= cbfs_find_next_entry(image
, entry
)) {
826 if (strcasecmp(entry
->filename
, name
) == 0) {
827 DEBUG("cbfs_get_entry: found %s\n", name
);
834 static int cbfs_payload_decompress(struct cbfs_payload_segment
*segments
,
835 struct buffer
*buff
, int num_seg
)
837 struct buffer new_buffer
;
838 struct buffer seg_buffer
;
843 decomp_func_ptr decompress
;
845 new_offset
= num_seg
* sizeof(*segments
);
846 new_buff_sz
= num_seg
* sizeof(*segments
);
848 /* Find out and allocate the amount of memory occupied
849 * by the binary data */
850 for (int i
= 0; i
< num_seg
; i
++)
851 new_buff_sz
+= segments
[i
].mem_len
;
853 if (buffer_create(&new_buffer
, new_buff_sz
, "decompressed_buff"))
856 in_ptr
= buffer_get(buff
) + new_offset
;
857 out_ptr
= buffer_get(&new_buffer
) + new_offset
;
859 for (int i
= 0; i
< num_seg
; i
++) {
863 /* Segments BSS and ENTRY do not have binary data. */
864 if (segments
[i
].type
== PAYLOAD_SEGMENT_BSS
||
865 segments
[i
].type
== PAYLOAD_SEGMENT_ENTRY
) {
867 } else if (segments
[i
].type
== PAYLOAD_SEGMENT_DEPRECATED_PARAMS
) {
868 memcpy(out_ptr
, in_ptr
, segments
[i
].len
);
869 segments
[i
].offset
= new_offset
;
870 new_offset
+= segments
[i
].len
;
871 in_ptr
+= segments
[i
].len
;
872 out_ptr
+= segments
[i
].len
;
873 segments
[i
].compression
= CBFS_COMPRESS_NONE
;
877 /* The payload uses an unknown compression algorithm. */
878 decompress
= decompression_function(segments
[i
].compression
);
879 if (decompress
== NULL
) {
880 ERROR("Unknown decompression algorithm: %u\n",
881 segments
[i
].compression
);
885 if (buffer_create(&tbuff
, segments
[i
].mem_len
, "segment")) {
886 buffer_delete(&new_buffer
);
890 if (decompress(in_ptr
, segments
[i
].len
, buffer_get(&tbuff
),
891 (int) buffer_size(&tbuff
),
893 ERROR("Couldn't decompress payload segment %u\n", i
);
894 buffer_delete(&new_buffer
);
895 buffer_delete(&tbuff
);
899 memcpy(out_ptr
, buffer_get(&tbuff
), decomp_size
);
901 in_ptr
+= segments
[i
].len
;
903 /* Update the offset of the segment. */
904 segments
[i
].offset
= new_offset
;
905 /* True decompressed size is just the data size. No metadata */
906 segments
[i
].len
= decomp_size
;
907 /* Segment is not compressed. */
908 segments
[i
].compression
= CBFS_COMPRESS_NONE
;
910 /* Update the offset and output buffer pointer. */
911 new_offset
+= decomp_size
;
912 out_ptr
+= decomp_size
;
914 buffer_delete(&tbuff
);
917 buffer_splice(&seg_buffer
, &new_buffer
, 0, 0);
918 xdr_segs(&seg_buffer
, segments
, num_seg
);
926 static int init_elf_from_arch(Elf64_Ehdr
*ehdr
, uint32_t cbfs_arch
)
933 case CBFS_ARCHITECTURE_X86
:
934 endian
= ELFDATA2LSB
;
938 case CBFS_ARCHITECTURE_ARM
:
939 endian
= ELFDATA2LSB
;
943 case CBFS_ARCHITECTURE_AARCH64
:
944 endian
= ELFDATA2LSB
;
946 machine
= EM_AARCH64
;
948 case CBFS_ARCHITECTURE_MIPS
:
949 endian
= ELFDATA2LSB
;
953 case CBFS_ARCHITECTURE_RISCV
:
954 endian
= ELFDATA2LSB
;
959 ERROR("Unsupported arch: %x\n", cbfs_arch
);
963 elf_init_eheader(ehdr
, machine
, nbits
, endian
);
967 static int cbfs_stage_make_elf(struct buffer
*buff
, uint32_t arch
,
968 struct cbfs_file
*entry
)
972 struct elf_writer
*ew
;
973 struct buffer elf_out
;
977 if (arch
== CBFS_ARCHITECTURE_UNKNOWN
) {
978 ERROR("You need to specify -m ARCH.\n");
982 struct cbfs_file_attr_stageheader
*stage
= NULL
;
983 for (struct cbfs_file_attribute
*attr
= cbfs_file_first_attr(entry
);
984 attr
!= NULL
; attr
= cbfs_file_next_attr(entry
, attr
)) {
985 if (be32toh(attr
->tag
) == CBFS_FILE_ATTR_TAG_STAGEHEADER
) {
986 stage
= (struct cbfs_file_attr_stageheader
*)attr
;
992 ERROR("Stage header not found for %s\n", entry
->filename
);
996 if (init_elf_from_arch(&ehdr
, arch
))
999 /* Attempt rmodule translation first. */
1000 rmod_ret
= rmodule_stage_to_elf(&ehdr
, buff
);
1003 ERROR("rmodule parsing failed\n");
1005 } else if (rmod_ret
== 0)
1008 /* Rmodule couldn't do anything with the data. Continue on with SELF. */
1010 ehdr
.e_entry
= be64toh(stage
->loadaddr
) + be32toh(stage
->entry_offset
);
1012 ew
= elf_writer_init(&ehdr
);
1014 ERROR("Unable to init ELF writer.\n");
1018 memset(&shdr
, 0, sizeof(shdr
));
1019 shdr
.sh_type
= SHT_PROGBITS
;
1020 shdr
.sh_flags
= SHF_WRITE
| SHF_ALLOC
| SHF_EXECINSTR
;
1021 shdr
.sh_addr
= be64toh(stage
->loadaddr
);
1022 shdr
.sh_size
= buffer_size(buff
);
1023 empty_sz
= be32toh(stage
->memlen
) - buffer_size(buff
);
1025 if (elf_writer_add_section(ew
, &shdr
, buff
, ".program")) {
1026 ERROR("Unable to add ELF section: .program\n");
1027 elf_writer_destroy(ew
);
1031 if (empty_sz
!= 0) {
1034 buffer_init(&b
, NULL
, NULL
, 0);
1035 memset(&shdr
, 0, sizeof(shdr
));
1036 shdr
.sh_type
= SHT_NOBITS
;
1037 shdr
.sh_flags
= SHF_WRITE
| SHF_ALLOC
;
1038 shdr
.sh_addr
= be64toh(stage
->loadaddr
) + buffer_size(buff
);
1039 shdr
.sh_size
= empty_sz
;
1040 if (elf_writer_add_section(ew
, &shdr
, &b
, ".empty")) {
1041 ERROR("Unable to add ELF section: .empty\n");
1042 elf_writer_destroy(ew
);
1047 if (elf_writer_serialize(ew
, &elf_out
)) {
1048 ERROR("Unable to create ELF file from stage.\n");
1049 elf_writer_destroy(ew
);
1053 /* Flip buffer with the created ELF one. */
1054 buffer_delete(buff
);
1057 elf_writer_destroy(ew
);
1062 static int cbfs_payload_make_elf(struct buffer
*buff
, uint32_t arch
,
1063 unused
struct cbfs_file
*entry
)
1067 struct cbfs_payload_segment
*segs
= NULL
;
1068 struct elf_writer
*ew
= NULL
;
1069 struct buffer elf_out
;
1073 if (arch
== CBFS_ARCHITECTURE_UNKNOWN
) {
1074 ERROR("You need to specify -m ARCH.\n");
1078 /* Count the number of segments inside buffer */
1080 uint32_t payload_type
= 0;
1082 struct cbfs_payload_segment
*seg
;
1084 seg
= buffer_get(buff
);
1085 payload_type
= read_be32(&seg
[segments
].type
);
1087 if (payload_type
== PAYLOAD_SEGMENT_CODE
) {
1089 } else if (payload_type
== PAYLOAD_SEGMENT_DATA
) {
1091 } else if (payload_type
== PAYLOAD_SEGMENT_BSS
) {
1093 } else if (payload_type
== PAYLOAD_SEGMENT_DEPRECATED_PARAMS
) {
1095 } else if (payload_type
== PAYLOAD_SEGMENT_ENTRY
) {
1096 /* The last segment in a payload is always ENTRY as
1097 * specified by the parse_elf_to_payload() function.
1098 * Therefore there is no need to continue looking for
1103 ERROR("Unknown payload segment type: %x\n",
1109 segs
= malloc(segments
* sizeof(*segs
));
1111 /* Decode xdr segments */
1112 for (int i
= 0; i
< segments
; i
++) {
1113 struct cbfs_payload_segment
*serialized_seg
= buffer_get(buff
);
1114 xdr_get_seg(&segs
[i
], &serialized_seg
[i
]);
1117 if (cbfs_payload_decompress(segs
, buff
, segments
)) {
1118 ERROR("Failed to decompress payload.\n");
1122 if (init_elf_from_arch(&ehdr
, arch
))
1125 ehdr
.e_entry
= segs
[segments
-1].load_addr
;
1127 ew
= elf_writer_init(&ehdr
);
1129 ERROR("Unable to init ELF writer.\n");
1133 for (int i
= 0; i
< segments
; i
++) {
1134 struct buffer tbuff
;
1135 size_t empty_sz
= 0;
1137 memset(&shdr
, 0, sizeof(shdr
));
1140 if (segs
[i
].type
== PAYLOAD_SEGMENT_CODE
) {
1141 shdr
.sh_type
= SHT_PROGBITS
;
1142 shdr
.sh_flags
= SHF_WRITE
| SHF_ALLOC
| SHF_EXECINSTR
;
1143 shdr
.sh_addr
= segs
[i
].load_addr
;
1144 shdr
.sh_size
= segs
[i
].len
;
1145 empty_sz
= segs
[i
].mem_len
- segs
[i
].len
;
1146 name
= strdup(".text");
1147 buffer_splice(&tbuff
, buff
, segs
[i
].offset
,
1149 } else if (segs
[i
].type
== PAYLOAD_SEGMENT_DATA
) {
1150 shdr
.sh_type
= SHT_PROGBITS
;
1151 shdr
.sh_flags
= SHF_ALLOC
| SHF_WRITE
;
1152 shdr
.sh_addr
= segs
[i
].load_addr
;
1153 shdr
.sh_size
= segs
[i
].len
;
1154 empty_sz
= segs
[i
].mem_len
- segs
[i
].len
;
1155 name
= strdup(".data");
1156 buffer_splice(&tbuff
, buff
, segs
[i
].offset
,
1158 } else if (segs
[i
].type
== PAYLOAD_SEGMENT_BSS
) {
1159 shdr
.sh_type
= SHT_NOBITS
;
1160 shdr
.sh_flags
= SHF_ALLOC
| SHF_WRITE
;
1161 shdr
.sh_addr
= segs
[i
].load_addr
;
1162 shdr
.sh_size
= segs
[i
].len
;
1163 name
= strdup(".bss");
1164 buffer_splice(&tbuff
, buff
, 0, 0);
1165 } else if (segs
[i
].type
== PAYLOAD_SEGMENT_DEPRECATED_PARAMS
) {
1166 shdr
.sh_type
= SHT_NOTE
;
1168 shdr
.sh_size
= segs
[i
].len
;
1169 name
= strdup(".note.pinfo");
1170 buffer_splice(&tbuff
, buff
, segs
[i
].offset
,
1172 } else if (segs
[i
].type
== PAYLOAD_SEGMENT_ENTRY
) {
1175 ERROR("unknown ELF segment type\n");
1180 ERROR("out of memory\n");
1184 if (elf_writer_add_section(ew
, &shdr
, &tbuff
, name
)) {
1185 ERROR("Unable to add ELF section: %s\n", name
);
1191 if (empty_sz
!= 0) {
1194 buffer_init(&b
, NULL
, NULL
, 0);
1195 memset(&shdr
, 0, sizeof(shdr
));
1196 shdr
.sh_type
= SHT_NOBITS
;
1197 shdr
.sh_flags
= SHF_WRITE
| SHF_ALLOC
;
1198 shdr
.sh_addr
= segs
[i
].load_addr
+ segs
[i
].len
;
1199 shdr
.sh_size
= empty_sz
;
1200 name
= strdup(".empty");
1202 ERROR("out of memory\n");
1205 if (elf_writer_add_section(ew
, &shdr
, &b
, name
)) {
1206 ERROR("Unable to add ELF section: %s\n", name
);
1214 if (elf_writer_serialize(ew
, &elf_out
)) {
1215 ERROR("Unable to create ELF file from payload.\n");
1219 /* Flip buffer with the created ELF one. */
1220 buffer_delete(buff
);
1226 elf_writer_destroy(ew
);
1230 int cbfs_export_entry(struct cbfs_image
*image
, const char *entry_name
,
1231 const char *filename
, uint32_t arch
, bool do_processing
)
1233 struct cbfs_file
*entry
= cbfs_get_entry(image
, entry_name
);
1234 struct buffer buffer
;
1236 ERROR("File not found: %s\n", entry_name
);
1240 unsigned int compressed_size
= be32toh(entry
->len
);
1241 unsigned int decompressed_size
= 0;
1242 unsigned int compression
= cbfs_file_get_compression_info(entry
,
1243 &decompressed_size
);
1244 unsigned int buffer_len
;
1245 decomp_func_ptr decompress
;
1247 if (do_processing
) {
1248 decompress
= decompression_function(compression
);
1250 ERROR("looking up decompression routine failed\n");
1253 buffer_len
= decompressed_size
;
1255 /* Force nop decompression */
1256 decompress
= decompression_function(CBFS_COMPRESS_NONE
);
1257 buffer_len
= compressed_size
;
1260 LOG("Found file %.30s at 0x%x, type %.12s, compressed %d, size %d\n",
1261 entry_name
, cbfs_get_entry_addr(image
, entry
),
1262 get_cbfs_entry_type_name(be32toh(entry
->type
)), compressed_size
,
1265 buffer_init(&buffer
, strdup("(cbfs_export_entry)"), NULL
, 0);
1266 buffer
.data
= malloc(buffer_len
);
1267 buffer
.size
= buffer_len
;
1269 if (decompress(CBFS_SUBHEADER(entry
), compressed_size
,
1270 buffer
.data
, buffer
.size
, NULL
)) {
1271 ERROR("decompression failed for %s\n", entry_name
);
1272 buffer_delete(&buffer
);
1277 * We want to export stages and payloads as ELFs, not with coreboot's
1278 * custom stage/SELF binary formats, so we need to do extra processing
1279 * to turn them back into an ELF.
1281 if (do_processing
) {
1282 int (*make_elf
)(struct buffer
*, uint32_t,
1283 struct cbfs_file
*) = NULL
;
1284 switch (be32toh(entry
->type
)) {
1285 case CBFS_TYPE_STAGE
:
1286 make_elf
= cbfs_stage_make_elf
;
1288 case CBFS_TYPE_SELF
:
1289 make_elf
= cbfs_payload_make_elf
;
1292 if (make_elf
&& make_elf(&buffer
, arch
, entry
)) {
1293 ERROR("Failed to write %s into %s.\n",
1294 entry_name
, filename
);
1295 buffer_delete(&buffer
);
1300 if (buffer_write_file(&buffer
, filename
) != 0) {
1301 ERROR("Failed to write %s into %s.\n",
1302 entry_name
, filename
);
1303 buffer_delete(&buffer
);
1307 buffer_delete(&buffer
);
1308 INFO("Successfully dumped the file to: %s\n", filename
);
1312 int cbfs_remove_entry(struct cbfs_image
*image
, const char *name
)
1314 struct cbfs_file
*entry
;
1315 entry
= cbfs_get_entry(image
, name
);
1317 ERROR("CBFS file %s not found.\n", name
);
1320 DEBUG("cbfs_remove_entry: Removed %s @ 0x%x\n",
1321 entry
->filename
, cbfs_get_entry_addr(image
, entry
));
1322 entry
->type
= htobe32(CBFS_TYPE_DELETED
);
1323 cbfs_legacy_walk(image
, cbfs_merge_empty_entry
, NULL
);
1327 int cbfs_print_header_info(struct cbfs_image
*image
)
1329 char *name
= strdup(image
->buffer
.name
);
1331 printf("%s: %zd kB, bootblocksize %d, romsize %d, offset 0x%x\n"
1332 "alignment: %d bytes, architecture: %s\n\n",
1334 image
->buffer
.size
/ 1024,
1335 image
->header
.bootblocksize
,
1336 image
->header
.romsize
,
1337 image
->header
.offset
,
1338 image
->header
.align
,
1339 arch_to_string(image
->header
.architecture
));
1344 static int cbfs_print_stage_info(struct cbfs_file
*entry
, FILE* fp
)
1347 struct cbfs_file_attr_stageheader
*stage
= NULL
;
1348 for (struct cbfs_file_attribute
*attr
= cbfs_file_first_attr(entry
);
1349 attr
!= NULL
; attr
= cbfs_file_next_attr(entry
, attr
)) {
1350 if (be32toh(attr
->tag
) == CBFS_FILE_ATTR_TAG_STAGEHEADER
) {
1351 stage
= (struct cbfs_file_attr_stageheader
*)attr
;
1356 if (stage
== NULL
) {
1357 fprintf(fp
, " ERROR: stage header not found!\n");
1362 " entry: 0x%" PRIx64
", load: 0x%" PRIx64
", "
1364 be64toh(stage
->loadaddr
) + be32toh(stage
->entry_offset
),
1365 be64toh(stage
->loadaddr
),
1366 be32toh(stage
->memlen
));
1370 static int cbfs_print_decoded_payload_segment_info(
1371 struct cbfs_payload_segment
*seg
, FILE *fp
)
1373 /* The input (seg) must be already decoded by
1374 * cbfs_decode_payload_segment.
1376 switch (seg
->type
) {
1377 case PAYLOAD_SEGMENT_CODE
:
1378 case PAYLOAD_SEGMENT_DATA
:
1379 fprintf(fp
, " %s (%s compression, offset: 0x%x, "
1380 "load: 0x%" PRIx64
", length: %d/%d)\n",
1381 (seg
->type
== PAYLOAD_SEGMENT_CODE
?
1383 lookup_name_by_type(types_cbfs_compression
,
1386 seg
->offset
, seg
->load_addr
, seg
->len
,
1390 case PAYLOAD_SEGMENT_ENTRY
:
1391 fprintf(fp
, " entry (0x%" PRIx64
")\n",
1395 case PAYLOAD_SEGMENT_BSS
:
1396 fprintf(fp
, " BSS (address 0x%016" PRIx64
", "
1398 seg
->load_addr
, seg
->len
);
1401 case PAYLOAD_SEGMENT_DEPRECATED_PARAMS
:
1402 fprintf(fp
, " parameters (deprecated)\n");
1406 fprintf(fp
, " 0x%x (%s compression, offset: 0x%x, "
1407 "load: 0x%" PRIx64
", length: %d/%d\n",
1409 lookup_name_by_type(types_cbfs_compression
,
1412 seg
->offset
, seg
->load_addr
, seg
->len
,
1419 int cbfs_print_entry_info(struct cbfs_image
*image
, struct cbfs_file
*entry
,
1422 const char *name
= entry
->filename
;
1423 struct cbfs_payload_segment
*payload
;
1424 FILE *fp
= (FILE *)arg
;
1426 if (!cbfs_is_valid_entry(image
, entry
)) {
1427 ERROR("cbfs_print_entry_info: Invalid entry at 0x%x\n",
1428 cbfs_get_entry_addr(image
, entry
));
1434 unsigned int decompressed_size
= 0;
1435 unsigned int compression
= cbfs_file_get_compression_info(entry
,
1436 &decompressed_size
);
1437 const char *compression_name
= lookup_name_by_type(
1438 types_cbfs_compression
, compression
, "????");
1440 if (compression
== CBFS_COMPRESS_NONE
)
1441 fprintf(fp
, "%-30s 0x%-8x %-12s %8d %-4s\n",
1442 *name
? name
: "(empty)",
1443 cbfs_get_entry_addr(image
, entry
),
1444 get_cbfs_entry_type_name(be32toh(entry
->type
)),
1445 be32toh(entry
->len
),
1449 fprintf(fp
, "%-30s 0x%-8x %-12s %8d %-4s (%d decompressed)\n",
1450 *name
? name
: "(empty)",
1451 cbfs_get_entry_addr(image
, entry
),
1452 get_cbfs_entry_type_name(be32toh(entry
->type
)),
1453 be32toh(entry
->len
),
1461 struct cbfs_file_attr_hash
*attr
= NULL
;
1462 while ((attr
= cbfs_file_get_next_hash(entry
, attr
)) != NULL
) {
1463 size_t hash_len
= vb2_digest_size(attr
->hash
.algo
);
1465 fprintf(fp
, "invalid/unsupported hash algorithm: %d\n",
1469 char *hash_str
= bintohex(attr
->hash
.raw
, hash_len
);
1470 int valid
= vb2_hash_verify(false, CBFS_SUBHEADER(entry
),
1471 be32toh(entry
->len
), &attr
->hash
) == VB2_SUCCESS
;
1472 const char *valid_str
= valid
? "valid" : "invalid";
1474 fprintf(fp
, " hash %s:%s %s\n",
1475 vb2_get_hash_algorithm_name(attr
->hash
.algo
),
1476 hash_str
, valid_str
);
1480 DEBUG(" cbfs_file=0x%x, offset=0x%x, content_address=0x%x+0x%x\n",
1481 cbfs_get_entry_addr(image
, entry
), be32toh(entry
->offset
),
1482 cbfs_get_entry_addr(image
, entry
) + be32toh(entry
->offset
),
1483 be32toh(entry
->len
));
1485 /* note the components of the subheader may be in host order ... */
1486 switch (be32toh(entry
->type
)) {
1487 case CBFS_TYPE_STAGE
:
1488 cbfs_print_stage_info(entry
, fp
);
1491 case CBFS_TYPE_SELF
:
1492 payload
= (struct cbfs_payload_segment
*)
1493 CBFS_SUBHEADER(entry
);
1495 struct cbfs_payload_segment seg
;
1496 cbfs_decode_payload_segment(&seg
, payload
);
1497 cbfs_print_decoded_payload_segment_info(
1499 if (seg
.type
== PAYLOAD_SEGMENT_ENTRY
)
1512 * The format of this output has been stable for many years. Since it is meant
1513 * to be parsed by scripts, we should probably not lightly make changes to it as
1514 * that could break older scripts expecting a different format.
1516 * Until CB:41119, the `-v` flag made no difference when `-k` was selected, so
1517 * presumably no scripts were using that combination. That's why that patch left
1518 * the output for `-k` by itself alone to avoid breaking legacy scripts, and
1519 * expanded `-k -v` to allow an arbitrary number of `<key>:<value>` tokens at
1520 * the end of each row behind the legacy column output. So the new output format
1521 * stability rules should be that `-k` will stay as it is, and `-k -v` may be
1522 * expanded to add more `<key>:<value>` tokens to the end of a row. Scripts that
1523 * want to parse `-k -v` output should be written to gracefully ignore any extra
1524 * such tokens where they don't recognize the key.
1526 * The `-k -v` output may also include extra rows that start with a `[`. These
1527 * do not represent a CBFS file and can instead be used to display data that is
1528 * associated with the CBFS as a whole and not any single file. Currently
1529 * defined are `[FMAP REGION]\t<region name>` and
1530 * `[METADATA HASH]\t<hash>:<algo>`. More may be defined in the future and
1531 * scripts parsing `-k -v` output should be written to gracefully ignore any
1532 * rows starting with `[` that they don't recognize.
1534 * The format for existing `<key:value>` tokens or `[` rows should never be
1535 * changed once they are added.
1537 static int cbfs_print_parseable_entry_info(struct cbfs_image
*image
,
1538 struct cbfs_file
*entry
, void *arg
)
1540 FILE *fp
= (FILE *)arg
;
1544 size_t metadata_size
;
1546 const char *sep
= "\t";
1548 if (!cbfs_is_valid_entry(image
, entry
)) {
1549 ERROR("cbfs_print_entry_info: Invalid entry at 0x%x\n",
1550 cbfs_get_entry_addr(image
, entry
));
1554 name
= entry
->filename
;
1557 type
= get_cbfs_entry_type_name(be32toh(entry
->type
)),
1558 metadata_size
= be32toh(entry
->offset
);
1559 data_size
= be32toh(entry
->len
);
1560 offset
= cbfs_get_entry_addr(image
, entry
);
1562 fprintf(fp
, "%s%s", name
, sep
);
1563 fprintf(fp
, "0x%zx%s", offset
, sep
);
1564 fprintf(fp
, "%s%s", type
, sep
);
1565 fprintf(fp
, "0x%zx%s", metadata_size
, sep
);
1566 fprintf(fp
, "0x%zx%s", data_size
, sep
);
1567 fprintf(fp
, "0x%zx", metadata_size
+ data_size
);
1570 unsigned int decompressed_size
= 0;
1571 unsigned int compression
= cbfs_file_get_compression_info(entry
,
1572 &decompressed_size
);
1573 if (compression
!= CBFS_COMPRESS_NONE
)
1574 fprintf(fp
, "%scomp:%s:0x%x", sep
, lookup_name_by_type(
1575 types_cbfs_compression
, compression
, "????"),
1578 struct cbfs_file_attr_hash
*attr
= NULL
;
1579 while ((attr
= cbfs_file_get_next_hash(entry
, attr
)) != NULL
) {
1580 size_t hash_len
= vb2_digest_size(attr
->hash
.algo
);
1583 char *hash_str
= bintohex(attr
->hash
.raw
, hash_len
);
1584 int valid
= vb2_hash_verify(false, CBFS_SUBHEADER(entry
),
1585 be32toh(entry
->len
), &attr
->hash
) == VB2_SUCCESS
;
1586 fprintf(fp
, "%shash:%s:%s:%s", sep
,
1587 vb2_get_hash_algorithm_name(attr
->hash
.algo
),
1588 hash_str
, valid
? "valid" : "invalid");
1597 void cbfs_print_directory(struct cbfs_image
*image
)
1599 if (cbfs_is_legacy_cbfs(image
))
1600 cbfs_print_header_info(image
);
1601 printf("%-30s %-10s %-12s Size Comp\n", "Name", "Offset", "Type");
1602 cbfs_legacy_walk(image
, cbfs_print_entry_info
, NULL
);
1605 void cbfs_print_parseable_directory(struct cbfs_image
*image
)
1608 const char *header
[] = {
1616 const char *sep
= "\t";
1618 for (i
= 0; i
< ARRAY_SIZE(header
) - 1; i
++)
1619 fprintf(stdout
, "%s%s", header
[i
], sep
);
1620 fprintf(stdout
, "%s\n", header
[i
]);
1621 cbfs_legacy_walk(image
, cbfs_print_parseable_entry_info
, stdout
);
1624 int cbfs_merge_empty_entry(struct cbfs_image
*image
, struct cbfs_file
*entry
,
1627 struct cbfs_file
*next
;
1628 uint32_t next_addr
= 0;
1630 /* We don't return here even if this entry is already empty because we
1631 want to merge the empty entries following after it. */
1633 /* Loop until non-empty entry is found, starting from the current entry.
1634 After the loop, next_addr points to the next non-empty entry. */
1636 while (be32toh(next
->type
) == CBFS_TYPE_DELETED
||
1637 be32toh(next
->type
) == CBFS_TYPE_NULL
) {
1638 next
= cbfs_find_next_entry(image
, next
);
1641 next_addr
= cbfs_get_entry_addr(image
, next
);
1642 if (!cbfs_is_valid_entry(image
, next
))
1643 /* 'next' could be the end of cbfs */
1648 /* Nothing to empty */
1651 /* We can return here if we find only a single empty entry.
1652 For simplicity, we just proceed (and make it empty again). */
1654 /* We're creating one empty entry for combined empty spaces */
1655 uint32_t addr
= cbfs_get_entry_addr(image
, entry
);
1656 size_t len
= next_addr
- addr
- cbfs_calculate_file_header_size("");
1657 DEBUG("join_empty_entry: [0x%x, 0x%x) len=%zu\n", addr
, next_addr
, len
);
1658 return cbfs_create_empty_entry(entry
, CBFS_TYPE_NULL
, len
, "");
1661 int cbfs_legacy_walk(struct cbfs_image
*image
, cbfs_entry_callback callback
,
1665 struct cbfs_file
*entry
;
1666 for (entry
= cbfs_find_first_entry(image
);
1667 entry
&& cbfs_is_valid_entry(image
, entry
);
1668 entry
= cbfs_find_next_entry(image
, entry
)) {
1670 if (callback(image
, entry
, arg
) != 0)
1676 static int cbfs_header_valid(struct cbfs_header
*header
)
1678 if ((be32toh(header
->magic
) == CBFS_HEADER_MAGIC
) &&
1679 ((be32toh(header
->version
) == CBFS_HEADER_VERSION1
) ||
1680 (be32toh(header
->version
) == CBFS_HEADER_VERSION2
)) &&
1681 (be32toh(header
->offset
) < be32toh(header
->romsize
)))
1686 struct cbfs_header
*cbfs_find_header(char *data
, size_t size
,
1687 uint32_t forced_offset
)
1692 struct cbfs_header
*header
, *result
= NULL
;
1694 if (forced_offset
< (size
- sizeof(struct cbfs_header
))) {
1695 /* Check if the forced header is valid. */
1696 header
= (struct cbfs_header
*)(data
+ forced_offset
);
1697 if (cbfs_header_valid(header
))
1702 // Try finding relative offset of master header at end of file first.
1703 rel_offset
= *(int32_t *)(data
+ size
- sizeof(int32_t));
1704 offset
= size
+ rel_offset
;
1705 DEBUG("relative offset: %#zx(-%#zx), offset: %#zx\n",
1706 (size_t)rel_offset
, (size_t)-rel_offset
, offset
);
1708 if (offset
>= size
- sizeof(*header
) ||
1709 !cbfs_header_valid((struct cbfs_header
*)(data
+ offset
))) {
1710 // Some use cases append non-CBFS data to the end of the ROM.
1711 DEBUG("relative offset seems wrong, scanning whole image...\n");
1715 for (; offset
+ sizeof(*header
) < size
; offset
++) {
1716 header
= (struct cbfs_header
*)(data
+ offset
);
1717 if (!cbfs_header_valid(header
))
1723 // Top-aligned images usually have a working relative offset
1724 // field, so this is more likely to happen on bottom-aligned
1725 // ones (where the first header is the "outermost" one)
1726 WARN("Multiple (%d) CBFS headers found, using the first one.\n",
1732 struct cbfs_file
*cbfs_find_first_entry(struct cbfs_image
*image
)
1735 if (image
->has_header
)
1736 /* header.offset is relative to start of flash, not
1737 * start of region, so use it with the full image.
1739 return (struct cbfs_file
*)
1740 (buffer_get_original_backing(&image
->buffer
) +
1741 image
->header
.offset
);
1743 return (struct cbfs_file
*)buffer_get(&image
->buffer
);
1746 struct cbfs_file
*cbfs_find_next_entry(struct cbfs_image
*image
,
1747 struct cbfs_file
*entry
)
1749 uint32_t addr
= cbfs_get_entry_addr(image
, entry
);
1750 int align
= image
->has_header
? image
->header
.align
: CBFS_ALIGNMENT
;
1751 assert(entry
&& cbfs_is_valid_entry(image
, entry
));
1752 addr
+= be32toh(entry
->offset
) + be32toh(entry
->len
);
1753 addr
= align_up(addr
, align
);
1754 return (struct cbfs_file
*)(image
->buffer
.data
+ addr
);
1757 uint32_t cbfs_get_entry_addr(struct cbfs_image
*image
, struct cbfs_file
*entry
)
1759 assert(image
&& image
->buffer
.data
&& entry
);
1760 return (int32_t)((char *)entry
- image
->buffer
.data
);
1763 int cbfs_is_valid_cbfs(struct cbfs_image
*image
)
1765 return buffer_check_magic(&image
->buffer
, CBFS_FILE_MAGIC
,
1766 strlen(CBFS_FILE_MAGIC
));
1769 int cbfs_is_legacy_cbfs(struct cbfs_image
*image
)
1771 return image
->has_header
;
1774 int cbfs_is_valid_entry(struct cbfs_image
*image
, struct cbfs_file
*entry
)
1776 uint32_t offset
= cbfs_get_entry_addr(image
, entry
);
1778 if (offset
>= image
->buffer
.size
)
1781 struct buffer entry_data
;
1782 buffer_clone(&entry_data
, &image
->buffer
);
1783 buffer_seek(&entry_data
, offset
);
1784 return buffer_check_magic(&entry_data
, CBFS_FILE_MAGIC
,
1785 strlen(CBFS_FILE_MAGIC
));
1788 struct cbfs_file
*cbfs_create_file_header(int type
,
1789 size_t len
, const char *name
)
1791 size_t header_size
= cbfs_calculate_file_header_size(name
);
1792 if (header_size
> CBFS_METADATA_MAX_SIZE
) {
1793 ERROR("'%s' name too long to fit in CBFS header\n", name
);
1797 struct cbfs_file
*entry
= malloc(CBFS_METADATA_MAX_SIZE
);
1798 memset(entry
, CBFS_CONTENT_DEFAULT_VALUE
, CBFS_METADATA_MAX_SIZE
);
1799 memcpy(entry
->magic
, CBFS_FILE_MAGIC
, sizeof(entry
->magic
));
1800 entry
->type
= htobe32(type
);
1801 entry
->len
= htobe32(len
);
1802 entry
->attributes_offset
= 0;
1803 entry
->offset
= htobe32(header_size
);
1804 memset(entry
->filename
, 0, be32toh(entry
->offset
) - sizeof(*entry
));
1805 strcpy(entry
->filename
, name
);
1809 int cbfs_create_empty_entry(struct cbfs_file
*entry
, int type
,
1810 size_t len
, const char *name
)
1812 struct cbfs_file
*tmp
= cbfs_create_file_header(type
, len
, name
);
1816 memcpy(entry
, tmp
, be32toh(tmp
->offset
));
1818 memset(CBFS_SUBHEADER(entry
), CBFS_CONTENT_DEFAULT_VALUE
, len
);
1822 struct cbfs_file_attribute
*cbfs_file_first_attr(struct cbfs_file
*file
)
1824 /* attributes_offset should be 0 when there is no attribute, but all
1825 * values that point into the cbfs_file header are invalid, too. */
1826 if (be32toh(file
->attributes_offset
) <= sizeof(*file
))
1829 /* There needs to be enough space for the file header and one
1830 * attribute header for this to make sense. */
1831 if (be32toh(file
->offset
) <=
1832 sizeof(*file
) + sizeof(struct cbfs_file_attribute
))
1835 return (struct cbfs_file_attribute
*)
1836 (((uint8_t *)file
) + be32toh(file
->attributes_offset
));
1839 struct cbfs_file_attribute
*cbfs_file_next_attr(struct cbfs_file
*file
,
1840 struct cbfs_file_attribute
*attr
)
1842 /* ex falso sequitur quodlibet */
1846 /* Is there enough space for another attribute? */
1847 if ((uint8_t *)attr
+ be32toh(attr
->len
) +
1848 sizeof(struct cbfs_file_attribute
) >
1849 (uint8_t *)file
+ be32toh(file
->offset
))
1852 struct cbfs_file_attribute
*next
= (struct cbfs_file_attribute
*)
1853 (((uint8_t *)attr
) + be32toh(attr
->len
));
1854 /* If any, "unused" attributes must come last. */
1855 if (be32toh(next
->tag
) == CBFS_FILE_ATTR_TAG_UNUSED
)
1857 if (be32toh(next
->tag
) == CBFS_FILE_ATTR_TAG_UNUSED2
)
1863 struct cbfs_file_attribute
*cbfs_add_file_attr(struct cbfs_file
*header
,
1867 assert(IS_ALIGNED(size
, CBFS_ATTRIBUTE_ALIGN
));
1868 struct cbfs_file_attribute
*attr
, *next
;
1869 next
= cbfs_file_first_attr(header
);
1872 next
= cbfs_file_next_attr(header
, attr
);
1873 } while (next
!= NULL
);
1874 uint32_t header_size
= be32toh(header
->offset
) + size
;
1875 if (header_size
> CBFS_METADATA_MAX_SIZE
) {
1876 DEBUG("exceeding allocated space for cbfs_file headers");
1879 /* attr points to the last valid attribute now.
1880 * If NULL, we have to create the first one. */
1882 /* New attributes start where the header ends.
1883 * header->offset is later set to accommodate the
1884 * additional structure.
1885 * No endianness translation necessary here, because both
1886 * fields are encoded the same way. */
1887 header
->attributes_offset
= header
->offset
;
1888 attr
= (struct cbfs_file_attribute
*)
1889 (((uint8_t *)header
) +
1890 be32toh(header
->attributes_offset
));
1892 attr
= (struct cbfs_file_attribute
*)
1893 (((uint8_t *)attr
) +
1894 be32toh(attr
->len
));
1896 header
->offset
= htobe32(header_size
);
1897 /* Attributes are expected to be small (much smaller than a flash page)
1898 and not really meant to be overwritten in-place. To avoid surprising
1899 values in reserved fields of attribute structures, initialize them to
1901 memset(attr
, 0, size
);
1902 attr
->tag
= htobe32(tag
);
1903 attr
->len
= htobe32(size
);
1907 int cbfs_add_file_hash(struct cbfs_file
*header
, struct buffer
*buffer
,
1908 enum vb2_hash_algorithm alg
)
1910 if (!vb2_digest_size(alg
))
1913 struct cbfs_file_attr_hash
*attr
=
1914 (struct cbfs_file_attr_hash
*)cbfs_add_file_attr(header
,
1915 CBFS_FILE_ATTR_TAG_HASH
, cbfs_file_attr_hash_size(alg
));
1920 if (vb2_hash_calculate(false, buffer_get(buffer
), buffer_size(buffer
),
1921 alg
, &attr
->hash
) != VB2_SUCCESS
)
1927 /* Finds a place to hold whole data in same memory page. */
1928 static int is_in_same_page(uint32_t start
, uint32_t size
, uint32_t page
)
1932 return (start
/ page
) == (start
+ size
- 1) / page
;
1935 /* Tests if data can fit in a range by given offset:
1936 * start ->| metadata_size | offset (+ size) |<- end
1938 static int is_in_range(size_t start
, size_t end
, size_t metadata_size
,
1939 size_t offset
, size_t size
)
1941 return (offset
>= start
+ metadata_size
&& offset
+ size
<= end
);
1944 static size_t absolute_align(const struct cbfs_image
*image
, size_t val
,
1947 const size_t region_offset
= buffer_offset(&image
->buffer
);
1948 /* To perform alignment on absolute address, take the region offset */
1949 /* of the image into account. */
1950 return align_up(val
+ region_offset
, align
) - region_offset
;
1954 int32_t cbfs_locate_entry(struct cbfs_image
*image
, size_t size
,
1955 size_t page_size
, size_t align
, size_t metadata_size
)
1957 struct cbfs_file
*entry
;
1959 size_t addr
, addr_next
, addr2
, addr3
, offset
;
1961 /* Default values: allow fitting anywhere in ROM. */
1963 page_size
= image
->has_header
? image
->header
.romsize
:
1968 if (size
> page_size
)
1969 ERROR("Input file size (%zd) greater than page size (%zd).\n",
1972 size_t image_align
= image
->has_header
? image
->header
.align
:
1974 if (page_size
% image_align
)
1975 WARN("%s: Page size (%#zx) not aligned with CBFS image (%#zx).\n",
1976 __func__
, page_size
, image_align
);
1978 need_len
= metadata_size
+ size
;
1980 // Merge empty entries to build get max available space.
1981 cbfs_legacy_walk(image
, cbfs_merge_empty_entry
, NULL
);
1983 /* Three cases of content location on memory page:
1985 * | PAGE 1 | PAGE 2 |
1986 * | <header><content>| Fit. Return start of content.
1989 * | PAGE 1 | PAGE 2 |
1990 * | <header><content> | Fits when we shift content to align
1991 * shift-> | <header>|<content> | at starting of PAGE 2.
1993 * case 3. (large content filling whole page)
1994 * | PAGE 1 | PAGE 2 | PAGE 3 |
1995 * | <header>< content > | Can't fit. If we shift content to
1996 * |trial-> <header>< content > | PAGE 2, header can't fit in free
1997 * | shift-> <header><content> space, so we must use PAGE 3.
1999 * The returned address can be then used as "base-address" (-b) in add-*
2000 * commands (will be re-calculated and positioned by cbfs_add_entry_at).
2001 * For stage targets, the address is also used to re-link stage before
2002 * being added into CBFS.
2004 for (entry
= cbfs_find_first_entry(image
);
2005 entry
&& cbfs_is_valid_entry(image
, entry
);
2006 entry
= cbfs_find_next_entry(image
, entry
)) {
2008 uint32_t type
= be32toh(entry
->type
);
2009 if (type
!= CBFS_TYPE_NULL
)
2012 addr
= cbfs_get_entry_addr(image
, entry
);
2013 addr_next
= cbfs_get_entry_addr(image
, cbfs_find_next_entry(
2015 if (addr_next
- addr
< need_len
)
2018 offset
= absolute_align(image
, addr
+ metadata_size
, align
);
2019 if (is_in_same_page(offset
, size
, page_size
) &&
2020 is_in_range(addr
, addr_next
, metadata_size
, offset
, size
)) {
2021 DEBUG("cbfs_locate_entry: FIT (PAGE1).");
2025 addr2
= align_up(addr
, page_size
);
2026 offset
= absolute_align(image
, addr2
, align
);
2027 if (is_in_range(addr
, addr_next
, metadata_size
, offset
, size
)) {
2028 DEBUG("cbfs_locate_entry: OVERLAP (PAGE2).");
2032 /* Assume page_size >= metadata_size so adding one page will
2033 * definitely provide the space for header. */
2034 assert(page_size
>= metadata_size
);
2035 addr3
= addr2
+ page_size
;
2036 offset
= absolute_align(image
, addr3
, align
);
2037 if (is_in_range(addr
, addr_next
, metadata_size
, offset
, size
)) {
2038 DEBUG("cbfs_locate_entry: OVERLAP+ (PAGE3).");