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
;
747 uint32_t max_null_entry_size
= 0;
748 struct cbfs_file
*entry
, *next
;
750 uint32_t header_size
= be32toh(header
->offset
);
752 need_size
= header_size
+ buffer
->size
;
753 DEBUG("cbfs_add_entry('%s'@0x%x) => need_size = %u+%zu=%u\n",
754 name
, content_offset
, header_size
, buffer
->size
, need_size
);
756 // Merge empty entries.
757 DEBUG("(trying to merge empty entries...)\n");
758 cbfs_legacy_walk(image
, cbfs_merge_empty_entry
, NULL
);
760 for (entry
= cbfs_find_first_entry(image
);
761 entry
&& cbfs_is_valid_entry(image
, entry
);
762 entry
= cbfs_find_next_entry(image
, entry
)) {
764 entry_type
= be32toh(entry
->type
);
765 if (entry_type
!= CBFS_TYPE_NULL
)
768 addr
= cbfs_get_entry_addr(image
, entry
);
769 next
= cbfs_find_next_entry(image
, entry
);
770 addr_next
= cbfs_get_entry_addr(image
, next
);
771 entry_size
= addr_next
- addr
;
772 max_null_entry_size
= MAX(max_null_entry_size
, entry_size
);
774 DEBUG("cbfs_add_entry: space at 0x%x+0x%x(%d) bytes\n",
775 addr
, entry_size
, entry_size
);
777 /* Will the file fit? Don't yet worry if we have space for a new
778 * "empty" entry. We take care of that later.
780 if (addr
+ need_size
> addr_next
)
783 // Test for complicated cases
784 if (content_offset
> 0) {
785 if (addr_next
< content_offset
) {
786 DEBUG("Not for specified offset yet");
788 } else if (addr
> content_offset
) {
789 DEBUG("Exceed specified content_offset.");
791 } else if (addr
+ header_size
> content_offset
) {
792 ERROR("Not enough space for header.\n");
794 } else if (content_offset
+ buffer
->size
> addr_next
) {
795 ERROR("Not enough space for content.\n");
800 // TODO there are more few tricky cases that we may
801 // want to fit by altering offset.
803 if (content_offset
== 0) {
804 // we tested every condition earlier under which
805 // placing the file there might fail
806 content_offset
= addr
+ header_size
;
809 DEBUG("section 0x%x+0x%x for content_offset 0x%x.\n",
810 addr
, entry_size
, content_offset
);
812 if (cbfs_add_entry_at(image
, entry
, buffer
->data
,
813 content_offset
, header
, len_align
) == 0) {
819 ERROR("Could not add %s [header %d + content %zd bytes (%zd KB)] @0x%x; "
820 "Largest empty slot: %d bytes\n",
821 buffer
->name
, header_size
, buffer
->size
, buffer
->size
/ 1024, content_offset
,
822 max_null_entry_size
);
826 struct cbfs_file
*cbfs_get_entry(struct cbfs_image
*image
, const char *name
)
828 struct cbfs_file
*entry
;
829 for (entry
= cbfs_find_first_entry(image
);
830 entry
&& cbfs_is_valid_entry(image
, entry
);
831 entry
= cbfs_find_next_entry(image
, entry
)) {
832 if (strcasecmp(entry
->filename
, name
) == 0) {
833 DEBUG("cbfs_get_entry: found %s\n", name
);
840 static int cbfs_payload_decompress(struct cbfs_payload_segment
*segments
,
841 struct buffer
*buff
, int num_seg
)
843 struct buffer new_buffer
;
844 struct buffer seg_buffer
;
849 decomp_func_ptr decompress
;
851 new_offset
= num_seg
* sizeof(*segments
);
852 new_buff_sz
= num_seg
* sizeof(*segments
);
854 /* Find out and allocate the amount of memory occupied
855 * by the binary data */
856 for (int i
= 0; i
< num_seg
; i
++)
857 new_buff_sz
+= segments
[i
].mem_len
;
859 if (buffer_create(&new_buffer
, new_buff_sz
, "decompressed_buff"))
862 in_ptr
= buffer_get(buff
) + new_offset
;
863 out_ptr
= buffer_get(&new_buffer
) + new_offset
;
865 for (int i
= 0; i
< num_seg
; i
++) {
869 /* Segments BSS and ENTRY do not have binary data. */
870 if (segments
[i
].type
== PAYLOAD_SEGMENT_BSS
||
871 segments
[i
].type
== PAYLOAD_SEGMENT_ENTRY
) {
873 } else if (segments
[i
].type
== PAYLOAD_SEGMENT_DEPRECATED_PARAMS
) {
874 memcpy(out_ptr
, in_ptr
, segments
[i
].len
);
875 segments
[i
].offset
= new_offset
;
876 new_offset
+= segments
[i
].len
;
877 in_ptr
+= segments
[i
].len
;
878 out_ptr
+= segments
[i
].len
;
879 segments
[i
].compression
= CBFS_COMPRESS_NONE
;
883 /* The payload uses an unknown compression algorithm. */
884 decompress
= decompression_function(segments
[i
].compression
);
885 if (decompress
== NULL
) {
886 ERROR("Unknown decompression algorithm: %u\n",
887 segments
[i
].compression
);
891 if (buffer_create(&tbuff
, segments
[i
].mem_len
, "segment")) {
892 buffer_delete(&new_buffer
);
896 if (decompress(in_ptr
, segments
[i
].len
, buffer_get(&tbuff
),
897 (int) buffer_size(&tbuff
),
899 ERROR("Couldn't decompress payload segment %u\n", i
);
900 buffer_delete(&new_buffer
);
901 buffer_delete(&tbuff
);
905 memcpy(out_ptr
, buffer_get(&tbuff
), decomp_size
);
907 in_ptr
+= segments
[i
].len
;
909 /* Update the offset of the segment. */
910 segments
[i
].offset
= new_offset
;
911 /* True decompressed size is just the data size. No metadata */
912 segments
[i
].len
= decomp_size
;
913 /* Segment is not compressed. */
914 segments
[i
].compression
= CBFS_COMPRESS_NONE
;
916 /* Update the offset and output buffer pointer. */
917 new_offset
+= decomp_size
;
918 out_ptr
+= decomp_size
;
920 buffer_delete(&tbuff
);
923 buffer_splice(&seg_buffer
, &new_buffer
, 0, 0);
924 xdr_segs(&seg_buffer
, segments
, num_seg
);
932 static int init_elf_from_arch(Elf64_Ehdr
*ehdr
, uint32_t cbfs_arch
)
939 case CBFS_ARCHITECTURE_X86
:
940 endian
= ELFDATA2LSB
;
944 case CBFS_ARCHITECTURE_ARM
:
945 endian
= ELFDATA2LSB
;
949 case CBFS_ARCHITECTURE_AARCH64
:
950 endian
= ELFDATA2LSB
;
952 machine
= EM_AARCH64
;
954 case CBFS_ARCHITECTURE_MIPS
:
955 endian
= ELFDATA2LSB
;
959 case CBFS_ARCHITECTURE_RISCV
:
960 endian
= ELFDATA2LSB
;
965 ERROR("Unsupported arch: %x\n", cbfs_arch
);
969 elf_init_eheader(ehdr
, machine
, nbits
, endian
);
973 static int cbfs_stage_make_elf(struct buffer
*buff
, uint32_t arch
,
974 struct cbfs_file
*entry
)
978 struct elf_writer
*ew
;
979 struct buffer elf_out
;
983 if (arch
== CBFS_ARCHITECTURE_UNKNOWN
) {
984 ERROR("You need to specify -m ARCH.\n");
988 struct cbfs_file_attr_stageheader
*stage
= NULL
;
989 for (struct cbfs_file_attribute
*attr
= cbfs_file_first_attr(entry
);
990 attr
!= NULL
; attr
= cbfs_file_next_attr(entry
, attr
)) {
991 if (be32toh(attr
->tag
) == CBFS_FILE_ATTR_TAG_STAGEHEADER
) {
992 stage
= (struct cbfs_file_attr_stageheader
*)attr
;
998 ERROR("Stage header not found for %s\n", entry
->filename
);
1002 if (init_elf_from_arch(&ehdr
, arch
))
1005 /* Attempt rmodule translation first. */
1006 rmod_ret
= rmodule_stage_to_elf(&ehdr
, buff
);
1009 ERROR("rmodule parsing failed\n");
1011 } else if (rmod_ret
== 0)
1014 /* Rmodule couldn't do anything with the data. Continue on with SELF. */
1016 ehdr
.e_entry
= be64toh(stage
->loadaddr
) + be32toh(stage
->entry_offset
);
1018 ew
= elf_writer_init(&ehdr
);
1020 ERROR("Unable to init ELF writer.\n");
1024 memset(&shdr
, 0, sizeof(shdr
));
1025 shdr
.sh_type
= SHT_PROGBITS
;
1026 shdr
.sh_flags
= SHF_WRITE
| SHF_ALLOC
| SHF_EXECINSTR
;
1027 shdr
.sh_addr
= be64toh(stage
->loadaddr
);
1028 shdr
.sh_size
= buffer_size(buff
);
1029 empty_sz
= be32toh(stage
->memlen
) - buffer_size(buff
);
1031 if (elf_writer_add_section(ew
, &shdr
, buff
, ".program")) {
1032 ERROR("Unable to add ELF section: .program\n");
1033 elf_writer_destroy(ew
);
1037 if (empty_sz
!= 0) {
1040 buffer_init(&b
, NULL
, NULL
, 0);
1041 memset(&shdr
, 0, sizeof(shdr
));
1042 shdr
.sh_type
= SHT_NOBITS
;
1043 shdr
.sh_flags
= SHF_WRITE
| SHF_ALLOC
;
1044 shdr
.sh_addr
= be64toh(stage
->loadaddr
) + buffer_size(buff
);
1045 shdr
.sh_size
= empty_sz
;
1046 if (elf_writer_add_section(ew
, &shdr
, &b
, ".empty")) {
1047 ERROR("Unable to add ELF section: .empty\n");
1048 elf_writer_destroy(ew
);
1053 if (elf_writer_serialize(ew
, &elf_out
)) {
1054 ERROR("Unable to create ELF file from stage.\n");
1055 elf_writer_destroy(ew
);
1059 /* Flip buffer with the created ELF one. */
1060 buffer_delete(buff
);
1063 elf_writer_destroy(ew
);
1068 static int cbfs_payload_make_elf(struct buffer
*buff
, uint32_t arch
,
1069 unused
struct cbfs_file
*entry
)
1073 struct cbfs_payload_segment
*segs
= NULL
;
1074 struct elf_writer
*ew
= NULL
;
1075 struct buffer elf_out
;
1079 if (arch
== CBFS_ARCHITECTURE_UNKNOWN
) {
1080 ERROR("You need to specify -m ARCH.\n");
1084 /* Count the number of segments inside buffer */
1086 uint32_t payload_type
= 0;
1088 struct cbfs_payload_segment
*seg
;
1090 seg
= buffer_get(buff
);
1091 payload_type
= read_be32(&seg
[segments
].type
);
1093 if (payload_type
== PAYLOAD_SEGMENT_CODE
) {
1095 } else if (payload_type
== PAYLOAD_SEGMENT_DATA
) {
1097 } else if (payload_type
== PAYLOAD_SEGMENT_BSS
) {
1099 } else if (payload_type
== PAYLOAD_SEGMENT_DEPRECATED_PARAMS
) {
1101 } else if (payload_type
== PAYLOAD_SEGMENT_ENTRY
) {
1102 /* The last segment in a payload is always ENTRY as
1103 * specified by the parse_elf_to_payload() function.
1104 * Therefore there is no need to continue looking for
1109 ERROR("Unknown payload segment type: %x\n",
1115 segs
= malloc(segments
* sizeof(*segs
));
1117 /* Decode xdr segments */
1118 for (int i
= 0; i
< segments
; i
++) {
1119 struct cbfs_payload_segment
*serialized_seg
= buffer_get(buff
);
1120 xdr_get_seg(&segs
[i
], &serialized_seg
[i
]);
1123 if (cbfs_payload_decompress(segs
, buff
, segments
)) {
1124 ERROR("Failed to decompress payload.\n");
1128 if (init_elf_from_arch(&ehdr
, arch
))
1131 ehdr
.e_entry
= segs
[segments
-1].load_addr
;
1133 ew
= elf_writer_init(&ehdr
);
1135 ERROR("Unable to init ELF writer.\n");
1139 for (int i
= 0; i
< segments
; i
++) {
1140 struct buffer tbuff
;
1141 size_t empty_sz
= 0;
1143 memset(&shdr
, 0, sizeof(shdr
));
1146 if (segs
[i
].type
== PAYLOAD_SEGMENT_CODE
) {
1147 shdr
.sh_type
= SHT_PROGBITS
;
1148 shdr
.sh_flags
= SHF_WRITE
| SHF_ALLOC
| SHF_EXECINSTR
;
1149 shdr
.sh_addr
= segs
[i
].load_addr
;
1150 shdr
.sh_size
= segs
[i
].len
;
1151 empty_sz
= segs
[i
].mem_len
- segs
[i
].len
;
1152 name
= strdup(".text");
1153 buffer_splice(&tbuff
, buff
, segs
[i
].offset
,
1155 } else if (segs
[i
].type
== PAYLOAD_SEGMENT_DATA
) {
1156 shdr
.sh_type
= SHT_PROGBITS
;
1157 shdr
.sh_flags
= SHF_ALLOC
| SHF_WRITE
;
1158 shdr
.sh_addr
= segs
[i
].load_addr
;
1159 shdr
.sh_size
= segs
[i
].len
;
1160 empty_sz
= segs
[i
].mem_len
- segs
[i
].len
;
1161 name
= strdup(".data");
1162 buffer_splice(&tbuff
, buff
, segs
[i
].offset
,
1164 } else if (segs
[i
].type
== PAYLOAD_SEGMENT_BSS
) {
1165 shdr
.sh_type
= SHT_NOBITS
;
1166 shdr
.sh_flags
= SHF_ALLOC
| SHF_WRITE
;
1167 shdr
.sh_addr
= segs
[i
].load_addr
;
1168 shdr
.sh_size
= segs
[i
].len
;
1169 name
= strdup(".bss");
1170 buffer_splice(&tbuff
, buff
, 0, 0);
1171 } else if (segs
[i
].type
== PAYLOAD_SEGMENT_DEPRECATED_PARAMS
) {
1172 shdr
.sh_type
= SHT_NOTE
;
1174 shdr
.sh_size
= segs
[i
].len
;
1175 name
= strdup(".note.pinfo");
1176 buffer_splice(&tbuff
, buff
, segs
[i
].offset
,
1178 } else if (segs
[i
].type
== PAYLOAD_SEGMENT_ENTRY
) {
1181 ERROR("unknown ELF segment type\n");
1186 ERROR("out of memory\n");
1190 if (elf_writer_add_section(ew
, &shdr
, &tbuff
, name
)) {
1191 ERROR("Unable to add ELF section: %s\n", name
);
1197 if (empty_sz
!= 0) {
1200 buffer_init(&b
, NULL
, NULL
, 0);
1201 memset(&shdr
, 0, sizeof(shdr
));
1202 shdr
.sh_type
= SHT_NOBITS
;
1203 shdr
.sh_flags
= SHF_WRITE
| SHF_ALLOC
;
1204 shdr
.sh_addr
= segs
[i
].load_addr
+ segs
[i
].len
;
1205 shdr
.sh_size
= empty_sz
;
1206 name
= strdup(".empty");
1208 ERROR("out of memory\n");
1211 if (elf_writer_add_section(ew
, &shdr
, &b
, name
)) {
1212 ERROR("Unable to add ELF section: %s\n", name
);
1220 if (elf_writer_serialize(ew
, &elf_out
)) {
1221 ERROR("Unable to create ELF file from payload.\n");
1225 /* Flip buffer with the created ELF one. */
1226 buffer_delete(buff
);
1232 elf_writer_destroy(ew
);
1236 int cbfs_export_entry(struct cbfs_image
*image
, const char *entry_name
,
1237 const char *filename
, uint32_t arch
, bool do_processing
)
1239 struct cbfs_file
*entry
= cbfs_get_entry(image
, entry_name
);
1240 struct buffer buffer
;
1242 ERROR("File not found: %s\n", entry_name
);
1246 unsigned int compressed_size
= be32toh(entry
->len
);
1247 unsigned int decompressed_size
= 0;
1248 unsigned int compression
= cbfs_file_get_compression_info(entry
,
1249 &decompressed_size
);
1250 unsigned int buffer_len
;
1251 decomp_func_ptr decompress
;
1253 if (do_processing
) {
1254 decompress
= decompression_function(compression
);
1256 ERROR("looking up decompression routine failed\n");
1259 buffer_len
= decompressed_size
;
1261 /* Force nop decompression */
1262 decompress
= decompression_function(CBFS_COMPRESS_NONE
);
1263 buffer_len
= compressed_size
;
1266 LOG("Found file %.30s at 0x%x, type %.12s, compressed %d, size %d\n",
1267 entry_name
, cbfs_get_entry_addr(image
, entry
),
1268 get_cbfs_entry_type_name(be32toh(entry
->type
)), compressed_size
,
1271 buffer_init(&buffer
, strdup("(cbfs_export_entry)"), NULL
, 0);
1272 buffer
.data
= malloc(buffer_len
);
1273 buffer
.size
= buffer_len
;
1275 if (decompress(CBFS_SUBHEADER(entry
), compressed_size
,
1276 buffer
.data
, buffer
.size
, NULL
)) {
1277 ERROR("decompression failed for %s\n", entry_name
);
1278 buffer_delete(&buffer
);
1283 * We want to export stages and payloads as ELFs, not with coreboot's
1284 * custom stage/SELF binary formats, so we need to do extra processing
1285 * to turn them back into an ELF.
1287 if (do_processing
) {
1288 int (*make_elf
)(struct buffer
*, uint32_t,
1289 struct cbfs_file
*) = NULL
;
1290 switch (be32toh(entry
->type
)) {
1291 case CBFS_TYPE_STAGE
:
1292 make_elf
= cbfs_stage_make_elf
;
1294 case CBFS_TYPE_SELF
:
1295 make_elf
= cbfs_payload_make_elf
;
1298 if (make_elf
&& make_elf(&buffer
, arch
, entry
)) {
1299 ERROR("Failed to write %s into %s.\n",
1300 entry_name
, filename
);
1301 buffer_delete(&buffer
);
1306 if (buffer_write_file(&buffer
, filename
) != 0) {
1307 ERROR("Failed to write %s into %s.\n",
1308 entry_name
, filename
);
1309 buffer_delete(&buffer
);
1313 buffer_delete(&buffer
);
1314 INFO("Successfully dumped the file to: %s\n", filename
);
1318 int cbfs_remove_entry(struct cbfs_image
*image
, const char *name
)
1320 struct cbfs_file
*entry
;
1321 entry
= cbfs_get_entry(image
, name
);
1323 ERROR("CBFS file %s not found.\n", name
);
1326 DEBUG("cbfs_remove_entry: Removed %s @ 0x%x\n",
1327 entry
->filename
, cbfs_get_entry_addr(image
, entry
));
1328 entry
->type
= htobe32(CBFS_TYPE_DELETED
);
1329 cbfs_legacy_walk(image
, cbfs_merge_empty_entry
, NULL
);
1333 int cbfs_print_header_info(struct cbfs_image
*image
)
1335 char *name
= strdup(image
->buffer
.name
);
1337 printf("%s: %zd kB, bootblocksize %d, romsize %d, offset 0x%x\n"
1338 "alignment: %d bytes, architecture: %s\n\n",
1340 image
->buffer
.size
/ 1024,
1341 image
->header
.bootblocksize
,
1342 image
->header
.romsize
,
1343 image
->header
.offset
,
1344 image
->header
.align
,
1345 arch_to_string(image
->header
.architecture
));
1350 static int cbfs_print_stage_info(struct cbfs_file
*entry
, FILE* fp
)
1353 struct cbfs_file_attr_stageheader
*stage
= NULL
;
1354 for (struct cbfs_file_attribute
*attr
= cbfs_file_first_attr(entry
);
1355 attr
!= NULL
; attr
= cbfs_file_next_attr(entry
, attr
)) {
1356 if (be32toh(attr
->tag
) == CBFS_FILE_ATTR_TAG_STAGEHEADER
) {
1357 stage
= (struct cbfs_file_attr_stageheader
*)attr
;
1362 if (stage
== NULL
) {
1363 fprintf(fp
, " ERROR: stage header not found!\n");
1368 " entry: 0x%" PRIx64
", load: 0x%" PRIx64
", "
1370 be64toh(stage
->loadaddr
) + be32toh(stage
->entry_offset
),
1371 be64toh(stage
->loadaddr
),
1372 be32toh(stage
->memlen
));
1376 static int cbfs_print_decoded_payload_segment_info(
1377 struct cbfs_payload_segment
*seg
, FILE *fp
)
1379 /* The input (seg) must be already decoded by
1380 * cbfs_decode_payload_segment.
1382 switch (seg
->type
) {
1383 case PAYLOAD_SEGMENT_CODE
:
1384 case PAYLOAD_SEGMENT_DATA
:
1385 fprintf(fp
, " %s (%s compression, offset: 0x%x, "
1386 "load: 0x%" PRIx64
", length: %d/%d)\n",
1387 (seg
->type
== PAYLOAD_SEGMENT_CODE
?
1389 lookup_name_by_type(types_cbfs_compression
,
1392 seg
->offset
, seg
->load_addr
, seg
->len
,
1396 case PAYLOAD_SEGMENT_ENTRY
:
1397 fprintf(fp
, " entry (0x%" PRIx64
")\n",
1401 case PAYLOAD_SEGMENT_BSS
:
1402 fprintf(fp
, " BSS (address 0x%016" PRIx64
", "
1404 seg
->load_addr
, seg
->len
);
1407 case PAYLOAD_SEGMENT_DEPRECATED_PARAMS
:
1408 fprintf(fp
, " parameters (deprecated)\n");
1412 fprintf(fp
, " 0x%x (%s compression, offset: 0x%x, "
1413 "load: 0x%" PRIx64
", length: %d/%d\n",
1415 lookup_name_by_type(types_cbfs_compression
,
1418 seg
->offset
, seg
->load_addr
, seg
->len
,
1425 int cbfs_print_entry_info(struct cbfs_image
*image
, struct cbfs_file
*entry
,
1428 const char *name
= entry
->filename
;
1429 struct cbfs_payload_segment
*payload
;
1430 FILE *fp
= (FILE *)arg
;
1432 if (!cbfs_is_valid_entry(image
, entry
)) {
1433 ERROR("cbfs_print_entry_info: Invalid entry at 0x%x\n",
1434 cbfs_get_entry_addr(image
, entry
));
1440 unsigned int decompressed_size
= 0;
1441 unsigned int compression
= cbfs_file_get_compression_info(entry
,
1442 &decompressed_size
);
1443 const char *compression_name
= lookup_name_by_type(
1444 types_cbfs_compression
, compression
, "????");
1446 if (compression
== CBFS_COMPRESS_NONE
)
1447 fprintf(fp
, "%-30s 0x%-8x %-12s %8d %-4s\n",
1448 *name
? name
: "(empty)",
1449 cbfs_get_entry_addr(image
, entry
),
1450 get_cbfs_entry_type_name(be32toh(entry
->type
)),
1451 be32toh(entry
->len
),
1455 fprintf(fp
, "%-30s 0x%-8x %-12s %8d %-4s (%d decompressed)\n",
1456 *name
? name
: "(empty)",
1457 cbfs_get_entry_addr(image
, entry
),
1458 get_cbfs_entry_type_name(be32toh(entry
->type
)),
1459 be32toh(entry
->len
),
1467 struct cbfs_file_attr_hash
*attr
= NULL
;
1468 while ((attr
= cbfs_file_get_next_hash(entry
, attr
)) != NULL
) {
1469 size_t hash_len
= vb2_digest_size(attr
->hash
.algo
);
1471 fprintf(fp
, "invalid/unsupported hash algorithm: %d\n",
1475 char *hash_str
= bintohex(attr
->hash
.raw
, hash_len
);
1476 int valid
= vb2_hash_verify(false, CBFS_SUBHEADER(entry
),
1477 be32toh(entry
->len
), &attr
->hash
) == VB2_SUCCESS
;
1478 const char *valid_str
= valid
? "valid" : "invalid";
1480 fprintf(fp
, " hash %s:%s %s\n",
1481 vb2_get_hash_algorithm_name(attr
->hash
.algo
),
1482 hash_str
, valid_str
);
1486 DEBUG(" cbfs_file=0x%x, offset=0x%x, content_address=0x%x+0x%x\n",
1487 cbfs_get_entry_addr(image
, entry
), be32toh(entry
->offset
),
1488 cbfs_get_entry_addr(image
, entry
) + be32toh(entry
->offset
),
1489 be32toh(entry
->len
));
1491 /* note the components of the subheader may be in host order ... */
1492 switch (be32toh(entry
->type
)) {
1493 case CBFS_TYPE_STAGE
:
1494 cbfs_print_stage_info(entry
, fp
);
1497 case CBFS_TYPE_SELF
:
1498 payload
= (struct cbfs_payload_segment
*)
1499 CBFS_SUBHEADER(entry
);
1501 struct cbfs_payload_segment seg
;
1502 cbfs_decode_payload_segment(&seg
, payload
);
1503 cbfs_print_decoded_payload_segment_info(
1505 if (seg
.type
== PAYLOAD_SEGMENT_ENTRY
)
1518 * The format of this output has been stable for many years. Since it is meant
1519 * to be parsed by scripts, we should probably not lightly make changes to it as
1520 * that could break older scripts expecting a different format.
1522 * Until CB:41119, the `-v` flag made no difference when `-k` was selected, so
1523 * presumably no scripts were using that combination. That's why that patch left
1524 * the output for `-k` by itself alone to avoid breaking legacy scripts, and
1525 * expanded `-k -v` to allow an arbitrary number of `<key>:<value>` tokens at
1526 * the end of each row behind the legacy column output. So the new output format
1527 * stability rules should be that `-k` will stay as it is, and `-k -v` may be
1528 * expanded to add more `<key>:<value>` tokens to the end of a row. Scripts that
1529 * want to parse `-k -v` output should be written to gracefully ignore any extra
1530 * such tokens where they don't recognize the key.
1532 * The `-k -v` output may also include extra rows that start with a `[`. These
1533 * do not represent a CBFS file and can instead be used to display data that is
1534 * associated with the CBFS as a whole and not any single file. Currently
1535 * defined are `[FMAP REGION]\t<region name>` and
1536 * `[METADATA HASH]\t<hash>:<algo>`. More may be defined in the future and
1537 * scripts parsing `-k -v` output should be written to gracefully ignore any
1538 * rows starting with `[` that they don't recognize.
1540 * The format for existing `<key:value>` tokens or `[` rows should never be
1541 * changed once they are added.
1543 static int cbfs_print_parseable_entry_info(struct cbfs_image
*image
,
1544 struct cbfs_file
*entry
, void *arg
)
1546 FILE *fp
= (FILE *)arg
;
1550 size_t metadata_size
;
1552 const char *sep
= "\t";
1554 if (!cbfs_is_valid_entry(image
, entry
)) {
1555 ERROR("cbfs_print_entry_info: Invalid entry at 0x%x\n",
1556 cbfs_get_entry_addr(image
, entry
));
1560 name
= entry
->filename
;
1563 type
= get_cbfs_entry_type_name(be32toh(entry
->type
)),
1564 metadata_size
= be32toh(entry
->offset
);
1565 data_size
= be32toh(entry
->len
);
1566 offset
= cbfs_get_entry_addr(image
, entry
);
1568 fprintf(fp
, "%s%s", name
, sep
);
1569 fprintf(fp
, "0x%zx%s", offset
, sep
);
1570 fprintf(fp
, "%s%s", type
, sep
);
1571 fprintf(fp
, "0x%zx%s", metadata_size
, sep
);
1572 fprintf(fp
, "0x%zx%s", data_size
, sep
);
1573 fprintf(fp
, "0x%zx", metadata_size
+ data_size
);
1576 unsigned int decompressed_size
= 0;
1577 unsigned int compression
= cbfs_file_get_compression_info(entry
,
1578 &decompressed_size
);
1579 if (compression
!= CBFS_COMPRESS_NONE
)
1580 fprintf(fp
, "%scomp:%s:0x%x", sep
, lookup_name_by_type(
1581 types_cbfs_compression
, compression
, "????"),
1584 struct cbfs_file_attr_hash
*attr
= NULL
;
1585 while ((attr
= cbfs_file_get_next_hash(entry
, attr
)) != NULL
) {
1586 size_t hash_len
= vb2_digest_size(attr
->hash
.algo
);
1589 char *hash_str
= bintohex(attr
->hash
.raw
, hash_len
);
1590 int valid
= vb2_hash_verify(false, CBFS_SUBHEADER(entry
),
1591 be32toh(entry
->len
), &attr
->hash
) == VB2_SUCCESS
;
1592 fprintf(fp
, "%shash:%s:%s:%s", sep
,
1593 vb2_get_hash_algorithm_name(attr
->hash
.algo
),
1594 hash_str
, valid
? "valid" : "invalid");
1603 void cbfs_print_directory(struct cbfs_image
*image
)
1605 if (cbfs_is_legacy_cbfs(image
))
1606 cbfs_print_header_info(image
);
1607 printf("%-30s %-10s %-12s Size Comp\n", "Name", "Offset", "Type");
1608 cbfs_legacy_walk(image
, cbfs_print_entry_info
, NULL
);
1611 void cbfs_print_parseable_directory(struct cbfs_image
*image
)
1614 const char *header
[] = {
1622 const char *sep
= "\t";
1624 for (i
= 0; i
< ARRAY_SIZE(header
) - 1; i
++)
1625 fprintf(stdout
, "%s%s", header
[i
], sep
);
1626 fprintf(stdout
, "%s\n", header
[i
]);
1627 cbfs_legacy_walk(image
, cbfs_print_parseable_entry_info
, stdout
);
1630 int cbfs_merge_empty_entry(struct cbfs_image
*image
, struct cbfs_file
*entry
,
1633 struct cbfs_file
*next
;
1634 uint32_t next_addr
= 0;
1636 /* We don't return here even if this entry is already empty because we
1637 want to merge the empty entries following after it. */
1639 /* Loop until non-empty entry is found, starting from the current entry.
1640 After the loop, next_addr points to the next non-empty entry. */
1642 while (be32toh(next
->type
) == CBFS_TYPE_DELETED
||
1643 be32toh(next
->type
) == CBFS_TYPE_NULL
) {
1644 next
= cbfs_find_next_entry(image
, next
);
1647 next_addr
= cbfs_get_entry_addr(image
, next
);
1648 if (!cbfs_is_valid_entry(image
, next
))
1649 /* 'next' could be the end of cbfs */
1654 /* Nothing to empty */
1657 /* We can return here if we find only a single empty entry.
1658 For simplicity, we just proceed (and make it empty again). */
1660 /* We're creating one empty entry for combined empty spaces */
1661 uint32_t addr
= cbfs_get_entry_addr(image
, entry
);
1662 size_t len
= next_addr
- addr
- cbfs_calculate_file_header_size("");
1663 DEBUG("join_empty_entry: [0x%x, 0x%x) len=%zu\n", addr
, next_addr
, len
);
1664 return cbfs_create_empty_entry(entry
, CBFS_TYPE_NULL
, len
, "");
1667 int cbfs_legacy_walk(struct cbfs_image
*image
, cbfs_entry_callback callback
,
1671 struct cbfs_file
*entry
;
1672 for (entry
= cbfs_find_first_entry(image
);
1673 entry
&& cbfs_is_valid_entry(image
, entry
);
1674 entry
= cbfs_find_next_entry(image
, entry
)) {
1676 if (callback(image
, entry
, arg
) != 0)
1682 static int cbfs_header_valid(struct cbfs_header
*header
)
1684 if ((be32toh(header
->magic
) == CBFS_HEADER_MAGIC
) &&
1685 ((be32toh(header
->version
) == CBFS_HEADER_VERSION1
) ||
1686 (be32toh(header
->version
) == CBFS_HEADER_VERSION2
)) &&
1687 (be32toh(header
->offset
) < be32toh(header
->romsize
)))
1692 struct cbfs_header
*cbfs_find_header(char *data
, size_t size
,
1693 uint32_t forced_offset
)
1698 struct cbfs_header
*header
, *result
= NULL
;
1700 if (forced_offset
< (size
- sizeof(struct cbfs_header
))) {
1701 /* Check if the forced header is valid. */
1702 header
= (struct cbfs_header
*)(data
+ forced_offset
);
1703 if (cbfs_header_valid(header
))
1708 // Try finding relative offset of master header at end of file first.
1709 rel_offset
= *(int32_t *)(data
+ size
- sizeof(int32_t));
1710 offset
= size
+ rel_offset
;
1711 DEBUG("relative offset: %#zx(-%#zx), offset: %#zx\n",
1712 (size_t)rel_offset
, (size_t)-rel_offset
, offset
);
1714 if (offset
>= size
- sizeof(*header
) ||
1715 !cbfs_header_valid((struct cbfs_header
*)(data
+ offset
))) {
1716 // Some use cases append non-CBFS data to the end of the ROM.
1717 DEBUG("relative offset seems wrong, scanning whole image...\n");
1721 for (; offset
+ sizeof(*header
) < size
; offset
++) {
1722 header
= (struct cbfs_header
*)(data
+ offset
);
1723 if (!cbfs_header_valid(header
))
1729 // Top-aligned images usually have a working relative offset
1730 // field, so this is more likely to happen on bottom-aligned
1731 // ones (where the first header is the "outermost" one)
1732 WARN("Multiple (%d) CBFS headers found, using the first one.\n",
1738 struct cbfs_file
*cbfs_find_first_entry(struct cbfs_image
*image
)
1741 if (image
->has_header
)
1742 /* header.offset is relative to start of flash, not
1743 * start of region, so use it with the full image.
1745 return (struct cbfs_file
*)
1746 (buffer_get_original_backing(&image
->buffer
) +
1747 image
->header
.offset
);
1749 return (struct cbfs_file
*)buffer_get(&image
->buffer
);
1752 struct cbfs_file
*cbfs_find_next_entry(struct cbfs_image
*image
,
1753 struct cbfs_file
*entry
)
1755 uint32_t addr
= cbfs_get_entry_addr(image
, entry
);
1756 int align
= image
->has_header
? image
->header
.align
: CBFS_ALIGNMENT
;
1757 assert(entry
&& cbfs_is_valid_entry(image
, entry
));
1758 addr
+= be32toh(entry
->offset
) + be32toh(entry
->len
);
1759 addr
= align_up(addr
, align
);
1760 return (struct cbfs_file
*)(image
->buffer
.data
+ addr
);
1763 uint32_t cbfs_get_entry_addr(struct cbfs_image
*image
, struct cbfs_file
*entry
)
1765 assert(image
&& image
->buffer
.data
&& entry
);
1766 return (int32_t)((char *)entry
- image
->buffer
.data
);
1769 int cbfs_is_valid_cbfs(struct cbfs_image
*image
)
1771 return buffer_check_magic(&image
->buffer
, CBFS_FILE_MAGIC
,
1772 strlen(CBFS_FILE_MAGIC
));
1775 int cbfs_is_legacy_cbfs(struct cbfs_image
*image
)
1777 return image
->has_header
;
1780 int cbfs_is_valid_entry(struct cbfs_image
*image
, struct cbfs_file
*entry
)
1782 uint32_t offset
= cbfs_get_entry_addr(image
, entry
);
1784 if (offset
>= image
->buffer
.size
)
1787 struct buffer entry_data
;
1788 buffer_clone(&entry_data
, &image
->buffer
);
1789 buffer_seek(&entry_data
, offset
);
1790 return buffer_check_magic(&entry_data
, CBFS_FILE_MAGIC
,
1791 strlen(CBFS_FILE_MAGIC
));
1794 struct cbfs_file
*cbfs_create_file_header(int type
,
1795 size_t len
, const char *name
)
1797 size_t header_size
= cbfs_calculate_file_header_size(name
);
1798 if (header_size
> CBFS_METADATA_MAX_SIZE
) {
1799 ERROR("'%s' name too long to fit in CBFS header\n", name
);
1803 struct cbfs_file
*entry
= malloc(CBFS_METADATA_MAX_SIZE
);
1804 memset(entry
, CBFS_CONTENT_DEFAULT_VALUE
, CBFS_METADATA_MAX_SIZE
);
1805 memcpy(entry
->magic
, CBFS_FILE_MAGIC
, sizeof(entry
->magic
));
1806 entry
->type
= htobe32(type
);
1807 entry
->len
= htobe32(len
);
1808 entry
->attributes_offset
= 0;
1809 entry
->offset
= htobe32(header_size
);
1810 memset(entry
->filename
, 0, be32toh(entry
->offset
) - sizeof(*entry
));
1811 strcpy(entry
->filename
, name
);
1815 int cbfs_create_empty_entry(struct cbfs_file
*entry
, int type
,
1816 size_t len
, const char *name
)
1818 struct cbfs_file
*tmp
= cbfs_create_file_header(type
, len
, name
);
1822 memcpy(entry
, tmp
, be32toh(tmp
->offset
));
1824 memset(CBFS_SUBHEADER(entry
), CBFS_CONTENT_DEFAULT_VALUE
, len
);
1828 struct cbfs_file_attribute
*cbfs_file_first_attr(struct cbfs_file
*file
)
1830 /* attributes_offset should be 0 when there is no attribute, but all
1831 * values that point into the cbfs_file header are invalid, too. */
1832 if (be32toh(file
->attributes_offset
) <= sizeof(*file
))
1835 /* There needs to be enough space for the file header and one
1836 * attribute header for this to make sense. */
1837 if (be32toh(file
->offset
) <=
1838 sizeof(*file
) + sizeof(struct cbfs_file_attribute
))
1841 return (struct cbfs_file_attribute
*)
1842 (((uint8_t *)file
) + be32toh(file
->attributes_offset
));
1845 struct cbfs_file_attribute
*cbfs_file_next_attr(struct cbfs_file
*file
,
1846 struct cbfs_file_attribute
*attr
)
1848 /* ex falso sequitur quodlibet */
1852 /* Is there enough space for another attribute? */
1853 if ((uint8_t *)attr
+ be32toh(attr
->len
) +
1854 sizeof(struct cbfs_file_attribute
) >
1855 (uint8_t *)file
+ be32toh(file
->offset
))
1858 struct cbfs_file_attribute
*next
= (struct cbfs_file_attribute
*)
1859 (((uint8_t *)attr
) + be32toh(attr
->len
));
1860 /* If any, "unused" attributes must come last. */
1861 if (be32toh(next
->tag
) == CBFS_FILE_ATTR_TAG_UNUSED
)
1863 if (be32toh(next
->tag
) == CBFS_FILE_ATTR_TAG_UNUSED2
)
1869 struct cbfs_file_attribute
*cbfs_add_file_attr(struct cbfs_file
*header
,
1873 assert(IS_ALIGNED(size
, CBFS_ATTRIBUTE_ALIGN
));
1874 struct cbfs_file_attribute
*attr
, *next
;
1875 next
= cbfs_file_first_attr(header
);
1878 next
= cbfs_file_next_attr(header
, attr
);
1879 } while (next
!= NULL
);
1880 uint32_t header_size
= be32toh(header
->offset
) + size
;
1881 if (header_size
> CBFS_METADATA_MAX_SIZE
) {
1882 DEBUG("exceeding allocated space for cbfs_file headers");
1885 /* attr points to the last valid attribute now.
1886 * If NULL, we have to create the first one. */
1888 /* New attributes start where the header ends.
1889 * header->offset is later set to accommodate the
1890 * additional structure.
1891 * No endianness translation necessary here, because both
1892 * fields are encoded the same way. */
1893 header
->attributes_offset
= header
->offset
;
1894 attr
= (struct cbfs_file_attribute
*)
1895 (((uint8_t *)header
) +
1896 be32toh(header
->attributes_offset
));
1898 attr
= (struct cbfs_file_attribute
*)
1899 (((uint8_t *)attr
) +
1900 be32toh(attr
->len
));
1902 header
->offset
= htobe32(header_size
);
1903 /* Attributes are expected to be small (much smaller than a flash page)
1904 and not really meant to be overwritten in-place. To avoid surprising
1905 values in reserved fields of attribute structures, initialize them to
1907 memset(attr
, 0, size
);
1908 attr
->tag
= htobe32(tag
);
1909 attr
->len
= htobe32(size
);
1913 int cbfs_add_file_hash(struct cbfs_file
*header
, struct buffer
*buffer
,
1914 enum vb2_hash_algorithm alg
)
1916 if (!vb2_digest_size(alg
))
1919 struct cbfs_file_attr_hash
*attr
=
1920 (struct cbfs_file_attr_hash
*)cbfs_add_file_attr(header
,
1921 CBFS_FILE_ATTR_TAG_HASH
, cbfs_file_attr_hash_size(alg
));
1926 if (vb2_hash_calculate(false, buffer_get(buffer
), buffer_size(buffer
),
1927 alg
, &attr
->hash
) != VB2_SUCCESS
)
1933 /* Finds a place to hold whole data in same memory page. */
1934 static int is_in_same_page(uint32_t start
, uint32_t size
, uint32_t page
)
1938 return (start
/ page
) == (start
+ size
- 1) / page
;
1941 /* Tests if data can fit in a range by given offset:
1942 * start ->| metadata_size | offset (+ size) |<- end
1944 static int is_in_range(size_t start
, size_t end
, size_t metadata_size
,
1945 size_t offset
, size_t size
)
1947 return (offset
>= start
+ metadata_size
&& offset
+ size
<= end
);
1950 static size_t absolute_align(const struct cbfs_image
*image
, size_t val
,
1953 const size_t region_offset
= buffer_offset(&image
->buffer
);
1954 /* To perform alignment on absolute address, take the region offset */
1955 /* of the image into account. */
1956 return align_up(val
+ region_offset
, align
) - region_offset
;
1960 int32_t cbfs_locate_entry(struct cbfs_image
*image
, size_t size
,
1961 size_t page_size
, size_t align
, size_t metadata_size
)
1963 struct cbfs_file
*entry
;
1965 size_t addr
, addr_next
, addr2
, addr3
, offset
;
1967 /* Default values: allow fitting anywhere in ROM. */
1969 page_size
= image
->has_header
? image
->header
.romsize
:
1974 if (size
> page_size
)
1975 ERROR("Input file size (%zd) greater than page size (%zd).\n",
1978 size_t image_align
= image
->has_header
? image
->header
.align
:
1980 if (page_size
% image_align
)
1981 WARN("%s: Page size (%#zx) not aligned with CBFS image (%#zx).\n",
1982 __func__
, page_size
, image_align
);
1984 need_len
= metadata_size
+ size
;
1986 // Merge empty entries to build get max available space.
1987 cbfs_legacy_walk(image
, cbfs_merge_empty_entry
, NULL
);
1989 /* Three cases of content location on memory page:
1991 * | PAGE 1 | PAGE 2 |
1992 * | <header><content>| Fit. Return start of content.
1995 * | PAGE 1 | PAGE 2 |
1996 * | <header><content> | Fits when we shift content to align
1997 * shift-> | <header>|<content> | at starting of PAGE 2.
1999 * case 3. (large content filling whole page)
2000 * | PAGE 1 | PAGE 2 | PAGE 3 |
2001 * | <header>< content > | Can't fit. If we shift content to
2002 * |trial-> <header>< content > | PAGE 2, header can't fit in free
2003 * | shift-> <header><content> space, so we must use PAGE 3.
2005 * The returned address can be then used as "base-address" (-b) in add-*
2006 * commands (will be re-calculated and positioned by cbfs_add_entry_at).
2007 * For stage targets, the address is also used to re-link stage before
2008 * being added into CBFS.
2010 for (entry
= cbfs_find_first_entry(image
);
2011 entry
&& cbfs_is_valid_entry(image
, entry
);
2012 entry
= cbfs_find_next_entry(image
, entry
)) {
2014 uint32_t type
= be32toh(entry
->type
);
2015 if (type
!= CBFS_TYPE_NULL
)
2018 addr
= cbfs_get_entry_addr(image
, entry
);
2019 addr_next
= cbfs_get_entry_addr(image
, cbfs_find_next_entry(
2021 if (addr_next
- addr
< need_len
)
2024 offset
= absolute_align(image
, addr
+ metadata_size
, align
);
2025 if (is_in_same_page(offset
, size
, page_size
) &&
2026 is_in_range(addr
, addr_next
, metadata_size
, offset
, size
)) {
2027 DEBUG("cbfs_locate_entry: FIT (PAGE1).");
2031 addr2
= align_up(addr
, page_size
);
2032 offset
= absolute_align(image
, addr2
, align
);
2033 if (is_in_range(addr
, addr_next
, metadata_size
, offset
, size
)) {
2034 DEBUG("cbfs_locate_entry: OVERLAP (PAGE2).");
2038 /* Assume page_size >= metadata_size so adding one page will
2039 * definitely provide the space for header. */
2040 assert(page_size
>= metadata_size
);
2041 addr3
= addr2
+ page_size
;
2042 offset
= absolute_align(image
, addr3
, align
);
2043 if (is_in_range(addr
, addr_next
, metadata_size
, offset
, size
)) {
2044 DEBUG("cbfs_locate_entry: OVERLAP+ (PAGE3).");