2020-05-08 19:28:13 +02:00
|
|
|
/* CBFS Image Manipulation */
|
util/: Replace GPLv2 boiler plate with SPDX header
Used commands:
perl -i -p0e 's|\/\*[\s*]*.*is free software[:;][\s*]*you[\s*]*can[\s*]*redistribute[\s*]*it[\s*]*and\/or[\s*]*modify[\s*]*it[\s*]*under[\s*]*the[\s*]*terms[\s*]*of[\s*]*the[\s*]*GNU[\s*]*General[\s*]*Public[\s*]*License[\s*]*as[\s*]*published[\s*]*by[\s*]*the[\s*]*Free[\s*]*Software[\s*]*Foundation[;,][\s*]*version[\s*]*2[\s*]*of[\s*]*the[\s*]*License.[\s*]*This[\s*]*program[\s*]*is[\s*]*distributed[\s*]*in[\s*]*the[\s*]*hope[\s*]*that[\s*]*it[\s*]*will[\s*]*be[\s*]*useful,[\s*]*but[\s*]*WITHOUT[\s*]*ANY[\s*]*WARRANTY;[\s*]*without[\s*]*even[\s*]*the[\s*]*implied[\s*]*warranty[\s*]*of[\s*]*MERCHANTABILITY[\s*]*or[\s*]*FITNESS[\s*]*FOR[\s*]*A[\s*]*PARTICULAR[\s*]*PURPOSE.[\s*]*See[\s*]*the[\s*]*GNU[\s*]*General[\s*]*Public[\s*]*License[\s*]*for[\s*]*more[\s*]*details.[\s*]*\*\/|/* SPDX-License-Identifier: GPL-2.0-only */|' $(cat filelist)
perl -i -p0e 's|This[\s*]*program[\s*]*is[\s*]*free[\s*]*software[:;][\s*]*you[\s*]*can[\s*]*redistribute[\s*]*it[\s*]*and/or[\s*]*modify[\s*]*it[\s*]*under[\s*]*the[\s*]*terms[\s*]*of[\s*]*the[\s*]*GNU[\s*]*General[\s*]*Public[\s*]*License[\s*]*as[\s*]*published[\s*]*by[\s*]*the[\s*]*Free[\s*]*Software[\s*]*Foundation[;,][\s*]*either[\s*]*version[\s*]*2[\s*]*of[\s*]*the[\s*]*License,[\s*]*or[\s*]*.at[\s*]*your[\s*]*option.*[\s*]*any[\s*]*later[\s*]*version.[\s*]*This[\s*]*program[\s*]*is[\s*]*distributed[\s*]*in[\s*]*the[\s*]*hope[\s*]*that[\s*]*it[\s*]*will[\s*]*be[\s*]*useful,[\s*]*but[\s*]*WITHOUT[\s*]*ANY[\s*]*WARRANTY;[\s*]*without[\s*]*even[\s*]*the[\s*]*implied[\s*]*warranty[\s*]*of[\s*]*MERCHANTABILITY[\s*]*or[\s*]*FITNESS[\s*]*FOR[\s*]*A[\s*]*PARTICULAR[\s*]*PURPOSE.[\s*]*See[\s*]*the[\s*]*GNU[\s*]*General[\s*]*Public[\s*]*License[\s*]*for[\s*]*more[\s*]*details.[\s*]*\*\/|/* SPDX-License-Identifier: GPL-2.0-or-later */|' $(cat filelist)
perl -i -p0e 's|\/\*[\s*]*.*This[\s*#]*program[\s*#]*is[\s*#]*free[\s*#]*software[;:,][\s*#]*you[\s*#]*can[\s*#]*redistribute[\s*#]*it[\s*#]*and/or[\s*#]*modify[\s*#]*it[\s*#]*under[\s*#]*the[\s*#]*terms[\s*#]*of[\s*#]*the[\s*#]*GNU[\s*#]*General[\s*#]*Public[\s*#]*License[\s*#]*as[\s*#]*published[\s*#]*by[\s*#]*the[\s*#]*Free[\s*#]*Software[\s*#]*Foundation[;:,][\s*#]*either[\s*#]*version[\s*#]*3[\s*#]*of[\s*#]*the[\s*#]*License[;:,][\s*#]*or[\s*#]*.at[\s*#]*your[\s*#]*option.*[\s*#]*any[\s*#]*later[\s*#]*version.[\s*#]*This[\s*#]*program[\s*#]*is[\s*#]*distributed[\s*#]*in[\s*#]*the[\s*#]*hope[\s*#]*that[\s*#]*it[\s*#]*will[\s*#]*be[\s*#]*useful[;:,][\s*#]*but[\s*#]*WITHOUT[\s*#]*ANY[\s*#]*WARRANTY[;:,][\s*#]*without[\s*#]*even[\s*#]*the[\s*#]*implied[\s*#]*warranty[\s*#]*of[\s*#]*MERCHANTABILITY[\s*#]*or[\s*#]*FITNESS[\s*#]*FOR[\s*#]*A[\s*#]*PARTICULAR[\s*#]*PURPOSE.[\s*#]*See[\s*#]*the[\s*#]*GNU[\s*#]*General[\s*#]*Public[\s*#]*License[\s*#]*for[\s*#]*more[\s*#]*details.[\s*]*\*\/|/* SPDX-License-Identifier: GPL-3.0-or-later */|' $(cat filelist)
perl -i -p0e 's|(\#\#*)[\w]*.*is free software[:;][\#\s]*you[\#\s]*can[\#\s]*redistribute[\#\s]*it[\#\s]*and\/or[\#\s]*modify[\#\s]*it[\s\#]*under[\s \#]*the[\s\#]*terms[\s\#]*of[\s\#]*the[\s\#]*GNU[\s\#]*General[\s\#]*Public[\s\#]*License[\s\#]*as[\s\#]*published[\s\#]*by[\s\#]*the[\s\#]*Free[\s\#]*Software[\s\#]*Foundation[;,][\s\#]*version[\s\#]*2[\s\#]*of[\s\#]*the[\s\#]*License.*[\s\#]*This[\s\#]*program[\s\#]*is[\s\#]*distributed[\s\#]*in[\s\#]*the[\s\#]*hope[\s\#]*that[\s\#]*it[\s\#]*will[\#\s]*be[\#\s]*useful,[\#\s]*but[\#\s]*WITHOUT[\#\s]*ANY[\#\s]*WARRANTY;[\#\s]*without[\#\s]*even[\#\s]*the[\#\s]*implied[\#\s]*warranty[\#\s]*of[\#\s]*MERCHANTABILITY[\#\s]*or[\#\s]*FITNESS[\#\s]*FOR[\#\s]*A[\#\s]*PARTICULAR[\#\s]*PURPOSE.[\#\s]*See[\#\s]*the[\#\s]*GNU[\#\s]*General[\#\s]*Public[\#\s]*License[\#\s]*for[\#\s]*more[\#\s]*details.\s(#* *\n)*|\1 SPDX-License-Identifier: GPL-2.0-only\n\n|' $(cat filelist)
perl -i -p0e 's|(\#\#*)[\w*]*.*is free software[:;][\s*]*you[\s*]*can[\s*]*redistribute[\s*]*it[\s*]*and\/or[\s*]*modify[\s*]*it[\s*]*under[\s*]*the[\s*]*terms[\s*]*of[\s*]*the[\s*]*GNU[\s*]*General[\s*]*Public[\s*]*License[\s*]*as[\s*]*published[\s*]*by[\s*]*the[\s*]*Free[\s*]*Software[\s*]*Foundation[;,][\s*]*version[\s*]*2[\s*]*of[\s*]*the[\s*]*License.[\s*]*This[\s*]*program[\s*]*is[\s*]*distributed[\s*]*in[\s*]*the[\s*]*hope[\s*]*that[\s*]*it[\s*]*will[\s*]*be[\s*]*useful,[\s*]*but[\s*]*WITHOUT[\s*]*ANY[\s*]*WARRANTY;[\s*]*without[\s*]*even[\s*]*the[\s*]*implied[\s*]*warranty[\s*]*of[\s*]*MERCHANTABILITY[\s*]*or[\s*]*FITNESS[\s*]*FOR[\s*]*A[\s*]*PARTICULAR[\s*]*PURPOSE.[\s*]*See[\s*]*the[\s*]*GNU[\s*]*General[\s*]*Public[\s*]*License[\s*]*for[\s*]*more[\s*]*details.\s(#* *\n)*|\1 SPDX-License-Identifier: GPL-2.0-only\n\n|' $(cat filelist)
Change-Id: I1008a63b804f355a916221ac994701d7584f60ff
Signed-off-by: Patrick Georgi <pgeorgi@google.com>
Signed-off-by: Elyes HAOUAS <ehaouas@noos.fr>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41177
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-05-08 20:48:04 +02:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
2013-01-28 18:56:17 +01:00
|
|
|
|
2013-01-28 19:15:49 +01:00
|
|
|
#include <inttypes.h>
|
|
|
|
#include <libgen.h>
|
2015-04-28 13:09:36 +02:00
|
|
|
#include <stddef.h>
|
2013-01-28 18:56:17 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2015-03-06 00:38:03 +01:00
|
|
|
#include <strings.h>
|
2016-06-09 12:35:36 +02:00
|
|
|
#include <commonlib/endian.h>
|
2019-04-25 11:45:12 +02:00
|
|
|
#include <vb2_sha.h>
|
2013-01-28 18:56:17 +01:00
|
|
|
|
|
|
|
#include "common.h"
|
|
|
|
#include "cbfs_image.h"
|
2015-10-28 03:02:30 +01:00
|
|
|
#include "elfparsing.h"
|
2015-10-28 17:39:34 +01:00
|
|
|
#include "rmodule.h"
|
2013-01-28 18:56:17 +01:00
|
|
|
|
cbfstool: Make the add action choose an aligned entries capacity
This fixes an inconsistency between `cbfstool create` and `cbfstool add` that
was resulting in confusing claims about the amount of free space at the end of a
CBFS. Calls to `cbfstool add` check whether a file fits under a given empty file
entry by testing whether it would collide with the beginning of the *subsequent*
file header; thus, if a file's end is unaligned, its reported size will not
match the actual available capacity. Although deleted entries always end on an
alignment boundary because `cbfstool remove` expands them to fill the available
space, `cbfstool create` doesn't necessarily size a new entries region to result
in an empty entry with an aligned end.
This problem never resulted in clobbering important data because cbfstool would
blindly reserve 64B (or the selected alignment) of free space immediately after
the all-inclusive empty file entry. This change alters the way this reservation
is reported: only the overhang past the alignment is used as hidden padding, and
the empty entry's capacity is always reported such that it ends at an aligned
address.
Much of the time that went into this patch was spent building trust in the
trickery cbfstool employs to avoid explicitly tracking the image's total
capacity for entries, so below are two proofs of correctness to save others time
and discourage inadvertent breakage:
OBSERVATION (A): A check in cbfs_image_create() guarantees that an aligned CBFS
empty file header is small enough that it won't cross another aligned address.
OBSERVATION (B): In cbfs_image_create(), the initial empty entry is sized such
that its contents end on an aligned address.
THM. 1: Placing a new file within an empty entry located below an existing file
entry will never leave an aligned flash address containing neither the beginning
of a file header nor part of a file.
We can prove this by contradiction: assume a newly-added file neither fills to
the end of the preexisting empty entry nor leaves room for another aligned
empty header after it. Then the first aligned address after the end of the
newly-inserted file...
- CASE 1: ...already contains a preexisting file entry header.
+ Then that address contains a file header.
- CASE 2: ...does not already house a file entry header.
+ Then because CBFS content doesn't fall outside headers, the area between
there and the *next* aligned address after that is unused.
+ By (A), we can fit a file header without clobbering anything.
+ Then that address now contains a file header.
THM. 2: Placing a new file in an empty entry at the very end of the image such
that it fits, but leaves no room for a final header, is guaranteed not to change
the total amount of space for entries, even if that new file is later removed
from the CBFS.
Again, we use contradiction: assume that creating such a file causes a
permanent...
- CASE 1: ...increase in the amount of available space.
+ Then the combination of the inserted file, its header, and any padding
must have exceeded the empty entry in size enough for it to cross at
least one additional aligned address, since aligned addresses are how
the limit on an entry's capacity is determined.
+ But adding the file couldn't have caused us to write past any further
aligned addresses because they are the boundary's used when verifying
that sufficient capacity exists; furthermore, by (B), no entry can ever
terminate beyond where the initial empty entry did when the CBFS was
first created.
+ Then the creation of the file did not result in a space increase.
- CASE 2: ...decrease in the amount of available space.
+ Then the end of the new file entry crosses at least one fewer aligned
address than did the empty file entry.
+ Then by (A), there is room to place a new file entry that describes the
remaining available space at the first available aligned address.
+ Then there is now a new record showing the same amount of available space.
+ Then the creation of the file did not result in a space decrease.
BUG=chromium:473726
TEST=Had the following conversation with cbfstool:
$ ./cbfstool test.image create -s 0x100000 -m arm
Created CBFS image (capacity = 1048408 bytes)
$ ./cbfstool test.image print
test.image: 1024 kB, bootblocksize 0, romsize 1048576, offset 0x40
alignment: 64 bytes, architecture: arm
Name Offset Type Size
(empty) 0x40 null 1048408
$ dd if=/dev/zero of=toobigmed.bin bs=1048409 count=1
1+0 records in
1+0 records out
1048409 bytes (1.0 MB) copied, 0.0057865 s, 181 MB/s
$ ./cbfstool test.image add -t 0x50 -f toobigmed.bin -n toobig
E: Could not add [toobigmed.bin, 1048409 bytes (1023 KB)@0x0]; too big?
E: Failed to add 'toobigmed.bin' into ROM image.
$ truncate -s -1 toobigmed.bin
$ ./cbfstool test.image add -t 0x50 -f toobigmed.bin -n toobig
$ ./cbfstool test.image print
test.image: 1024 kB, bootblocksize 0, romsize 1048576, offset 0x40
alignment: 64 bytes, architecture: arm
Name Offset Type Size
toobig 0x40 raw 1048408
$ ./cbfstool test.image remove
-n toobig
$ ./cbfstool test.image print
test.image: 1024 kB, bootblocksize 0, romsize 1048576, offset 0x40
alignment: 64 bytes, architecture: arm
Name Offset Type Size
(empty) 0x40 deleted 1048408
$ ./cbfstool test.image print
test.image: 1024 kB, bootblocksize 0, romsize 1048576, offset 0x40
alignment: 64 bytes, architecture: arm
Name Offset Type Size
(empty) 0x40 deleted 1048408
BRANCH=None
Change-Id: I118743e37469ef0226970decc900db5d9b92c5df
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: e317ddca14bc36bc36e6406b758378c88e9ae04e
Original-Change-Id: I294ee489b4918646c359b06aa1581918f2d8badc
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/263962
Original-Reviewed-by: Hung-Te Lin <hungte@chromium.org>
Original-Reviewed-by: Stefan Reinauer <reinauer@google.com>
Reviewed-on: http://review.coreboot.org/9939
Tested-by: build bot (Jenkins)
2015-04-03 18:13:04 +02:00
|
|
|
/* Even though the file-adding functions---cbfs_add_entry() and
|
|
|
|
* cbfs_add_entry_at()---perform their sizing checks against the beginning of
|
|
|
|
* the subsequent section rather than a stable recorded value such as an empty
|
|
|
|
* file header's len field, it's possible to prove two interesting properties
|
|
|
|
* about their behavior:
|
|
|
|
* - Placing a new file within an empty entry located below an existing file
|
|
|
|
* entry will never leave an aligned flash address containing neither the
|
|
|
|
* beginning of a file header nor part of a file.
|
|
|
|
* - Placing a new file in an empty entry at the very end of the image such
|
|
|
|
* that it fits, but leaves no room for a final header, is guaranteed not to
|
|
|
|
* change the total amount of space for entries, even if that new file is
|
|
|
|
* later removed from the CBFS.
|
|
|
|
* These properties are somewhat nonobvious from the implementation, so the
|
|
|
|
* reader is encouraged to blame this comment and examine the full proofs
|
|
|
|
* in the commit message before making significant changes that would risk
|
|
|
|
* removing said guarantees.
|
|
|
|
*/
|
|
|
|
|
2013-01-28 18:56:17 +01:00
|
|
|
/* The file name align is not defined in CBFS spec -- only a preference by
|
|
|
|
* (old) cbfstool. */
|
|
|
|
#define CBFS_FILENAME_ALIGN (16)
|
|
|
|
|
2013-12-03 20:13:35 +01:00
|
|
|
static const char *lookup_name_by_type(const struct typedesc_t *desc, uint32_t type,
|
2013-03-26 20:51:36 +01:00
|
|
|
const char *default_value)
|
|
|
|
{
|
2013-01-28 19:15:49 +01:00
|
|
|
int i;
|
|
|
|
for (i = 0; desc[i].name; i++)
|
|
|
|
if (desc[i].type == type)
|
|
|
|
return desc[i].name;
|
|
|
|
return default_value;
|
|
|
|
}
|
|
|
|
|
2015-05-08 06:00:05 +02:00
|
|
|
static int lookup_type_by_name(const struct typedesc_t *desc, const char *name)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; desc[i].name && strcasecmp(name, desc[i].name); ++i);
|
|
|
|
return desc[i].name ? (int)desc[i].type : -1;
|
|
|
|
}
|
|
|
|
|
2015-03-04 00:55:03 +01:00
|
|
|
static const char *get_cbfs_entry_type_name(uint32_t type)
|
2013-03-26 20:51:36 +01:00
|
|
|
{
|
2015-09-09 16:46:00 +02:00
|
|
|
return lookup_name_by_type(filetypes, type, "(unknown)");
|
2013-01-28 19:15:49 +01:00
|
|
|
}
|
|
|
|
|
2015-05-08 06:00:05 +02:00
|
|
|
int cbfs_parse_comp_algo(const char *name)
|
|
|
|
{
|
|
|
|
return lookup_type_by_name(types_cbfs_compression, name);
|
|
|
|
}
|
|
|
|
|
2015-10-01 15:54:04 +02:00
|
|
|
static const char *get_hash_attr_name(uint16_t hash_type)
|
|
|
|
{
|
|
|
|
return lookup_name_by_type(types_cbfs_hash, hash_type, "(invalid)");
|
|
|
|
}
|
|
|
|
|
|
|
|
int cbfs_parse_hash_algo(const char *name)
|
|
|
|
{
|
|
|
|
return lookup_type_by_name(types_cbfs_hash, name);
|
|
|
|
}
|
|
|
|
|
2013-01-28 19:38:40 +01:00
|
|
|
/* CBFS image */
|
|
|
|
|
2015-08-11 15:10:02 +02:00
|
|
|
size_t cbfs_calculate_file_header_size(const char *name)
|
2013-03-26 20:51:36 +01:00
|
|
|
{
|
2013-01-28 19:38:40 +01:00
|
|
|
return (sizeof(struct cbfs_file) +
|
|
|
|
align_up(strlen(name) + 1, CBFS_FILENAME_ALIGN));
|
|
|
|
}
|
|
|
|
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
/* Only call on legacy CBFSes possessing a master header. */
|
2014-02-05 08:10:08 +01:00
|
|
|
static int cbfs_fix_legacy_size(struct cbfs_image *image, char *hdr_loc)
|
2013-03-26 20:51:36 +01:00
|
|
|
{
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
assert(image);
|
|
|
|
assert(cbfs_is_legacy_cbfs(image));
|
2013-01-28 20:16:20 +01:00
|
|
|
// A bug in old cbfstool may produce extra few bytes (by alignment) and
|
|
|
|
// cause cbfstool to overwrite things after free space -- which is
|
|
|
|
// usually CBFS header on x86. We need to workaround that.
|
2016-02-10 18:07:52 +01:00
|
|
|
// Except when we run across a file that contains the actual header,
|
|
|
|
// in which case this image is a safe, new-style
|
|
|
|
// `cbfstool add-master-header` based image.
|
2013-01-28 20:16:20 +01:00
|
|
|
|
|
|
|
struct cbfs_file *entry, *first = NULL, *last = NULL;
|
|
|
|
for (first = entry = cbfs_find_first_entry(image);
|
2013-02-09 03:38:55 +01:00
|
|
|
entry && cbfs_is_valid_entry(image, entry);
|
2013-01-28 20:16:20 +01:00
|
|
|
entry = cbfs_find_next_entry(image, entry)) {
|
2016-02-10 18:07:52 +01:00
|
|
|
/* Is the header guarded by a CBFS file entry? Then exit */
|
|
|
|
if (((char *)entry) + ntohl(entry->offset) == hdr_loc) {
|
|
|
|
return 0;
|
|
|
|
}
|
2013-01-28 20:16:20 +01:00
|
|
|
last = entry;
|
|
|
|
}
|
2014-02-05 08:10:08 +01:00
|
|
|
if ((char *)first < (char *)hdr_loc &&
|
|
|
|
(char *)entry > (char *)hdr_loc) {
|
2013-01-28 20:16:20 +01:00
|
|
|
WARN("CBFS image was created with old cbfstool with size bug. "
|
|
|
|
"Fixing size in last entry...\n");
|
2015-05-06 00:40:15 +02:00
|
|
|
last->len = htonl(ntohl(last->len) - image->header.align);
|
2013-01-28 20:16:20 +01:00
|
|
|
DEBUG("Last entry has been changed from 0x%x to 0x%x.\n",
|
|
|
|
cbfs_get_entry_addr(image, entry),
|
|
|
|
cbfs_get_entry_addr(image,
|
|
|
|
cbfs_find_next_entry(image, last)));
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-01-06 17:38:15 +01:00
|
|
|
void cbfs_put_header(void *dest, const struct cbfs_header *header)
|
|
|
|
{
|
|
|
|
struct buffer outheader;
|
|
|
|
|
|
|
|
outheader.data = dest;
|
|
|
|
outheader.size = 0;
|
|
|
|
|
|
|
|
xdr_be.put32(&outheader, header->magic);
|
|
|
|
xdr_be.put32(&outheader, header->version);
|
|
|
|
xdr_be.put32(&outheader, header->romsize);
|
|
|
|
xdr_be.put32(&outheader, header->bootblocksize);
|
|
|
|
xdr_be.put32(&outheader, header->align);
|
|
|
|
xdr_be.put32(&outheader, header->offset);
|
|
|
|
xdr_be.put32(&outheader, header->architecture);
|
|
|
|
}
|
2014-02-05 08:10:08 +01:00
|
|
|
|
2014-05-16 04:14:05 +02:00
|
|
|
static void cbfs_decode_payload_segment(struct cbfs_payload_segment *output,
|
|
|
|
struct cbfs_payload_segment *input)
|
|
|
|
{
|
|
|
|
struct buffer seg = {
|
|
|
|
.data = (void *)input,
|
|
|
|
.size = sizeof(*input),
|
|
|
|
};
|
|
|
|
output->type = xdr_be.get32(&seg);
|
|
|
|
output->compression = xdr_be.get32(&seg);
|
|
|
|
output->offset = xdr_be.get32(&seg);
|
|
|
|
output->load_addr = xdr_be.get64(&seg);
|
|
|
|
output->len = xdr_be.get32(&seg);
|
|
|
|
output->mem_len = xdr_be.get32(&seg);
|
|
|
|
assert(seg.size == 0);
|
|
|
|
}
|
|
|
|
|
2015-08-26 12:23:26 +02:00
|
|
|
static int cbfs_file_get_compression_info(struct cbfs_file *entry,
|
|
|
|
uint32_t *decompressed_size)
|
|
|
|
{
|
|
|
|
unsigned int compression = CBFS_COMPRESS_NONE;
|
2016-12-14 16:08:52 +01:00
|
|
|
if (decompressed_size)
|
|
|
|
*decompressed_size = ntohl(entry->len);
|
2015-08-26 12:23:26 +02:00
|
|
|
for (struct cbfs_file_attribute *attr = cbfs_file_first_attr(entry);
|
|
|
|
attr != NULL;
|
|
|
|
attr = cbfs_file_next_attr(entry, attr)) {
|
|
|
|
if (ntohl(attr->tag) == CBFS_FILE_ATTR_TAG_COMPRESSION) {
|
|
|
|
struct cbfs_file_attr_compression *ac =
|
|
|
|
(struct cbfs_file_attr_compression *)attr;
|
|
|
|
compression = ntohl(ac->compression);
|
|
|
|
if (decompressed_size)
|
|
|
|
*decompressed_size =
|
|
|
|
ntohl(ac->decompressed_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return compression;
|
|
|
|
}
|
|
|
|
|
2015-10-01 15:54:04 +02:00
|
|
|
static struct cbfs_file_attr_hash *cbfs_file_get_next_hash(
|
|
|
|
struct cbfs_file *entry, struct cbfs_file_attr_hash *cur)
|
|
|
|
{
|
|
|
|
struct cbfs_file_attribute *attr = (struct cbfs_file_attribute *)cur;
|
|
|
|
if (attr == NULL) {
|
|
|
|
attr = cbfs_file_first_attr(entry);
|
|
|
|
if (attr == NULL)
|
|
|
|
return NULL;
|
|
|
|
if (ntohl(attr->tag) == CBFS_FILE_ATTR_TAG_HASH)
|
|
|
|
return (struct cbfs_file_attr_hash *)attr;
|
|
|
|
}
|
|
|
|
while ((attr = cbfs_file_next_attr(entry, attr)) != NULL) {
|
|
|
|
if (ntohl(attr->tag) == CBFS_FILE_ATTR_TAG_HASH)
|
|
|
|
return (struct cbfs_file_attr_hash *)attr;
|
|
|
|
};
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-03-06 00:38:03 +01:00
|
|
|
void cbfs_get_header(struct cbfs_header *header, void *src)
|
2014-02-05 08:10:08 +01:00
|
|
|
{
|
|
|
|
struct buffer outheader;
|
|
|
|
|
2015-03-06 00:38:03 +01:00
|
|
|
outheader.data = src; /* We're not modifying the data */
|
2014-02-05 08:10:08 +01:00
|
|
|
outheader.size = 0;
|
|
|
|
|
|
|
|
header->magic = xdr_be.get32(&outheader);
|
|
|
|
header->version = xdr_be.get32(&outheader);
|
|
|
|
header->romsize = xdr_be.get32(&outheader);
|
|
|
|
header->bootblocksize = xdr_be.get32(&outheader);
|
|
|
|
header->align = xdr_be.get32(&outheader);
|
|
|
|
header->offset = xdr_be.get32(&outheader);
|
|
|
|
header->architecture = xdr_be.get32(&outheader);
|
|
|
|
}
|
|
|
|
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
int cbfs_image_create(struct cbfs_image *image, size_t entries_size)
|
2013-01-29 02:45:12 +01:00
|
|
|
{
|
cbfstool: Restructure around support for reading/writing portions of files
The buffer API that cbfstool uses to read and write files only directly supports
one-shot operations on whole files. This adds an intermediate partitioned_file
module that sits on top of the buffer system and has an awareness of FMAP
entries. It provides an easy way to get a buffer for an individual region of a
larger image file based on FMAP section name, as well as incrementally write
those smaller buffers back to the backing file at the appropriate offset. The
module has two distinct modes of operation:
- For new images whose layout is described exclusively by an FMAP section, all
the aforementioned functionality will be available.
- For images in the current format, where the CBFS master header serves as the
root of knowledge of the image's size and layout, the module falls back to a
legacy operation mode, where it only allows manipulation of the entire image
as one unit, but exposes this support through the same interface by mapping
the region named SECTION_NAME_PRIMARY_CBFS ("COREBOOT") to the whole file.
The tool is presently only ported onto the new module running in legacy mode:
higher-level support for true "partitioned" images will be forthcoming. However,
as part of this change, the crusty cbfs_image_from_file() and
cbfs_image_write_file() abstractions are removed and replaced with a single
cbfs_image function, cbfs_image_from_buffer(), as well as centralized image
reading/writing directly in cbfstool's main() function. This reduces the
boilerplate required to implement each new action, makes the create action much
more similar to the others, and will make implementing additional actions and
adding in support for the new format much easier.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom images with and without this patch
and diff their hexdumps. Ensure that no differences occur at different locations
from the diffs between subsequent builds of an identical source tree. Then flash
a full new build onto nyan_big and watch it boot normally.
BRANCH=None
Change-Id: I25578c7b223bc8434c3074cb0dd8894534f8c500
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 7e1c96a48e7a27fc6b90289d35e6e169d5e7ad20
Original-Change-Id: Ia4a1a4c48df42b9ec2d6b9471b3a10eb7b24bb39
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265581
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10134
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
2015-03-25 21:40:08 +01:00
|
|
|
assert(image);
|
|
|
|
assert(image->buffer.data);
|
|
|
|
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
size_t empty_header_len = cbfs_calculate_file_header_size("");
|
|
|
|
uint32_t entries_offset = 0;
|
|
|
|
uint32_t align = CBFS_ENTRY_ALIGNMENT;
|
|
|
|
if (image->has_header) {
|
|
|
|
entries_offset = image->header.offset;
|
2013-01-29 02:45:12 +01:00
|
|
|
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
if (entries_offset > image->buffer.size) {
|
|
|
|
ERROR("CBFS file entries are located outside CBFS itself\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
align = image->header.align;
|
|
|
|
}
|
2013-01-29 02:45:12 +01:00
|
|
|
|
cbfstool: Make the add action choose an aligned entries capacity
This fixes an inconsistency between `cbfstool create` and `cbfstool add` that
was resulting in confusing claims about the amount of free space at the end of a
CBFS. Calls to `cbfstool add` check whether a file fits under a given empty file
entry by testing whether it would collide with the beginning of the *subsequent*
file header; thus, if a file's end is unaligned, its reported size will not
match the actual available capacity. Although deleted entries always end on an
alignment boundary because `cbfstool remove` expands them to fill the available
space, `cbfstool create` doesn't necessarily size a new entries region to result
in an empty entry with an aligned end.
This problem never resulted in clobbering important data because cbfstool would
blindly reserve 64B (or the selected alignment) of free space immediately after
the all-inclusive empty file entry. This change alters the way this reservation
is reported: only the overhang past the alignment is used as hidden padding, and
the empty entry's capacity is always reported such that it ends at an aligned
address.
Much of the time that went into this patch was spent building trust in the
trickery cbfstool employs to avoid explicitly tracking the image's total
capacity for entries, so below are two proofs of correctness to save others time
and discourage inadvertent breakage:
OBSERVATION (A): A check in cbfs_image_create() guarantees that an aligned CBFS
empty file header is small enough that it won't cross another aligned address.
OBSERVATION (B): In cbfs_image_create(), the initial empty entry is sized such
that its contents end on an aligned address.
THM. 1: Placing a new file within an empty entry located below an existing file
entry will never leave an aligned flash address containing neither the beginning
of a file header nor part of a file.
We can prove this by contradiction: assume a newly-added file neither fills to
the end of the preexisting empty entry nor leaves room for another aligned
empty header after it. Then the first aligned address after the end of the
newly-inserted file...
- CASE 1: ...already contains a preexisting file entry header.
+ Then that address contains a file header.
- CASE 2: ...does not already house a file entry header.
+ Then because CBFS content doesn't fall outside headers, the area between
there and the *next* aligned address after that is unused.
+ By (A), we can fit a file header without clobbering anything.
+ Then that address now contains a file header.
THM. 2: Placing a new file in an empty entry at the very end of the image such
that it fits, but leaves no room for a final header, is guaranteed not to change
the total amount of space for entries, even if that new file is later removed
from the CBFS.
Again, we use contradiction: assume that creating such a file causes a
permanent...
- CASE 1: ...increase in the amount of available space.
+ Then the combination of the inserted file, its header, and any padding
must have exceeded the empty entry in size enough for it to cross at
least one additional aligned address, since aligned addresses are how
the limit on an entry's capacity is determined.
+ But adding the file couldn't have caused us to write past any further
aligned addresses because they are the boundary's used when verifying
that sufficient capacity exists; furthermore, by (B), no entry can ever
terminate beyond where the initial empty entry did when the CBFS was
first created.
+ Then the creation of the file did not result in a space increase.
- CASE 2: ...decrease in the amount of available space.
+ Then the end of the new file entry crosses at least one fewer aligned
address than did the empty file entry.
+ Then by (A), there is room to place a new file entry that describes the
remaining available space at the first available aligned address.
+ Then there is now a new record showing the same amount of available space.
+ Then the creation of the file did not result in a space decrease.
BUG=chromium:473726
TEST=Had the following conversation with cbfstool:
$ ./cbfstool test.image create -s 0x100000 -m arm
Created CBFS image (capacity = 1048408 bytes)
$ ./cbfstool test.image print
test.image: 1024 kB, bootblocksize 0, romsize 1048576, offset 0x40
alignment: 64 bytes, architecture: arm
Name Offset Type Size
(empty) 0x40 null 1048408
$ dd if=/dev/zero of=toobigmed.bin bs=1048409 count=1
1+0 records in
1+0 records out
1048409 bytes (1.0 MB) copied, 0.0057865 s, 181 MB/s
$ ./cbfstool test.image add -t 0x50 -f toobigmed.bin -n toobig
E: Could not add [toobigmed.bin, 1048409 bytes (1023 KB)@0x0]; too big?
E: Failed to add 'toobigmed.bin' into ROM image.
$ truncate -s -1 toobigmed.bin
$ ./cbfstool test.image add -t 0x50 -f toobigmed.bin -n toobig
$ ./cbfstool test.image print
test.image: 1024 kB, bootblocksize 0, romsize 1048576, offset 0x40
alignment: 64 bytes, architecture: arm
Name Offset Type Size
toobig 0x40 raw 1048408
$ ./cbfstool test.image remove
-n toobig
$ ./cbfstool test.image print
test.image: 1024 kB, bootblocksize 0, romsize 1048576, offset 0x40
alignment: 64 bytes, architecture: arm
Name Offset Type Size
(empty) 0x40 deleted 1048408
$ ./cbfstool test.image print
test.image: 1024 kB, bootblocksize 0, romsize 1048576, offset 0x40
alignment: 64 bytes, architecture: arm
Name Offset Type Size
(empty) 0x40 deleted 1048408
BRANCH=None
Change-Id: I118743e37469ef0226970decc900db5d9b92c5df
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: e317ddca14bc36bc36e6406b758378c88e9ae04e
Original-Change-Id: I294ee489b4918646c359b06aa1581918f2d8badc
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/263962
Original-Reviewed-by: Hung-Te Lin <hungte@chromium.org>
Original-Reviewed-by: Stefan Reinauer <reinauer@google.com>
Reviewed-on: http://review.coreboot.org/9939
Tested-by: build bot (Jenkins)
2015-04-03 18:13:04 +02:00
|
|
|
// This attribute must be given in order to prove that this module
|
|
|
|
// correctly preserves certain CBFS properties. See the block comment
|
|
|
|
// near the top of this file (and the associated commit message).
|
|
|
|
if (align < empty_header_len) {
|
|
|
|
ERROR("CBFS must be aligned to at least %zu bytes\n",
|
|
|
|
empty_header_len);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
if (entries_size > image->buffer.size - entries_offset) {
|
|
|
|
ERROR("CBFS doesn't have enough space to fit its file entries\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (empty_header_len > entries_size) {
|
|
|
|
ERROR("CBFS is too small to fit any header\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
struct cbfs_file *entry_header =
|
|
|
|
(struct cbfs_file *)(image->buffer.data + entries_offset);
|
|
|
|
// This alignment is necessary in order to prove that this module
|
|
|
|
// correctly preserves certain CBFS properties. See the block comment
|
|
|
|
// near the top of this file (and the associated commit message).
|
|
|
|
entries_size -= entries_size % align;
|
|
|
|
|
|
|
|
size_t capacity = entries_size - empty_header_len;
|
|
|
|
LOG("Created CBFS (capacity = %zu bytes)\n", capacity);
|
2015-08-12 09:12:06 +02:00
|
|
|
return cbfs_create_empty_entry(entry_header, CBFS_COMPONENT_NULL,
|
|
|
|
capacity, "");
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int cbfs_legacy_image_create(struct cbfs_image *image,
|
|
|
|
uint32_t architecture,
|
|
|
|
uint32_t align,
|
|
|
|
struct buffer *bootblock,
|
|
|
|
uint32_t bootblock_offset,
|
|
|
|
uint32_t header_offset,
|
|
|
|
uint32_t entries_offset)
|
|
|
|
{
|
|
|
|
assert(image);
|
|
|
|
assert(image->buffer.data);
|
|
|
|
assert(bootblock);
|
|
|
|
|
|
|
|
int32_t *rel_offset;
|
|
|
|
uint32_t cbfs_len;
|
|
|
|
void *header_loc;
|
|
|
|
size_t size = image->buffer.size;
|
|
|
|
|
|
|
|
DEBUG("cbfs_image_create: bootblock=0x%x+0x%zx, "
|
|
|
|
"header=0x%x+0x%zx, entries_offset=0x%x\n",
|
|
|
|
bootblock_offset, bootblock->size, header_offset,
|
|
|
|
sizeof(image->header), entries_offset);
|
|
|
|
|
|
|
|
// Adjust legacy top-aligned address to ROM offset.
|
2013-01-29 02:45:12 +01:00
|
|
|
if (IS_TOP_ALIGNED_ADDRESS(entries_offset))
|
2015-03-06 00:38:03 +01:00
|
|
|
entries_offset = size + (int32_t)entries_offset;
|
2013-01-29 02:45:12 +01:00
|
|
|
if (IS_TOP_ALIGNED_ADDRESS(bootblock_offset))
|
2015-03-06 00:38:03 +01:00
|
|
|
bootblock_offset = size + (int32_t)bootblock_offset;
|
2013-01-29 02:45:12 +01:00
|
|
|
if (IS_TOP_ALIGNED_ADDRESS(header_offset))
|
2015-03-06 00:38:03 +01:00
|
|
|
header_offset = size + (int32_t)header_offset;
|
2013-01-29 02:45:12 +01:00
|
|
|
|
|
|
|
DEBUG("cbfs_create_image: (real offset) bootblock=0x%x, "
|
|
|
|
"header=0x%x, entries_offset=0x%x\n",
|
|
|
|
bootblock_offset, header_offset, entries_offset);
|
|
|
|
|
|
|
|
// Prepare bootblock
|
|
|
|
if (bootblock_offset + bootblock->size > size) {
|
|
|
|
ERROR("Bootblock (0x%x+0x%zx) exceed ROM size (0x%zx)\n",
|
|
|
|
bootblock_offset, bootblock->size, size);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-02-06 05:41:49 +01:00
|
|
|
if (entries_offset > bootblock_offset &&
|
|
|
|
entries_offset < bootblock->size) {
|
|
|
|
ERROR("Bootblock (0x%x+0x%zx) overlap CBFS data (0x%x)\n",
|
|
|
|
bootblock_offset, bootblock->size, entries_offset);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-01-29 02:45:12 +01:00
|
|
|
memcpy(image->buffer.data + bootblock_offset, bootblock->data,
|
|
|
|
bootblock->size);
|
|
|
|
|
|
|
|
// Prepare header
|
2015-05-06 05:35:26 +02:00
|
|
|
if (header_offset + sizeof(image->header) > size - sizeof(int32_t)) {
|
2013-01-29 02:45:12 +01:00
|
|
|
ERROR("Header (0x%x+0x%zx) exceed ROM size (0x%zx)\n",
|
2015-05-06 05:35:26 +02:00
|
|
|
header_offset, sizeof(image->header), size);
|
2013-01-29 02:45:12 +01:00
|
|
|
return -1;
|
|
|
|
}
|
2015-05-06 00:40:15 +02:00
|
|
|
image->header.magic = CBFS_HEADER_MAGIC;
|
|
|
|
image->header.version = CBFS_HEADER_VERSION;
|
|
|
|
image->header.romsize = size;
|
|
|
|
image->header.bootblocksize = bootblock->size;
|
|
|
|
image->header.align = align;
|
|
|
|
image->header.offset = entries_offset;
|
|
|
|
image->header.architecture = architecture;
|
2014-02-05 08:10:08 +01:00
|
|
|
|
|
|
|
header_loc = (image->buffer.data + header_offset);
|
2015-05-06 00:40:15 +02:00
|
|
|
cbfs_put_header(header_loc, &image->header);
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
image->has_header = true;
|
2013-01-29 02:45:12 +01:00
|
|
|
|
2014-11-10 22:14:24 +01:00
|
|
|
// The last 4 byte of the image contain the relative offset from the end
|
|
|
|
// of the image to the master header as a 32-bit signed integer. x86
|
|
|
|
// relies on this also being its (memory-mapped, top-aligned) absolute
|
|
|
|
// 32-bit address by virtue of how two's complement numbers work.
|
|
|
|
assert(size % sizeof(int32_t) == 0);
|
|
|
|
rel_offset = (int32_t *)(image->buffer.data + size - sizeof(int32_t));
|
|
|
|
*rel_offset = header_offset - size;
|
|
|
|
|
2013-01-29 02:45:12 +01:00
|
|
|
// Prepare entries
|
|
|
|
if (align_up(entries_offset, align) != entries_offset) {
|
|
|
|
ERROR("Offset (0x%x) must be aligned to 0x%x.\n",
|
|
|
|
entries_offset, align);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
// To calculate available length, find
|
2014-11-10 22:14:24 +01:00
|
|
|
// e = min(bootblock, header, rel_offset) where e > entries_offset.
|
|
|
|
cbfs_len = size - sizeof(int32_t);
|
2013-01-29 02:45:12 +01:00
|
|
|
if (bootblock_offset > entries_offset && bootblock_offset < cbfs_len)
|
|
|
|
cbfs_len = bootblock_offset;
|
|
|
|
if (header_offset > entries_offset && header_offset < cbfs_len)
|
|
|
|
cbfs_len = header_offset;
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
|
|
|
|
if (cbfs_image_create(image, cbfs_len - entries_offset))
|
|
|
|
return -1;
|
2013-01-29 02:45:12 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
cbfstool: Restructure around support for reading/writing portions of files
The buffer API that cbfstool uses to read and write files only directly supports
one-shot operations on whole files. This adds an intermediate partitioned_file
module that sits on top of the buffer system and has an awareness of FMAP
entries. It provides an easy way to get a buffer for an individual region of a
larger image file based on FMAP section name, as well as incrementally write
those smaller buffers back to the backing file at the appropriate offset. The
module has two distinct modes of operation:
- For new images whose layout is described exclusively by an FMAP section, all
the aforementioned functionality will be available.
- For images in the current format, where the CBFS master header serves as the
root of knowledge of the image's size and layout, the module falls back to a
legacy operation mode, where it only allows manipulation of the entire image
as one unit, but exposes this support through the same interface by mapping
the region named SECTION_NAME_PRIMARY_CBFS ("COREBOOT") to the whole file.
The tool is presently only ported onto the new module running in legacy mode:
higher-level support for true "partitioned" images will be forthcoming. However,
as part of this change, the crusty cbfs_image_from_file() and
cbfs_image_write_file() abstractions are removed and replaced with a single
cbfs_image function, cbfs_image_from_buffer(), as well as centralized image
reading/writing directly in cbfstool's main() function. This reduces the
boilerplate required to implement each new action, makes the create action much
more similar to the others, and will make implementing additional actions and
adding in support for the new format much easier.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom images with and without this patch
and diff their hexdumps. Ensure that no differences occur at different locations
from the diffs between subsequent builds of an identical source tree. Then flash
a full new build onto nyan_big and watch it boot normally.
BRANCH=None
Change-Id: I25578c7b223bc8434c3074cb0dd8894534f8c500
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 7e1c96a48e7a27fc6b90289d35e6e169d5e7ad20
Original-Change-Id: Ia4a1a4c48df42b9ec2d6b9471b3a10eb7b24bb39
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265581
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10134
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
2015-03-25 21:40:08 +01:00
|
|
|
int cbfs_image_from_buffer(struct cbfs_image *out, struct buffer *in,
|
|
|
|
uint32_t offset)
|
2013-03-26 20:51:36 +01:00
|
|
|
{
|
cbfstool: Restructure around support for reading/writing portions of files
The buffer API that cbfstool uses to read and write files only directly supports
one-shot operations on whole files. This adds an intermediate partitioned_file
module that sits on top of the buffer system and has an awareness of FMAP
entries. It provides an easy way to get a buffer for an individual region of a
larger image file based on FMAP section name, as well as incrementally write
those smaller buffers back to the backing file at the appropriate offset. The
module has two distinct modes of operation:
- For new images whose layout is described exclusively by an FMAP section, all
the aforementioned functionality will be available.
- For images in the current format, where the CBFS master header serves as the
root of knowledge of the image's size and layout, the module falls back to a
legacy operation mode, where it only allows manipulation of the entire image
as one unit, but exposes this support through the same interface by mapping
the region named SECTION_NAME_PRIMARY_CBFS ("COREBOOT") to the whole file.
The tool is presently only ported onto the new module running in legacy mode:
higher-level support for true "partitioned" images will be forthcoming. However,
as part of this change, the crusty cbfs_image_from_file() and
cbfs_image_write_file() abstractions are removed and replaced with a single
cbfs_image function, cbfs_image_from_buffer(), as well as centralized image
reading/writing directly in cbfstool's main() function. This reduces the
boilerplate required to implement each new action, makes the create action much
more similar to the others, and will make implementing additional actions and
adding in support for the new format much easier.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom images with and without this patch
and diff their hexdumps. Ensure that no differences occur at different locations
from the diffs between subsequent builds of an identical source tree. Then flash
a full new build onto nyan_big and watch it boot normally.
BRANCH=None
Change-Id: I25578c7b223bc8434c3074cb0dd8894534f8c500
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 7e1c96a48e7a27fc6b90289d35e6e169d5e7ad20
Original-Change-Id: Ia4a1a4c48df42b9ec2d6b9471b3a10eb7b24bb39
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265581
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10134
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
2015-03-25 21:40:08 +01:00
|
|
|
assert(out);
|
|
|
|
assert(in);
|
|
|
|
assert(in->data);
|
2014-02-05 08:10:08 +01:00
|
|
|
|
cbfstool: Restructure around support for reading/writing portions of files
The buffer API that cbfstool uses to read and write files only directly supports
one-shot operations on whole files. This adds an intermediate partitioned_file
module that sits on top of the buffer system and has an awareness of FMAP
entries. It provides an easy way to get a buffer for an individual region of a
larger image file based on FMAP section name, as well as incrementally write
those smaller buffers back to the backing file at the appropriate offset. The
module has two distinct modes of operation:
- For new images whose layout is described exclusively by an FMAP section, all
the aforementioned functionality will be available.
- For images in the current format, where the CBFS master header serves as the
root of knowledge of the image's size and layout, the module falls back to a
legacy operation mode, where it only allows manipulation of the entire image
as one unit, but exposes this support through the same interface by mapping
the region named SECTION_NAME_PRIMARY_CBFS ("COREBOOT") to the whole file.
The tool is presently only ported onto the new module running in legacy mode:
higher-level support for true "partitioned" images will be forthcoming. However,
as part of this change, the crusty cbfs_image_from_file() and
cbfs_image_write_file() abstractions are removed and replaced with a single
cbfs_image function, cbfs_image_from_buffer(), as well as centralized image
reading/writing directly in cbfstool's main() function. This reduces the
boilerplate required to implement each new action, makes the create action much
more similar to the others, and will make implementing additional actions and
adding in support for the new format much easier.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom images with and without this patch
and diff their hexdumps. Ensure that no differences occur at different locations
from the diffs between subsequent builds of an identical source tree. Then flash
a full new build onto nyan_big and watch it boot normally.
BRANCH=None
Change-Id: I25578c7b223bc8434c3074cb0dd8894534f8c500
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 7e1c96a48e7a27fc6b90289d35e6e169d5e7ad20
Original-Change-Id: Ia4a1a4c48df42b9ec2d6b9471b3a10eb7b24bb39
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265581
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10134
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
2015-03-25 21:40:08 +01:00
|
|
|
buffer_clone(&out->buffer, in);
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
out->has_header = false;
|
|
|
|
|
2015-09-11 18:34:39 +02:00
|
|
|
if (cbfs_is_valid_cbfs(out)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
cbfstool: Restructure around support for reading/writing portions of files
The buffer API that cbfstool uses to read and write files only directly supports
one-shot operations on whole files. This adds an intermediate partitioned_file
module that sits on top of the buffer system and has an awareness of FMAP
entries. It provides an easy way to get a buffer for an individual region of a
larger image file based on FMAP section name, as well as incrementally write
those smaller buffers back to the backing file at the appropriate offset. The
module has two distinct modes of operation:
- For new images whose layout is described exclusively by an FMAP section, all
the aforementioned functionality will be available.
- For images in the current format, where the CBFS master header serves as the
root of knowledge of the image's size and layout, the module falls back to a
legacy operation mode, where it only allows manipulation of the entire image
as one unit, but exposes this support through the same interface by mapping
the region named SECTION_NAME_PRIMARY_CBFS ("COREBOOT") to the whole file.
The tool is presently only ported onto the new module running in legacy mode:
higher-level support for true "partitioned" images will be forthcoming. However,
as part of this change, the crusty cbfs_image_from_file() and
cbfs_image_write_file() abstractions are removed and replaced with a single
cbfs_image function, cbfs_image_from_buffer(), as well as centralized image
reading/writing directly in cbfstool's main() function. This reduces the
boilerplate required to implement each new action, makes the create action much
more similar to the others, and will make implementing additional actions and
adding in support for the new format much easier.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom images with and without this patch
and diff their hexdumps. Ensure that no differences occur at different locations
from the diffs between subsequent builds of an identical source tree. Then flash
a full new build onto nyan_big and watch it boot normally.
BRANCH=None
Change-Id: I25578c7b223bc8434c3074cb0dd8894534f8c500
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 7e1c96a48e7a27fc6b90289d35e6e169d5e7ad20
Original-Change-Id: Ia4a1a4c48df42b9ec2d6b9471b3a10eb7b24bb39
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265581
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10134
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
2015-03-25 21:40:08 +01:00
|
|
|
void *header_loc = cbfs_find_header(in->data, in->size, offset);
|
|
|
|
if (header_loc) {
|
|
|
|
cbfs_get_header(&out->header, header_loc);
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
out->has_header = true;
|
cbfstool: Restructure around support for reading/writing portions of files
The buffer API that cbfstool uses to read and write files only directly supports
one-shot operations on whole files. This adds an intermediate partitioned_file
module that sits on top of the buffer system and has an awareness of FMAP
entries. It provides an easy way to get a buffer for an individual region of a
larger image file based on FMAP section name, as well as incrementally write
those smaller buffers back to the backing file at the appropriate offset. The
module has two distinct modes of operation:
- For new images whose layout is described exclusively by an FMAP section, all
the aforementioned functionality will be available.
- For images in the current format, where the CBFS master header serves as the
root of knowledge of the image's size and layout, the module falls back to a
legacy operation mode, where it only allows manipulation of the entire image
as one unit, but exposes this support through the same interface by mapping
the region named SECTION_NAME_PRIMARY_CBFS ("COREBOOT") to the whole file.
The tool is presently only ported onto the new module running in legacy mode:
higher-level support for true "partitioned" images will be forthcoming. However,
as part of this change, the crusty cbfs_image_from_file() and
cbfs_image_write_file() abstractions are removed and replaced with a single
cbfs_image function, cbfs_image_from_buffer(), as well as centralized image
reading/writing directly in cbfstool's main() function. This reduces the
boilerplate required to implement each new action, makes the create action much
more similar to the others, and will make implementing additional actions and
adding in support for the new format much easier.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom images with and without this patch
and diff their hexdumps. Ensure that no differences occur at different locations
from the diffs between subsequent builds of an identical source tree. Then flash
a full new build onto nyan_big and watch it boot normally.
BRANCH=None
Change-Id: I25578c7b223bc8434c3074cb0dd8894534f8c500
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 7e1c96a48e7a27fc6b90289d35e6e169d5e7ad20
Original-Change-Id: Ia4a1a4c48df42b9ec2d6b9471b3a10eb7b24bb39
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265581
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10134
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
2015-03-25 21:40:08 +01:00
|
|
|
cbfs_fix_legacy_size(out, header_loc);
|
2015-09-11 18:34:39 +02:00
|
|
|
return 0;
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
} else if (offset != ~0u) {
|
|
|
|
ERROR("The -H switch is only valid on legacy images having CBFS master headers.\n");
|
|
|
|
return 1;
|
2013-01-28 18:56:17 +01:00
|
|
|
}
|
2015-09-11 18:34:39 +02:00
|
|
|
ERROR("Selected image region is not a valid CBFS.\n");
|
|
|
|
return 1;
|
2013-01-28 18:56:17 +01:00
|
|
|
}
|
|
|
|
|
2015-11-20 19:22:50 +01:00
|
|
|
int cbfs_copy_instance(struct cbfs_image *image, struct buffer *dst)
|
cbfstool: add a command to duplicate a cbfs instance
The new command allows to create a file where the original CBFS image
is duplicated at a different offset.
The required options of the new command are -D, the offset where the
copy CBFS header is placed, and -s, the size of the new CBFS copy.
When a CBFS is copied, the bootblock area of the source CBFS is
ignored, as well as empty and deleted files in the source CBFS. The
size of the destination CBFS is calculated as the rombase size of the
source CBFS less the bootblock size.
The copy instance can be created in the image only above the original,
which rules out the use of this new command for x86 images. If
necessary, this limitation could be addressed later.
As with other cbfstool commands, unless explicitly specified the
lowest CBFS instance in the image is considered the source. If
necessary, the user can specify the source CBFS using the -H option.
BRANCH=storm
BUG=chrome-os-partner:34161, chromium:445938
TEST=run multiple cbfstool commands on a storm image:
$ cd /tmp
$ cp /build/storm/firmware/image.serial.bin storm.bin
$ cbfstool storm.bin print
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
$ cbfstool storm.bin copy -D 0x420000
E: You need to specify -s/--size.
$ cbfstool storm.bin copy -D 0x420000 -s 0x70000
$ cbfstool storm.bin print
W: Multiple (2) CBFS headers found, using the first one.
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
cbfstool storm.bin print -H 0x420000
storm.bin: 8192 kB, bootblocksize 0, romsize 4784128, offset 0x420040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x420040 raw 416
ddr.mbn 0x420240 raw 25836
rpm.mbn 0x426780 raw 78576
tz.mbn 0x439ac0 raw 85360
fallback/verstage 0x44e880 stage 41620
fallback/romstage 0x458b80 stage 19556
fallback/ramstage 0x45d840 stage 25579
config 0x463c80 raw 2878
fallback/payload 0x464800 payload 64811
u-boot.dtb 0x474580 (unknown) 2993
(empty) 0x475180 null 110168
$ cbfstool storm.bin remove -n config -H 0x420000
$ cbfstool storm.bin copy -H 0x420000 -D 0x620000 -s 0x70000
$ cbfstool storm.bin print -H 0x620000
storm.bin: 8192 kB, bootblocksize 0, romsize 6881280, offset 0x620040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x620040 raw 416
ddr.mbn 0x620240 raw 25836
rpm.mbn 0x626780 raw 78576
tz.mbn 0x639ac0 raw 85360
fallback/verstage 0x64e880 stage 41620
fallback/romstage 0x658b80 stage 19556
fallback/ramstage 0x65d840 stage 25579
fallback/payload 0x663c80 payload 64811
u-boot.dtb 0x673a00 (unknown) 2993
(empty) 0x674600 null 113112
$ cbfstool /build/storm/firmware/image.serial.bin extract -n fallback/payload -f payload1
[..]
$ cbfstool storm.bin extract -H 0x620000 -n fallback/payload -f payload2
[..]
$ diff payload1 payload2
Change-Id: Ieb9205848aec361bb870de0d284dff06c597564f
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: b8d3c1b09a47ca24d2d2effc6de0e89d1b0a8903
Original-Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Change-Id: I227e607ccf7a9a8e2a1f3c6bbc506b8d29a35b1b
Original-Reviewed-on: https://chromium-review.googlesource.com/237561
Reviewed-on: http://review.coreboot.org/9742
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2014-12-24 04:26:54 +01:00
|
|
|
{
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
assert(image);
|
|
|
|
|
cbfstool: add a command to duplicate a cbfs instance
The new command allows to create a file where the original CBFS image
is duplicated at a different offset.
The required options of the new command are -D, the offset where the
copy CBFS header is placed, and -s, the size of the new CBFS copy.
When a CBFS is copied, the bootblock area of the source CBFS is
ignored, as well as empty and deleted files in the source CBFS. The
size of the destination CBFS is calculated as the rombase size of the
source CBFS less the bootblock size.
The copy instance can be created in the image only above the original,
which rules out the use of this new command for x86 images. If
necessary, this limitation could be addressed later.
As with other cbfstool commands, unless explicitly specified the
lowest CBFS instance in the image is considered the source. If
necessary, the user can specify the source CBFS using the -H option.
BRANCH=storm
BUG=chrome-os-partner:34161, chromium:445938
TEST=run multiple cbfstool commands on a storm image:
$ cd /tmp
$ cp /build/storm/firmware/image.serial.bin storm.bin
$ cbfstool storm.bin print
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
$ cbfstool storm.bin copy -D 0x420000
E: You need to specify -s/--size.
$ cbfstool storm.bin copy -D 0x420000 -s 0x70000
$ cbfstool storm.bin print
W: Multiple (2) CBFS headers found, using the first one.
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
cbfstool storm.bin print -H 0x420000
storm.bin: 8192 kB, bootblocksize 0, romsize 4784128, offset 0x420040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x420040 raw 416
ddr.mbn 0x420240 raw 25836
rpm.mbn 0x426780 raw 78576
tz.mbn 0x439ac0 raw 85360
fallback/verstage 0x44e880 stage 41620
fallback/romstage 0x458b80 stage 19556
fallback/ramstage 0x45d840 stage 25579
config 0x463c80 raw 2878
fallback/payload 0x464800 payload 64811
u-boot.dtb 0x474580 (unknown) 2993
(empty) 0x475180 null 110168
$ cbfstool storm.bin remove -n config -H 0x420000
$ cbfstool storm.bin copy -H 0x420000 -D 0x620000 -s 0x70000
$ cbfstool storm.bin print -H 0x620000
storm.bin: 8192 kB, bootblocksize 0, romsize 6881280, offset 0x620040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x620040 raw 416
ddr.mbn 0x620240 raw 25836
rpm.mbn 0x626780 raw 78576
tz.mbn 0x639ac0 raw 85360
fallback/verstage 0x64e880 stage 41620
fallback/romstage 0x658b80 stage 19556
fallback/ramstage 0x65d840 stage 25579
fallback/payload 0x663c80 payload 64811
u-boot.dtb 0x673a00 (unknown) 2993
(empty) 0x674600 null 113112
$ cbfstool /build/storm/firmware/image.serial.bin extract -n fallback/payload -f payload1
[..]
$ cbfstool storm.bin extract -H 0x620000 -n fallback/payload -f payload2
[..]
$ diff payload1 payload2
Change-Id: Ieb9205848aec361bb870de0d284dff06c597564f
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: b8d3c1b09a47ca24d2d2effc6de0e89d1b0a8903
Original-Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Change-Id: I227e607ccf7a9a8e2a1f3c6bbc506b8d29a35b1b
Original-Reviewed-on: https://chromium-review.googlesource.com/237561
Reviewed-on: http://review.coreboot.org/9742
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2014-12-24 04:26:54 +01:00
|
|
|
struct cbfs_file *src_entry, *dst_entry;
|
2015-11-20 21:48:18 +01:00
|
|
|
size_t align;
|
cbfstool: add a command to duplicate a cbfs instance
The new command allows to create a file where the original CBFS image
is duplicated at a different offset.
The required options of the new command are -D, the offset where the
copy CBFS header is placed, and -s, the size of the new CBFS copy.
When a CBFS is copied, the bootblock area of the source CBFS is
ignored, as well as empty and deleted files in the source CBFS. The
size of the destination CBFS is calculated as the rombase size of the
source CBFS less the bootblock size.
The copy instance can be created in the image only above the original,
which rules out the use of this new command for x86 images. If
necessary, this limitation could be addressed later.
As with other cbfstool commands, unless explicitly specified the
lowest CBFS instance in the image is considered the source. If
necessary, the user can specify the source CBFS using the -H option.
BRANCH=storm
BUG=chrome-os-partner:34161, chromium:445938
TEST=run multiple cbfstool commands on a storm image:
$ cd /tmp
$ cp /build/storm/firmware/image.serial.bin storm.bin
$ cbfstool storm.bin print
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
$ cbfstool storm.bin copy -D 0x420000
E: You need to specify -s/--size.
$ cbfstool storm.bin copy -D 0x420000 -s 0x70000
$ cbfstool storm.bin print
W: Multiple (2) CBFS headers found, using the first one.
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
cbfstool storm.bin print -H 0x420000
storm.bin: 8192 kB, bootblocksize 0, romsize 4784128, offset 0x420040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x420040 raw 416
ddr.mbn 0x420240 raw 25836
rpm.mbn 0x426780 raw 78576
tz.mbn 0x439ac0 raw 85360
fallback/verstage 0x44e880 stage 41620
fallback/romstage 0x458b80 stage 19556
fallback/ramstage 0x45d840 stage 25579
config 0x463c80 raw 2878
fallback/payload 0x464800 payload 64811
u-boot.dtb 0x474580 (unknown) 2993
(empty) 0x475180 null 110168
$ cbfstool storm.bin remove -n config -H 0x420000
$ cbfstool storm.bin copy -H 0x420000 -D 0x620000 -s 0x70000
$ cbfstool storm.bin print -H 0x620000
storm.bin: 8192 kB, bootblocksize 0, romsize 6881280, offset 0x620040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x620040 raw 416
ddr.mbn 0x620240 raw 25836
rpm.mbn 0x626780 raw 78576
tz.mbn 0x639ac0 raw 85360
fallback/verstage 0x64e880 stage 41620
fallback/romstage 0x658b80 stage 19556
fallback/ramstage 0x65d840 stage 25579
fallback/payload 0x663c80 payload 64811
u-boot.dtb 0x673a00 (unknown) 2993
(empty) 0x674600 null 113112
$ cbfstool /build/storm/firmware/image.serial.bin extract -n fallback/payload -f payload1
[..]
$ cbfstool storm.bin extract -H 0x620000 -n fallback/payload -f payload2
[..]
$ diff payload1 payload2
Change-Id: Ieb9205848aec361bb870de0d284dff06c597564f
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: b8d3c1b09a47ca24d2d2effc6de0e89d1b0a8903
Original-Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Change-Id: I227e607ccf7a9a8e2a1f3c6bbc506b8d29a35b1b
Original-Reviewed-on: https://chromium-review.googlesource.com/237561
Reviewed-on: http://review.coreboot.org/9742
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2014-12-24 04:26:54 +01:00
|
|
|
ssize_t last_entry_size;
|
|
|
|
|
2015-11-20 19:22:50 +01:00
|
|
|
size_t copy_end = buffer_size(dst);
|
cbfstool: add a command to duplicate a cbfs instance
The new command allows to create a file where the original CBFS image
is duplicated at a different offset.
The required options of the new command are -D, the offset where the
copy CBFS header is placed, and -s, the size of the new CBFS copy.
When a CBFS is copied, the bootblock area of the source CBFS is
ignored, as well as empty and deleted files in the source CBFS. The
size of the destination CBFS is calculated as the rombase size of the
source CBFS less the bootblock size.
The copy instance can be created in the image only above the original,
which rules out the use of this new command for x86 images. If
necessary, this limitation could be addressed later.
As with other cbfstool commands, unless explicitly specified the
lowest CBFS instance in the image is considered the source. If
necessary, the user can specify the source CBFS using the -H option.
BRANCH=storm
BUG=chrome-os-partner:34161, chromium:445938
TEST=run multiple cbfstool commands on a storm image:
$ cd /tmp
$ cp /build/storm/firmware/image.serial.bin storm.bin
$ cbfstool storm.bin print
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
$ cbfstool storm.bin copy -D 0x420000
E: You need to specify -s/--size.
$ cbfstool storm.bin copy -D 0x420000 -s 0x70000
$ cbfstool storm.bin print
W: Multiple (2) CBFS headers found, using the first one.
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
cbfstool storm.bin print -H 0x420000
storm.bin: 8192 kB, bootblocksize 0, romsize 4784128, offset 0x420040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x420040 raw 416
ddr.mbn 0x420240 raw 25836
rpm.mbn 0x426780 raw 78576
tz.mbn 0x439ac0 raw 85360
fallback/verstage 0x44e880 stage 41620
fallback/romstage 0x458b80 stage 19556
fallback/ramstage 0x45d840 stage 25579
config 0x463c80 raw 2878
fallback/payload 0x464800 payload 64811
u-boot.dtb 0x474580 (unknown) 2993
(empty) 0x475180 null 110168
$ cbfstool storm.bin remove -n config -H 0x420000
$ cbfstool storm.bin copy -H 0x420000 -D 0x620000 -s 0x70000
$ cbfstool storm.bin print -H 0x620000
storm.bin: 8192 kB, bootblocksize 0, romsize 6881280, offset 0x620040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x620040 raw 416
ddr.mbn 0x620240 raw 25836
rpm.mbn 0x626780 raw 78576
tz.mbn 0x639ac0 raw 85360
fallback/verstage 0x64e880 stage 41620
fallback/romstage 0x658b80 stage 19556
fallback/ramstage 0x65d840 stage 25579
fallback/payload 0x663c80 payload 64811
u-boot.dtb 0x673a00 (unknown) 2993
(empty) 0x674600 null 113112
$ cbfstool /build/storm/firmware/image.serial.bin extract -n fallback/payload -f payload1
[..]
$ cbfstool storm.bin extract -H 0x620000 -n fallback/payload -f payload2
[..]
$ diff payload1 payload2
Change-Id: Ieb9205848aec361bb870de0d284dff06c597564f
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: b8d3c1b09a47ca24d2d2effc6de0e89d1b0a8903
Original-Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Change-Id: I227e607ccf7a9a8e2a1f3c6bbc506b8d29a35b1b
Original-Reviewed-on: https://chromium-review.googlesource.com/237561
Reviewed-on: http://review.coreboot.org/9742
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2014-12-24 04:26:54 +01:00
|
|
|
|
2015-11-20 21:48:18 +01:00
|
|
|
align = CBFS_ENTRY_ALIGNMENT;
|
cbfstool: add a command to duplicate a cbfs instance
The new command allows to create a file where the original CBFS image
is duplicated at a different offset.
The required options of the new command are -D, the offset where the
copy CBFS header is placed, and -s, the size of the new CBFS copy.
When a CBFS is copied, the bootblock area of the source CBFS is
ignored, as well as empty and deleted files in the source CBFS. The
size of the destination CBFS is calculated as the rombase size of the
source CBFS less the bootblock size.
The copy instance can be created in the image only above the original,
which rules out the use of this new command for x86 images. If
necessary, this limitation could be addressed later.
As with other cbfstool commands, unless explicitly specified the
lowest CBFS instance in the image is considered the source. If
necessary, the user can specify the source CBFS using the -H option.
BRANCH=storm
BUG=chrome-os-partner:34161, chromium:445938
TEST=run multiple cbfstool commands on a storm image:
$ cd /tmp
$ cp /build/storm/firmware/image.serial.bin storm.bin
$ cbfstool storm.bin print
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
$ cbfstool storm.bin copy -D 0x420000
E: You need to specify -s/--size.
$ cbfstool storm.bin copy -D 0x420000 -s 0x70000
$ cbfstool storm.bin print
W: Multiple (2) CBFS headers found, using the first one.
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
cbfstool storm.bin print -H 0x420000
storm.bin: 8192 kB, bootblocksize 0, romsize 4784128, offset 0x420040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x420040 raw 416
ddr.mbn 0x420240 raw 25836
rpm.mbn 0x426780 raw 78576
tz.mbn 0x439ac0 raw 85360
fallback/verstage 0x44e880 stage 41620
fallback/romstage 0x458b80 stage 19556
fallback/ramstage 0x45d840 stage 25579
config 0x463c80 raw 2878
fallback/payload 0x464800 payload 64811
u-boot.dtb 0x474580 (unknown) 2993
(empty) 0x475180 null 110168
$ cbfstool storm.bin remove -n config -H 0x420000
$ cbfstool storm.bin copy -H 0x420000 -D 0x620000 -s 0x70000
$ cbfstool storm.bin print -H 0x620000
storm.bin: 8192 kB, bootblocksize 0, romsize 6881280, offset 0x620040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x620040 raw 416
ddr.mbn 0x620240 raw 25836
rpm.mbn 0x626780 raw 78576
tz.mbn 0x639ac0 raw 85360
fallback/verstage 0x64e880 stage 41620
fallback/romstage 0x658b80 stage 19556
fallback/ramstage 0x65d840 stage 25579
fallback/payload 0x663c80 payload 64811
u-boot.dtb 0x673a00 (unknown) 2993
(empty) 0x674600 null 113112
$ cbfstool /build/storm/firmware/image.serial.bin extract -n fallback/payload -f payload1
[..]
$ cbfstool storm.bin extract -H 0x620000 -n fallback/payload -f payload2
[..]
$ diff payload1 payload2
Change-Id: Ieb9205848aec361bb870de0d284dff06c597564f
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: b8d3c1b09a47ca24d2d2effc6de0e89d1b0a8903
Original-Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Change-Id: I227e607ccf7a9a8e2a1f3c6bbc506b8d29a35b1b
Original-Reviewed-on: https://chromium-review.googlesource.com/237561
Reviewed-on: http://review.coreboot.org/9742
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2014-12-24 04:26:54 +01:00
|
|
|
|
2015-11-20 21:48:18 +01:00
|
|
|
dst_entry = (struct cbfs_file *)buffer_get(dst);
|
cbfstool: add a command to duplicate a cbfs instance
The new command allows to create a file where the original CBFS image
is duplicated at a different offset.
The required options of the new command are -D, the offset where the
copy CBFS header is placed, and -s, the size of the new CBFS copy.
When a CBFS is copied, the bootblock area of the source CBFS is
ignored, as well as empty and deleted files in the source CBFS. The
size of the destination CBFS is calculated as the rombase size of the
source CBFS less the bootblock size.
The copy instance can be created in the image only above the original,
which rules out the use of this new command for x86 images. If
necessary, this limitation could be addressed later.
As with other cbfstool commands, unless explicitly specified the
lowest CBFS instance in the image is considered the source. If
necessary, the user can specify the source CBFS using the -H option.
BRANCH=storm
BUG=chrome-os-partner:34161, chromium:445938
TEST=run multiple cbfstool commands on a storm image:
$ cd /tmp
$ cp /build/storm/firmware/image.serial.bin storm.bin
$ cbfstool storm.bin print
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
$ cbfstool storm.bin copy -D 0x420000
E: You need to specify -s/--size.
$ cbfstool storm.bin copy -D 0x420000 -s 0x70000
$ cbfstool storm.bin print
W: Multiple (2) CBFS headers found, using the first one.
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
cbfstool storm.bin print -H 0x420000
storm.bin: 8192 kB, bootblocksize 0, romsize 4784128, offset 0x420040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x420040 raw 416
ddr.mbn 0x420240 raw 25836
rpm.mbn 0x426780 raw 78576
tz.mbn 0x439ac0 raw 85360
fallback/verstage 0x44e880 stage 41620
fallback/romstage 0x458b80 stage 19556
fallback/ramstage 0x45d840 stage 25579
config 0x463c80 raw 2878
fallback/payload 0x464800 payload 64811
u-boot.dtb 0x474580 (unknown) 2993
(empty) 0x475180 null 110168
$ cbfstool storm.bin remove -n config -H 0x420000
$ cbfstool storm.bin copy -H 0x420000 -D 0x620000 -s 0x70000
$ cbfstool storm.bin print -H 0x620000
storm.bin: 8192 kB, bootblocksize 0, romsize 6881280, offset 0x620040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x620040 raw 416
ddr.mbn 0x620240 raw 25836
rpm.mbn 0x626780 raw 78576
tz.mbn 0x639ac0 raw 85360
fallback/verstage 0x64e880 stage 41620
fallback/romstage 0x658b80 stage 19556
fallback/ramstage 0x65d840 stage 25579
fallback/payload 0x663c80 payload 64811
u-boot.dtb 0x673a00 (unknown) 2993
(empty) 0x674600 null 113112
$ cbfstool /build/storm/firmware/image.serial.bin extract -n fallback/payload -f payload1
[..]
$ cbfstool storm.bin extract -H 0x620000 -n fallback/payload -f payload2
[..]
$ diff payload1 payload2
Change-Id: Ieb9205848aec361bb870de0d284dff06c597564f
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: b8d3c1b09a47ca24d2d2effc6de0e89d1b0a8903
Original-Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Change-Id: I227e607ccf7a9a8e2a1f3c6bbc506b8d29a35b1b
Original-Reviewed-on: https://chromium-review.googlesource.com/237561
Reviewed-on: http://review.coreboot.org/9742
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2014-12-24 04:26:54 +01:00
|
|
|
|
|
|
|
/* Copy non-empty files */
|
|
|
|
for (src_entry = cbfs_find_first_entry(image);
|
|
|
|
src_entry && cbfs_is_valid_entry(image, src_entry);
|
|
|
|
src_entry = cbfs_find_next_entry(image, src_entry)) {
|
|
|
|
size_t entry_size;
|
|
|
|
|
|
|
|
if ((src_entry->type == htonl(CBFS_COMPONENT_NULL)) ||
|
2015-11-20 21:48:18 +01:00
|
|
|
(src_entry->type == htonl(CBFS_COMPONENT_CBFSHEADER)) ||
|
cbfstool: add a command to duplicate a cbfs instance
The new command allows to create a file where the original CBFS image
is duplicated at a different offset.
The required options of the new command are -D, the offset where the
copy CBFS header is placed, and -s, the size of the new CBFS copy.
When a CBFS is copied, the bootblock area of the source CBFS is
ignored, as well as empty and deleted files in the source CBFS. The
size of the destination CBFS is calculated as the rombase size of the
source CBFS less the bootblock size.
The copy instance can be created in the image only above the original,
which rules out the use of this new command for x86 images. If
necessary, this limitation could be addressed later.
As with other cbfstool commands, unless explicitly specified the
lowest CBFS instance in the image is considered the source. If
necessary, the user can specify the source CBFS using the -H option.
BRANCH=storm
BUG=chrome-os-partner:34161, chromium:445938
TEST=run multiple cbfstool commands on a storm image:
$ cd /tmp
$ cp /build/storm/firmware/image.serial.bin storm.bin
$ cbfstool storm.bin print
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
$ cbfstool storm.bin copy -D 0x420000
E: You need to specify -s/--size.
$ cbfstool storm.bin copy -D 0x420000 -s 0x70000
$ cbfstool storm.bin print
W: Multiple (2) CBFS headers found, using the first one.
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
cbfstool storm.bin print -H 0x420000
storm.bin: 8192 kB, bootblocksize 0, romsize 4784128, offset 0x420040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x420040 raw 416
ddr.mbn 0x420240 raw 25836
rpm.mbn 0x426780 raw 78576
tz.mbn 0x439ac0 raw 85360
fallback/verstage 0x44e880 stage 41620
fallback/romstage 0x458b80 stage 19556
fallback/ramstage 0x45d840 stage 25579
config 0x463c80 raw 2878
fallback/payload 0x464800 payload 64811
u-boot.dtb 0x474580 (unknown) 2993
(empty) 0x475180 null 110168
$ cbfstool storm.bin remove -n config -H 0x420000
$ cbfstool storm.bin copy -H 0x420000 -D 0x620000 -s 0x70000
$ cbfstool storm.bin print -H 0x620000
storm.bin: 8192 kB, bootblocksize 0, romsize 6881280, offset 0x620040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x620040 raw 416
ddr.mbn 0x620240 raw 25836
rpm.mbn 0x626780 raw 78576
tz.mbn 0x639ac0 raw 85360
fallback/verstage 0x64e880 stage 41620
fallback/romstage 0x658b80 stage 19556
fallback/ramstage 0x65d840 stage 25579
fallback/payload 0x663c80 payload 64811
u-boot.dtb 0x673a00 (unknown) 2993
(empty) 0x674600 null 113112
$ cbfstool /build/storm/firmware/image.serial.bin extract -n fallback/payload -f payload1
[..]
$ cbfstool storm.bin extract -H 0x620000 -n fallback/payload -f payload2
[..]
$ diff payload1 payload2
Change-Id: Ieb9205848aec361bb870de0d284dff06c597564f
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: b8d3c1b09a47ca24d2d2effc6de0e89d1b0a8903
Original-Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Change-Id: I227e607ccf7a9a8e2a1f3c6bbc506b8d29a35b1b
Original-Reviewed-on: https://chromium-review.googlesource.com/237561
Reviewed-on: http://review.coreboot.org/9742
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2014-12-24 04:26:54 +01:00
|
|
|
(src_entry->type == htonl(CBFS_COMPONENT_DELETED)))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
entry_size = htonl(src_entry->len) + htonl(src_entry->offset);
|
|
|
|
memcpy(dst_entry, src_entry, entry_size);
|
|
|
|
dst_entry = (struct cbfs_file *)(
|
|
|
|
(uintptr_t)dst_entry + align_up(entry_size, align));
|
|
|
|
|
2018-11-02 19:14:38 +01:00
|
|
|
if ((size_t)((uint8_t *)dst_entry - (uint8_t *)buffer_get(dst))
|
|
|
|
>= copy_end) {
|
cbfstool: add a command to duplicate a cbfs instance
The new command allows to create a file where the original CBFS image
is duplicated at a different offset.
The required options of the new command are -D, the offset where the
copy CBFS header is placed, and -s, the size of the new CBFS copy.
When a CBFS is copied, the bootblock area of the source CBFS is
ignored, as well as empty and deleted files in the source CBFS. The
size of the destination CBFS is calculated as the rombase size of the
source CBFS less the bootblock size.
The copy instance can be created in the image only above the original,
which rules out the use of this new command for x86 images. If
necessary, this limitation could be addressed later.
As with other cbfstool commands, unless explicitly specified the
lowest CBFS instance in the image is considered the source. If
necessary, the user can specify the source CBFS using the -H option.
BRANCH=storm
BUG=chrome-os-partner:34161, chromium:445938
TEST=run multiple cbfstool commands on a storm image:
$ cd /tmp
$ cp /build/storm/firmware/image.serial.bin storm.bin
$ cbfstool storm.bin print
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
$ cbfstool storm.bin copy -D 0x420000
E: You need to specify -s/--size.
$ cbfstool storm.bin copy -D 0x420000 -s 0x70000
$ cbfstool storm.bin print
W: Multiple (2) CBFS headers found, using the first one.
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
cbfstool storm.bin print -H 0x420000
storm.bin: 8192 kB, bootblocksize 0, romsize 4784128, offset 0x420040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x420040 raw 416
ddr.mbn 0x420240 raw 25836
rpm.mbn 0x426780 raw 78576
tz.mbn 0x439ac0 raw 85360
fallback/verstage 0x44e880 stage 41620
fallback/romstage 0x458b80 stage 19556
fallback/ramstage 0x45d840 stage 25579
config 0x463c80 raw 2878
fallback/payload 0x464800 payload 64811
u-boot.dtb 0x474580 (unknown) 2993
(empty) 0x475180 null 110168
$ cbfstool storm.bin remove -n config -H 0x420000
$ cbfstool storm.bin copy -H 0x420000 -D 0x620000 -s 0x70000
$ cbfstool storm.bin print -H 0x620000
storm.bin: 8192 kB, bootblocksize 0, romsize 6881280, offset 0x620040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x620040 raw 416
ddr.mbn 0x620240 raw 25836
rpm.mbn 0x626780 raw 78576
tz.mbn 0x639ac0 raw 85360
fallback/verstage 0x64e880 stage 41620
fallback/romstage 0x658b80 stage 19556
fallback/ramstage 0x65d840 stage 25579
fallback/payload 0x663c80 payload 64811
u-boot.dtb 0x673a00 (unknown) 2993
(empty) 0x674600 null 113112
$ cbfstool /build/storm/firmware/image.serial.bin extract -n fallback/payload -f payload1
[..]
$ cbfstool storm.bin extract -H 0x620000 -n fallback/payload -f payload2
[..]
$ diff payload1 payload2
Change-Id: Ieb9205848aec361bb870de0d284dff06c597564f
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: b8d3c1b09a47ca24d2d2effc6de0e89d1b0a8903
Original-Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Change-Id: I227e607ccf7a9a8e2a1f3c6bbc506b8d29a35b1b
Original-Reviewed-on: https://chromium-review.googlesource.com/237561
Reviewed-on: http://review.coreboot.org/9742
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2014-12-24 04:26:54 +01:00
|
|
|
ERROR("Ran out of room in copy region.\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-20 21:48:18 +01:00
|
|
|
/* Last entry size is all the room above it, except for top 4 bytes
|
|
|
|
* which may be used by the master header pointer. This messes with
|
|
|
|
* the ability to stash something "top-aligned" into the region, but
|
|
|
|
* keeps things simpler. */
|
2018-11-02 19:14:38 +01:00
|
|
|
last_entry_size = copy_end -
|
|
|
|
((uint8_t *)dst_entry - (uint8_t *)buffer_get(dst)) -
|
|
|
|
cbfs_calculate_file_header_size("") - sizeof(int32_t);
|
cbfstool: add a command to duplicate a cbfs instance
The new command allows to create a file where the original CBFS image
is duplicated at a different offset.
The required options of the new command are -D, the offset where the
copy CBFS header is placed, and -s, the size of the new CBFS copy.
When a CBFS is copied, the bootblock area of the source CBFS is
ignored, as well as empty and deleted files in the source CBFS. The
size of the destination CBFS is calculated as the rombase size of the
source CBFS less the bootblock size.
The copy instance can be created in the image only above the original,
which rules out the use of this new command for x86 images. If
necessary, this limitation could be addressed later.
As with other cbfstool commands, unless explicitly specified the
lowest CBFS instance in the image is considered the source. If
necessary, the user can specify the source CBFS using the -H option.
BRANCH=storm
BUG=chrome-os-partner:34161, chromium:445938
TEST=run multiple cbfstool commands on a storm image:
$ cd /tmp
$ cp /build/storm/firmware/image.serial.bin storm.bin
$ cbfstool storm.bin print
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
$ cbfstool storm.bin copy -D 0x420000
E: You need to specify -s/--size.
$ cbfstool storm.bin copy -D 0x420000 -s 0x70000
$ cbfstool storm.bin print
W: Multiple (2) CBFS headers found, using the first one.
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
cbfstool storm.bin print -H 0x420000
storm.bin: 8192 kB, bootblocksize 0, romsize 4784128, offset 0x420040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x420040 raw 416
ddr.mbn 0x420240 raw 25836
rpm.mbn 0x426780 raw 78576
tz.mbn 0x439ac0 raw 85360
fallback/verstage 0x44e880 stage 41620
fallback/romstage 0x458b80 stage 19556
fallback/ramstage 0x45d840 stage 25579
config 0x463c80 raw 2878
fallback/payload 0x464800 payload 64811
u-boot.dtb 0x474580 (unknown) 2993
(empty) 0x475180 null 110168
$ cbfstool storm.bin remove -n config -H 0x420000
$ cbfstool storm.bin copy -H 0x420000 -D 0x620000 -s 0x70000
$ cbfstool storm.bin print -H 0x620000
storm.bin: 8192 kB, bootblocksize 0, romsize 6881280, offset 0x620040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x620040 raw 416
ddr.mbn 0x620240 raw 25836
rpm.mbn 0x626780 raw 78576
tz.mbn 0x639ac0 raw 85360
fallback/verstage 0x64e880 stage 41620
fallback/romstage 0x658b80 stage 19556
fallback/ramstage 0x65d840 stage 25579
fallback/payload 0x663c80 payload 64811
u-boot.dtb 0x673a00 (unknown) 2993
(empty) 0x674600 null 113112
$ cbfstool /build/storm/firmware/image.serial.bin extract -n fallback/payload -f payload1
[..]
$ cbfstool storm.bin extract -H 0x620000 -n fallback/payload -f payload2
[..]
$ diff payload1 payload2
Change-Id: Ieb9205848aec361bb870de0d284dff06c597564f
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: b8d3c1b09a47ca24d2d2effc6de0e89d1b0a8903
Original-Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Change-Id: I227e607ccf7a9a8e2a1f3c6bbc506b8d29a35b1b
Original-Reviewed-on: https://chromium-review.googlesource.com/237561
Reviewed-on: http://review.coreboot.org/9742
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2014-12-24 04:26:54 +01:00
|
|
|
|
|
|
|
if (last_entry_size < 0)
|
|
|
|
WARN("No room to create the last entry!\n")
|
|
|
|
else
|
2015-08-12 09:12:06 +02:00
|
|
|
cbfs_create_empty_entry(dst_entry, CBFS_COMPONENT_NULL,
|
|
|
|
last_entry_size, "");
|
cbfstool: add a command to duplicate a cbfs instance
The new command allows to create a file where the original CBFS image
is duplicated at a different offset.
The required options of the new command are -D, the offset where the
copy CBFS header is placed, and -s, the size of the new CBFS copy.
When a CBFS is copied, the bootblock area of the source CBFS is
ignored, as well as empty and deleted files in the source CBFS. The
size of the destination CBFS is calculated as the rombase size of the
source CBFS less the bootblock size.
The copy instance can be created in the image only above the original,
which rules out the use of this new command for x86 images. If
necessary, this limitation could be addressed later.
As with other cbfstool commands, unless explicitly specified the
lowest CBFS instance in the image is considered the source. If
necessary, the user can specify the source CBFS using the -H option.
BRANCH=storm
BUG=chrome-os-partner:34161, chromium:445938
TEST=run multiple cbfstool commands on a storm image:
$ cd /tmp
$ cp /build/storm/firmware/image.serial.bin storm.bin
$ cbfstool storm.bin print
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
$ cbfstool storm.bin copy -D 0x420000
E: You need to specify -s/--size.
$ cbfstool storm.bin copy -D 0x420000 -s 0x70000
$ cbfstool storm.bin print
W: Multiple (2) CBFS headers found, using the first one.
storm.bin: 8192 kB, bootblocksize 34472, romsize 458752, offset 0x8700
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x8700 raw 416
ddr.mbn 0x8900 raw 25836
rpm.mbn 0xee40 raw 78576
tz.mbn 0x22180 raw 85360
fallback/verstage 0x36f40 stage 41620
fallback/romstage 0x41240 stage 19556
fallback/ramstage 0x45f00 stage 25579
config 0x4c340 raw 2878
fallback/payload 0x4cec0 payload 64811
u-boot.dtb 0x5cc40 (unknown) 2993
(empty) 0x5d840 null 75608
cbfstool storm.bin print -H 0x420000
storm.bin: 8192 kB, bootblocksize 0, romsize 4784128, offset 0x420040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x420040 raw 416
ddr.mbn 0x420240 raw 25836
rpm.mbn 0x426780 raw 78576
tz.mbn 0x439ac0 raw 85360
fallback/verstage 0x44e880 stage 41620
fallback/romstage 0x458b80 stage 19556
fallback/ramstage 0x45d840 stage 25579
config 0x463c80 raw 2878
fallback/payload 0x464800 payload 64811
u-boot.dtb 0x474580 (unknown) 2993
(empty) 0x475180 null 110168
$ cbfstool storm.bin remove -n config -H 0x420000
$ cbfstool storm.bin copy -H 0x420000 -D 0x620000 -s 0x70000
$ cbfstool storm.bin print -H 0x620000
storm.bin: 8192 kB, bootblocksize 0, romsize 6881280, offset 0x620040
alignment: 64 bytes, architecture: arm
Name Offset Type Size
cdt.mbn 0x620040 raw 416
ddr.mbn 0x620240 raw 25836
rpm.mbn 0x626780 raw 78576
tz.mbn 0x639ac0 raw 85360
fallback/verstage 0x64e880 stage 41620
fallback/romstage 0x658b80 stage 19556
fallback/ramstage 0x65d840 stage 25579
fallback/payload 0x663c80 payload 64811
u-boot.dtb 0x673a00 (unknown) 2993
(empty) 0x674600 null 113112
$ cbfstool /build/storm/firmware/image.serial.bin extract -n fallback/payload -f payload1
[..]
$ cbfstool storm.bin extract -H 0x620000 -n fallback/payload -f payload2
[..]
$ diff payload1 payload2
Change-Id: Ieb9205848aec361bb870de0d284dff06c597564f
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: b8d3c1b09a47ca24d2d2effc6de0e89d1b0a8903
Original-Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Change-Id: I227e607ccf7a9a8e2a1f3c6bbc506b8d29a35b1b
Original-Reviewed-on: https://chromium-review.googlesource.com/237561
Reviewed-on: http://review.coreboot.org/9742
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2014-12-24 04:26:54 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-19 14:39:58 +02:00
|
|
|
int cbfs_expand_to_region(struct buffer *region)
|
|
|
|
{
|
|
|
|
if (buffer_get(region) == NULL)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
struct cbfs_image image;
|
|
|
|
memset(&image, 0, sizeof(image));
|
|
|
|
if (cbfs_image_from_buffer(&image, region, 0)) {
|
|
|
|
ERROR("reading CBFS failed!\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t region_sz = buffer_size(region);
|
|
|
|
|
|
|
|
struct cbfs_file *entry;
|
|
|
|
for (entry = buffer_get(region);
|
|
|
|
cbfs_is_valid_entry(&image, entry);
|
|
|
|
entry = cbfs_find_next_entry(&image, entry)) {
|
|
|
|
/* just iterate through */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* entry now points to the first aligned address after the last valid
|
|
|
|
* file header. That's either outside the image or exactly the place
|
|
|
|
* where we need to create a new file.
|
|
|
|
*/
|
2018-11-02 19:14:38 +01:00
|
|
|
int last_entry_size = region_sz -
|
|
|
|
((uint8_t *)entry - (uint8_t *)buffer_get(region)) -
|
|
|
|
cbfs_calculate_file_header_size("") - sizeof(int32_t);
|
2017-09-19 14:39:58 +02:00
|
|
|
|
|
|
|
if (last_entry_size > 0) {
|
|
|
|
cbfs_create_empty_entry(entry, CBFS_COMPONENT_NULL,
|
|
|
|
last_entry_size, "");
|
|
|
|
/* If the last entry was an empty file, merge them. */
|
|
|
|
cbfs_walk(&image, cbfs_merge_empty_entry, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-20 11:59:18 +02:00
|
|
|
int cbfs_truncate_space(struct buffer *region, uint32_t *size)
|
|
|
|
{
|
|
|
|
if (buffer_get(region) == NULL)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
struct cbfs_image image;
|
|
|
|
memset(&image, 0, sizeof(image));
|
|
|
|
if (cbfs_image_from_buffer(&image, region, 0)) {
|
|
|
|
ERROR("reading CBFS failed!\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct cbfs_file *entry, *trailer;
|
|
|
|
for (trailer = entry = buffer_get(region);
|
|
|
|
cbfs_is_valid_entry(&image, entry);
|
|
|
|
trailer = entry,
|
|
|
|
entry = cbfs_find_next_entry(&image, entry)) {
|
|
|
|
/* just iterate through */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* trailer now points to the last valid CBFS entry's header.
|
|
|
|
* If that file is empty, remove it and report its header's offset as
|
|
|
|
* maximum size.
|
|
|
|
*/
|
|
|
|
if ((strlen(trailer->filename) != 0) &&
|
|
|
|
(trailer->type != htonl(CBFS_COMPONENT_NULL)) &&
|
|
|
|
(trailer->type != htonl(CBFS_COMPONENT_DELETED))) {
|
|
|
|
/* nothing to truncate. Return de-facto CBFS size in case it
|
|
|
|
* was already truncated. */
|
2018-11-02 19:14:38 +01:00
|
|
|
*size = (uint8_t *)entry - (uint8_t *)buffer_get(region);
|
2017-09-20 11:59:18 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2018-11-02 19:14:38 +01:00
|
|
|
*size = (uint8_t *)trailer - (uint8_t *)buffer_get(region);
|
2017-09-20 11:59:18 +02:00
|
|
|
memset(trailer, 0xff, buffer_size(region) - *size);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-27 00:08:56 +01:00
|
|
|
static size_t cbfs_file_entry_metadata_size(const struct cbfs_file *f)
|
|
|
|
{
|
|
|
|
return ntohl(f->offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t cbfs_file_entry_data_size(const struct cbfs_file *f)
|
|
|
|
{
|
|
|
|
return ntohl(f->len);
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t cbfs_file_entry_size(const struct cbfs_file *f)
|
|
|
|
{
|
|
|
|
return cbfs_file_entry_metadata_size(f) + cbfs_file_entry_data_size(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
int cbfs_compact_instance(struct cbfs_image *image)
|
|
|
|
{
|
|
|
|
assert(image);
|
|
|
|
|
|
|
|
struct cbfs_file *prev;
|
|
|
|
struct cbfs_file *cur;
|
|
|
|
|
|
|
|
/* The prev entry will always be an empty entry. */
|
|
|
|
prev = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note: this function does not honor alignment or fixed location files.
|
|
|
|
* It's behavior is akin to cbfs_copy_instance() in that it expects
|
|
|
|
* the caller to understand the ramifications of compacting a
|
|
|
|
* fragmented CBFS image.
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (cur = cbfs_find_first_entry(image);
|
|
|
|
cur && cbfs_is_valid_entry(image, cur);
|
|
|
|
cur = cbfs_find_next_entry(image, cur)) {
|
|
|
|
size_t prev_size;
|
|
|
|
size_t cur_size;
|
|
|
|
size_t empty_metadata_size;
|
|
|
|
size_t spill_size;
|
|
|
|
uint32_t type = htonl(cur->type);
|
|
|
|
|
|
|
|
/* Current entry is empty. Kepp track of it. */
|
|
|
|
if ((type == htonl(CBFS_COMPONENT_NULL)) ||
|
|
|
|
(type == htonl(CBFS_COMPONENT_DELETED))) {
|
|
|
|
prev = cur;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Need to ensure the previous entry is an empty one. */
|
|
|
|
if (prev == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* At this point prev is an empty entry. Put the non-empty
|
2020-01-29 13:31:16 +01:00
|
|
|
* file in prev's location. Then add a new empty entry. This
|
2016-01-27 00:08:56 +01:00
|
|
|
* essentialy bubbles empty entries towards the end. */
|
|
|
|
|
|
|
|
prev_size = cbfs_file_entry_size(prev);
|
|
|
|
cur_size = cbfs_file_entry_size(cur);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Adjust the empty file size by the actual space occupied
|
|
|
|
* bewtween the beginning of the empty file and the non-empty
|
|
|
|
* file.
|
|
|
|
*/
|
|
|
|
prev_size += (cbfs_get_entry_addr(image, cur) -
|
|
|
|
cbfs_get_entry_addr(image, prev)) - prev_size;
|
|
|
|
|
|
|
|
/* Move the non-empty file over the empty file. */
|
|
|
|
memmove(prev, cur, cur_size);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get location of the empty file. Note that since prev was
|
|
|
|
* overwritten with the non-empty file the previously moved
|
|
|
|
* file needs to be used to calculate the empty file's location.
|
|
|
|
*/
|
|
|
|
cur = cbfs_find_next_entry(image, prev);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The total space to work with for swapping the 2 entries
|
|
|
|
* consists of the 2 files' sizes combined. However, the
|
|
|
|
* cbfs_file entries start on CBFS_ALIGNMENT boundaries.
|
|
|
|
* Because of this the empty file size may end up smaller
|
|
|
|
* because of the non-empty file's metadata and data length.
|
|
|
|
*
|
|
|
|
* Calculate the spill size which is the amount of data lost
|
|
|
|
* due to the alignment constraints after moving the non-empty
|
|
|
|
* file.
|
|
|
|
*/
|
|
|
|
spill_size = (cbfs_get_entry_addr(image, cur) -
|
|
|
|
cbfs_get_entry_addr(image, prev)) - cur_size;
|
|
|
|
|
|
|
|
empty_metadata_size = cbfs_calculate_file_header_size("");
|
|
|
|
|
|
|
|
/* Check if new empty size can contain the metadata. */
|
|
|
|
if (empty_metadata_size + spill_size > prev_size) {
|
|
|
|
ERROR("Unable to swap '%s' with prev empty entry.\n",
|
|
|
|
prev->filename);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the empty file's size. */
|
|
|
|
prev_size -= spill_size + empty_metadata_size;
|
|
|
|
|
|
|
|
/* Create new empty file. */
|
|
|
|
cbfs_create_empty_entry(cur, CBFS_COMPONENT_NULL,
|
|
|
|
prev_size, "");
|
|
|
|
|
|
|
|
/* Merge any potential empty entries together. */
|
|
|
|
cbfs_walk(image, cbfs_merge_empty_entry, NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Since current switched to an empty file keep track of it.
|
|
|
|
* Even if any empty files were merged the empty entry still
|
|
|
|
* starts at previously calculated location.
|
|
|
|
*/
|
|
|
|
prev = cur;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-26 20:51:36 +01:00
|
|
|
int cbfs_image_delete(struct cbfs_image *image)
|
|
|
|
{
|
2014-03-08 14:05:18 +01:00
|
|
|
if (image == NULL)
|
|
|
|
return 0;
|
|
|
|
|
2013-01-28 18:56:17 +01:00
|
|
|
buffer_delete(&image->buffer);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-01-29 03:24:00 +01:00
|
|
|
/* Tries to add an entry with its data (CBFS_SUBHEADER) at given offset. */
|
|
|
|
static int cbfs_add_entry_at(struct cbfs_image *image,
|
|
|
|
struct cbfs_file *entry,
|
|
|
|
const void *data,
|
2015-08-11 15:55:16 +02:00
|
|
|
uint32_t content_offset,
|
2018-11-20 13:54:49 +01:00
|
|
|
const struct cbfs_file *header,
|
|
|
|
const size_t len_align)
|
2013-03-26 20:51:36 +01:00
|
|
|
{
|
2013-01-29 03:24:00 +01:00
|
|
|
struct cbfs_file *next = cbfs_find_next_entry(image, entry);
|
|
|
|
uint32_t addr = cbfs_get_entry_addr(image, entry),
|
|
|
|
addr_next = cbfs_get_entry_addr(image, next);
|
2015-08-11 15:55:16 +02:00
|
|
|
uint32_t min_entry_size = cbfs_calculate_file_header_size("");
|
2015-08-25 12:24:49 +02:00
|
|
|
uint32_t len, header_offset;
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
uint32_t align = image->has_header ? image->header.align :
|
|
|
|
CBFS_ENTRY_ALIGNMENT;
|
2015-08-25 22:27:57 +02:00
|
|
|
uint32_t header_size = ntohl(header->offset);
|
2013-01-29 03:24:00 +01:00
|
|
|
|
2015-08-25 12:24:49 +02:00
|
|
|
header_offset = content_offset - header_size;
|
|
|
|
if (header_offset % align)
|
|
|
|
header_offset -= header_offset % align;
|
|
|
|
if (header_offset < addr) {
|
2013-01-29 03:24:00 +01:00
|
|
|
ERROR("No space to hold cbfs_file header.");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Process buffer BEFORE content_offset.
|
2015-08-25 12:24:49 +02:00
|
|
|
if (header_offset - addr > min_entry_size) {
|
2013-01-29 03:24:00 +01:00
|
|
|
DEBUG("|min|...|header|content|... <create new entry>\n");
|
2015-08-25 12:24:49 +02:00
|
|
|
len = header_offset - addr - min_entry_size;
|
2015-08-12 09:12:06 +02:00
|
|
|
cbfs_create_empty_entry(entry, CBFS_COMPONENT_NULL, len, "");
|
2013-01-29 03:24:00 +01:00
|
|
|
if (verbose > 1) cbfs_print_entry_info(image, entry, stderr);
|
|
|
|
entry = cbfs_find_next_entry(image, entry);
|
|
|
|
addr = cbfs_get_entry_addr(image, entry);
|
|
|
|
}
|
|
|
|
|
2015-08-25 13:00:04 +02:00
|
|
|
len = content_offset - addr - header_size;
|
2015-08-25 22:26:02 +02:00
|
|
|
memcpy(entry, header, header_size);
|
2015-08-25 13:00:04 +02:00
|
|
|
if (len != 0) {
|
2018-08-23 18:08:20 +02:00
|
|
|
/* the header moved backwards a bit to accommodate cbfs_file
|
2015-08-25 13:00:04 +02:00
|
|
|
* alignment requirements, so patch up ->offset to still point
|
|
|
|
* to file data.
|
|
|
|
*/
|
2013-01-29 03:24:00 +01:00
|
|
|
DEBUG("|..|header|content|... <use offset to create entry>\n");
|
2015-08-25 13:11:28 +02:00
|
|
|
DEBUG("before: offset=0x%x\n", ntohl(entry->offset));
|
2013-01-29 03:24:00 +01:00
|
|
|
// TODO reset expanded name buffer to 0xFF.
|
2015-08-25 13:00:04 +02:00
|
|
|
entry->offset = htonl(ntohl(entry->offset) + len);
|
2015-08-25 13:11:28 +02:00
|
|
|
DEBUG("after: offset=0x%x\n", ntohl(entry->len));
|
2013-01-29 03:24:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ready to fill data into entry.
|
|
|
|
DEBUG("content_offset: 0x%x, entry location: %x\n",
|
|
|
|
content_offset, (int)((char*)CBFS_SUBHEADER(entry) -
|
|
|
|
image->buffer.data));
|
|
|
|
assert((char*)CBFS_SUBHEADER(entry) - image->buffer.data ==
|
2015-04-28 13:09:36 +02:00
|
|
|
(ptrdiff_t)content_offset);
|
2015-08-25 13:16:04 +02:00
|
|
|
memcpy(CBFS_SUBHEADER(entry), data, ntohl(entry->len));
|
2013-01-29 03:24:00 +01:00
|
|
|
if (verbose > 1) cbfs_print_entry_info(image, entry, stderr);
|
|
|
|
|
2018-11-20 13:54:49 +01:00
|
|
|
// Align the length to a multiple of len_align
|
|
|
|
if (len_align &&
|
|
|
|
((ntohl(entry->offset) + ntohl(entry->len)) % len_align)) {
|
|
|
|
size_t off = (ntohl(entry->offset) + ntohl(entry->len)) % len_align;
|
|
|
|
entry->len = htonl(ntohl(entry->len) + len_align - off);
|
|
|
|
}
|
|
|
|
|
2013-01-29 03:24:00 +01:00
|
|
|
// Process buffer AFTER entry.
|
|
|
|
entry = cbfs_find_next_entry(image, entry);
|
|
|
|
addr = cbfs_get_entry_addr(image, entry);
|
2015-04-03 05:58:26 +02:00
|
|
|
if (addr == addr_next)
|
|
|
|
return 0;
|
2013-01-29 03:24:00 +01:00
|
|
|
|
2015-04-03 05:58:26 +02:00
|
|
|
assert(addr < addr_next);
|
2013-01-29 03:24:00 +01:00
|
|
|
if (addr_next - addr < min_entry_size) {
|
cbfstool: Make the add action choose an aligned entries capacity
This fixes an inconsistency between `cbfstool create` and `cbfstool add` that
was resulting in confusing claims about the amount of free space at the end of a
CBFS. Calls to `cbfstool add` check whether a file fits under a given empty file
entry by testing whether it would collide with the beginning of the *subsequent*
file header; thus, if a file's end is unaligned, its reported size will not
match the actual available capacity. Although deleted entries always end on an
alignment boundary because `cbfstool remove` expands them to fill the available
space, `cbfstool create` doesn't necessarily size a new entries region to result
in an empty entry with an aligned end.
This problem never resulted in clobbering important data because cbfstool would
blindly reserve 64B (or the selected alignment) of free space immediately after
the all-inclusive empty file entry. This change alters the way this reservation
is reported: only the overhang past the alignment is used as hidden padding, and
the empty entry's capacity is always reported such that it ends at an aligned
address.
Much of the time that went into this patch was spent building trust in the
trickery cbfstool employs to avoid explicitly tracking the image's total
capacity for entries, so below are two proofs of correctness to save others time
and discourage inadvertent breakage:
OBSERVATION (A): A check in cbfs_image_create() guarantees that an aligned CBFS
empty file header is small enough that it won't cross another aligned address.
OBSERVATION (B): In cbfs_image_create(), the initial empty entry is sized such
that its contents end on an aligned address.
THM. 1: Placing a new file within an empty entry located below an existing file
entry will never leave an aligned flash address containing neither the beginning
of a file header nor part of a file.
We can prove this by contradiction: assume a newly-added file neither fills to
the end of the preexisting empty entry nor leaves room for another aligned
empty header after it. Then the first aligned address after the end of the
newly-inserted file...
- CASE 1: ...already contains a preexisting file entry header.
+ Then that address contains a file header.
- CASE 2: ...does not already house a file entry header.
+ Then because CBFS content doesn't fall outside headers, the area between
there and the *next* aligned address after that is unused.
+ By (A), we can fit a file header without clobbering anything.
+ Then that address now contains a file header.
THM. 2: Placing a new file in an empty entry at the very end of the image such
that it fits, but leaves no room for a final header, is guaranteed not to change
the total amount of space for entries, even if that new file is later removed
from the CBFS.
Again, we use contradiction: assume that creating such a file causes a
permanent...
- CASE 1: ...increase in the amount of available space.
+ Then the combination of the inserted file, its header, and any padding
must have exceeded the empty entry in size enough for it to cross at
least one additional aligned address, since aligned addresses are how
the limit on an entry's capacity is determined.
+ But adding the file couldn't have caused us to write past any further
aligned addresses because they are the boundary's used when verifying
that sufficient capacity exists; furthermore, by (B), no entry can ever
terminate beyond where the initial empty entry did when the CBFS was
first created.
+ Then the creation of the file did not result in a space increase.
- CASE 2: ...decrease in the amount of available space.
+ Then the end of the new file entry crosses at least one fewer aligned
address than did the empty file entry.
+ Then by (A), there is room to place a new file entry that describes the
remaining available space at the first available aligned address.
+ Then there is now a new record showing the same amount of available space.
+ Then the creation of the file did not result in a space decrease.
BUG=chromium:473726
TEST=Had the following conversation with cbfstool:
$ ./cbfstool test.image create -s 0x100000 -m arm
Created CBFS image (capacity = 1048408 bytes)
$ ./cbfstool test.image print
test.image: 1024 kB, bootblocksize 0, romsize 1048576, offset 0x40
alignment: 64 bytes, architecture: arm
Name Offset Type Size
(empty) 0x40 null 1048408
$ dd if=/dev/zero of=toobigmed.bin bs=1048409 count=1
1+0 records in
1+0 records out
1048409 bytes (1.0 MB) copied, 0.0057865 s, 181 MB/s
$ ./cbfstool test.image add -t 0x50 -f toobigmed.bin -n toobig
E: Could not add [toobigmed.bin, 1048409 bytes (1023 KB)@0x0]; too big?
E: Failed to add 'toobigmed.bin' into ROM image.
$ truncate -s -1 toobigmed.bin
$ ./cbfstool test.image add -t 0x50 -f toobigmed.bin -n toobig
$ ./cbfstool test.image print
test.image: 1024 kB, bootblocksize 0, romsize 1048576, offset 0x40
alignment: 64 bytes, architecture: arm
Name Offset Type Size
toobig 0x40 raw 1048408
$ ./cbfstool test.image remove
-n toobig
$ ./cbfstool test.image print
test.image: 1024 kB, bootblocksize 0, romsize 1048576, offset 0x40
alignment: 64 bytes, architecture: arm
Name Offset Type Size
(empty) 0x40 deleted 1048408
$ ./cbfstool test.image print
test.image: 1024 kB, bootblocksize 0, romsize 1048576, offset 0x40
alignment: 64 bytes, architecture: arm
Name Offset Type Size
(empty) 0x40 deleted 1048408
BRANCH=None
Change-Id: I118743e37469ef0226970decc900db5d9b92c5df
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: e317ddca14bc36bc36e6406b758378c88e9ae04e
Original-Change-Id: I294ee489b4918646c359b06aa1581918f2d8badc
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/263962
Original-Reviewed-by: Hung-Te Lin <hungte@chromium.org>
Original-Reviewed-by: Stefan Reinauer <reinauer@google.com>
Reviewed-on: http://review.coreboot.org/9939
Tested-by: build bot (Jenkins)
2015-04-03 18:13:04 +02:00
|
|
|
DEBUG("No need for new \"empty\" entry\n");
|
|
|
|
/* No need to increase the size of the just
|
|
|
|
* stored file to extend to next file. Alignment
|
|
|
|
* of next file takes care of this.
|
|
|
|
*/
|
|
|
|
return 0;
|
2013-01-29 03:24:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
len = addr_next - addr - min_entry_size;
|
2015-11-20 23:23:44 +01:00
|
|
|
/* keep space for master header pointer */
|
2018-11-02 19:14:38 +01:00
|
|
|
if ((uint8_t *)entry + min_entry_size + len >
|
|
|
|
(uint8_t *)buffer_get(&image->buffer) +
|
|
|
|
buffer_size(&image->buffer) - sizeof(int32_t)) {
|
2015-11-20 23:23:44 +01:00
|
|
|
len -= sizeof(int32_t);
|
|
|
|
}
|
2015-08-12 09:12:06 +02:00
|
|
|
cbfs_create_empty_entry(entry, CBFS_COMPONENT_NULL, len, "");
|
2013-01-29 03:24:00 +01:00
|
|
|
if (verbose > 1) cbfs_print_entry_info(image, entry, stderr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cbfs_add_entry(struct cbfs_image *image, struct buffer *buffer,
|
2015-08-25 13:53:42 +02:00
|
|
|
uint32_t content_offset,
|
2018-11-20 13:54:49 +01:00
|
|
|
struct cbfs_file *header,
|
|
|
|
const size_t len_align)
|
2013-03-26 20:51:36 +01:00
|
|
|
{
|
2015-05-07 11:39:22 +02:00
|
|
|
assert(image);
|
|
|
|
assert(buffer);
|
|
|
|
assert(buffer->data);
|
|
|
|
assert(!IS_TOP_ALIGNED_ADDRESS(content_offset));
|
|
|
|
|
2015-08-25 22:26:02 +02:00
|
|
|
const char *name = header->filename;
|
2015-08-25 13:53:42 +02:00
|
|
|
|
2013-01-29 03:24:00 +01:00
|
|
|
uint32_t entry_type;
|
|
|
|
uint32_t addr, addr_next;
|
|
|
|
struct cbfs_file *entry, *next;
|
2015-08-12 12:29:20 +02:00
|
|
|
uint32_t need_size;
|
2015-08-25 22:27:57 +02:00
|
|
|
uint32_t header_size = ntohl(header->offset);
|
2013-01-29 03:24:00 +01:00
|
|
|
|
|
|
|
need_size = header_size + buffer->size;
|
|
|
|
DEBUG("cbfs_add_entry('%s'@0x%x) => need_size = %u+%zu=%u\n",
|
|
|
|
name, content_offset, header_size, buffer->size, need_size);
|
|
|
|
|
|
|
|
// Merge empty entries.
|
|
|
|
DEBUG("(trying to merge empty entries...)\n");
|
|
|
|
cbfs_walk(image, cbfs_merge_empty_entry, NULL);
|
|
|
|
|
|
|
|
for (entry = cbfs_find_first_entry(image);
|
2013-02-09 03:38:55 +01:00
|
|
|
entry && cbfs_is_valid_entry(image, entry);
|
2013-01-29 03:24:00 +01:00
|
|
|
entry = cbfs_find_next_entry(image, entry)) {
|
|
|
|
|
|
|
|
entry_type = ntohl(entry->type);
|
|
|
|
if (entry_type != CBFS_COMPONENT_NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
addr = cbfs_get_entry_addr(image, entry);
|
|
|
|
next = cbfs_find_next_entry(image, entry);
|
|
|
|
addr_next = cbfs_get_entry_addr(image, next);
|
|
|
|
|
|
|
|
DEBUG("cbfs_add_entry: space at 0x%x+0x%x(%d) bytes\n",
|
|
|
|
addr, addr_next - addr, addr_next - addr);
|
2014-01-21 22:28:38 +01:00
|
|
|
|
|
|
|
/* Will the file fit? Don't yet worry if we have space for a new
|
|
|
|
* "empty" entry. We take care of that later.
|
|
|
|
*/
|
2013-01-29 03:24:00 +01:00
|
|
|
if (addr + need_size > addr_next)
|
|
|
|
continue;
|
|
|
|
|
2015-08-12 12:05:21 +02:00
|
|
|
// Test for complicated cases
|
|
|
|
if (content_offset > 0) {
|
|
|
|
if (addr_next < content_offset) {
|
|
|
|
DEBUG("Not for specified offset yet");
|
|
|
|
continue;
|
|
|
|
} else if (addr > content_offset) {
|
|
|
|
DEBUG("Exceed specified content_offset.");
|
|
|
|
break;
|
|
|
|
} else if (addr + header_size > content_offset) {
|
|
|
|
ERROR("Not enough space for header.\n");
|
|
|
|
break;
|
|
|
|
} else if (content_offset + buffer->size > addr_next) {
|
|
|
|
ERROR("Not enough space for content.\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO there are more few tricky cases that we may
|
|
|
|
// want to fit by altering offset.
|
|
|
|
|
2015-08-12 12:29:20 +02:00
|
|
|
if (content_offset == 0) {
|
|
|
|
// we tested every condition earlier under which
|
|
|
|
// placing the file there might fail
|
|
|
|
content_offset = addr + header_size;
|
2013-01-29 03:24:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG("section 0x%x+0x%x for content_offset 0x%x.\n",
|
|
|
|
addr, addr_next - addr, content_offset);
|
|
|
|
|
2015-08-25 22:27:57 +02:00
|
|
|
if (cbfs_add_entry_at(image, entry, buffer->data,
|
2018-11-20 13:54:49 +01:00
|
|
|
content_offset, header, len_align) == 0) {
|
2013-01-29 03:24:00 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ERROR("Could not add [%s, %zd bytes (%zd KB)@0x%x]; too big?\n",
|
|
|
|
buffer->name, buffer->size, buffer->size / 1024, content_offset);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-03-26 20:51:36 +01:00
|
|
|
struct cbfs_file *cbfs_get_entry(struct cbfs_image *image, const char *name)
|
|
|
|
{
|
2013-01-28 19:29:49 +01:00
|
|
|
struct cbfs_file *entry;
|
|
|
|
for (entry = cbfs_find_first_entry(image);
|
2013-02-09 03:38:55 +01:00
|
|
|
entry && cbfs_is_valid_entry(image, entry);
|
2013-01-28 19:29:49 +01:00
|
|
|
entry = cbfs_find_next_entry(image, entry)) {
|
2015-07-15 16:42:38 +02:00
|
|
|
if (strcasecmp(entry->filename, name) == 0) {
|
2013-01-28 19:29:49 +01:00
|
|
|
DEBUG("cbfs_get_entry: found %s\n", name);
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-10-28 03:02:30 +01:00
|
|
|
static int cbfs_stage_decompress(struct cbfs_stage *stage, struct buffer *buff)
|
2015-10-24 00:42:32 +02:00
|
|
|
{
|
|
|
|
struct buffer reader;
|
|
|
|
char *orig_buffer;
|
|
|
|
char *new_buffer;
|
|
|
|
size_t new_buff_sz;
|
|
|
|
decomp_func_ptr decompress;
|
|
|
|
|
|
|
|
buffer_clone(&reader, buff);
|
|
|
|
|
|
|
|
/* The stage metadata is in little endian. */
|
2015-10-28 03:02:30 +01:00
|
|
|
stage->compression = xdr_le.get32(&reader);
|
|
|
|
stage->entry = xdr_le.get64(&reader);
|
|
|
|
stage->load = xdr_le.get64(&reader);
|
|
|
|
stage->len = xdr_le.get32(&reader);
|
|
|
|
stage->memlen = xdr_le.get32(&reader);
|
|
|
|
|
|
|
|
/* Create a buffer just with the uncompressed program now that the
|
|
|
|
* struct cbfs_stage has been peeled off. */
|
|
|
|
if (stage->compression == CBFS_COMPRESS_NONE) {
|
|
|
|
new_buff_sz = buffer_size(buff) - sizeof(struct cbfs_stage);
|
|
|
|
|
|
|
|
orig_buffer = buffer_get(buff);
|
|
|
|
new_buffer = calloc(1, new_buff_sz);
|
|
|
|
memcpy(new_buffer, orig_buffer + sizeof(struct cbfs_stage),
|
|
|
|
new_buff_sz);
|
|
|
|
buffer_init(buff, buff->name, new_buffer, new_buff_sz);
|
|
|
|
free(orig_buffer);
|
2015-10-24 00:42:32 +02:00
|
|
|
return 0;
|
2015-10-28 03:02:30 +01:00
|
|
|
}
|
2015-10-24 00:42:32 +02:00
|
|
|
|
2015-10-28 03:02:30 +01:00
|
|
|
decompress = decompression_function(stage->compression);
|
2015-10-24 00:42:32 +02:00
|
|
|
if (decompress == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
orig_buffer = buffer_get(buff);
|
|
|
|
|
|
|
|
/* This can be too big of a buffer needed, but there's no current
|
|
|
|
* field indicating decompressed size of data. */
|
2015-10-28 03:02:30 +01:00
|
|
|
new_buff_sz = stage->memlen;
|
2015-10-24 00:42:32 +02:00
|
|
|
new_buffer = calloc(1, new_buff_sz);
|
|
|
|
|
|
|
|
if (decompress(orig_buffer + sizeof(struct cbfs_stage),
|
|
|
|
(int)(buffer_size(buff) - sizeof(struct cbfs_stage)),
|
2015-10-28 03:02:30 +01:00
|
|
|
new_buffer, (int)new_buff_sz, &new_buff_sz)) {
|
2015-10-24 00:42:32 +02:00
|
|
|
ERROR("Couldn't decompress stage.\n");
|
|
|
|
free(new_buffer);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Include correct size for full stage info. */
|
|
|
|
buffer_init(buff, buff->name, new_buffer, new_buff_sz);
|
|
|
|
|
|
|
|
/* True decompressed size is just the data size -- no metadata. */
|
2015-10-28 03:02:30 +01:00
|
|
|
stage->len = new_buff_sz;
|
2015-10-24 00:42:32 +02:00
|
|
|
/* Stage is not compressed. */
|
2015-10-28 03:02:30 +01:00
|
|
|
stage->compression = CBFS_COMPRESS_NONE;
|
2015-10-24 00:42:32 +02:00
|
|
|
|
|
|
|
free(orig_buffer);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-09 12:35:36 +02:00
|
|
|
static int cbfs_payload_decompress(struct cbfs_payload_segment *segments,
|
|
|
|
struct buffer *buff, int num_seg)
|
|
|
|
{
|
|
|
|
struct buffer new_buffer;
|
|
|
|
struct buffer seg_buffer;
|
|
|
|
size_t new_buff_sz;
|
|
|
|
char *in_ptr;
|
|
|
|
char *out_ptr;
|
|
|
|
size_t new_offset;
|
|
|
|
decomp_func_ptr decompress;
|
|
|
|
|
|
|
|
new_offset = num_seg * sizeof(*segments);
|
|
|
|
new_buff_sz = num_seg * sizeof(*segments);
|
|
|
|
|
|
|
|
/* Find out and allocate the amount of memory occupied
|
|
|
|
* by the binary data */
|
|
|
|
for (int i = 0; i < num_seg; i++)
|
|
|
|
new_buff_sz += segments[i].mem_len;
|
|
|
|
|
2016-08-05 17:27:18 +02:00
|
|
|
if (buffer_create(&new_buffer, new_buff_sz, "decompressed_buff"))
|
|
|
|
return -1;
|
2016-06-09 12:35:36 +02:00
|
|
|
|
|
|
|
in_ptr = buffer_get(buff) + new_offset;
|
|
|
|
out_ptr = buffer_get(&new_buffer) + new_offset;
|
|
|
|
|
|
|
|
for (int i = 0; i < num_seg; i++) {
|
|
|
|
struct buffer tbuff;
|
|
|
|
size_t decomp_size;
|
|
|
|
|
|
|
|
/* Segments BSS and ENTRY do not have binary data. */
|
|
|
|
if (segments[i].type == PAYLOAD_SEGMENT_BSS ||
|
|
|
|
segments[i].type == PAYLOAD_SEGMENT_ENTRY) {
|
|
|
|
continue;
|
|
|
|
} else if (segments[i].type == PAYLOAD_SEGMENT_PARAMS) {
|
|
|
|
memcpy(out_ptr, in_ptr, segments[i].len);
|
|
|
|
segments[i].offset = new_offset;
|
|
|
|
new_offset += segments[i].len;
|
|
|
|
in_ptr += segments[i].len;
|
|
|
|
out_ptr += segments[i].len;
|
|
|
|
segments[i].compression = CBFS_COMPRESS_NONE;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-07-18 07:23:52 +02:00
|
|
|
/* The payload uses an unknown compression algorithm. */
|
|
|
|
decompress = decompression_function(segments[i].compression);
|
|
|
|
if (decompress == NULL) {
|
|
|
|
ERROR("Unknown decompression algorithm: %u\n",
|
|
|
|
segments[i].compression);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-08-05 17:27:18 +02:00
|
|
|
if (buffer_create(&tbuff, segments[i].mem_len, "segment")) {
|
|
|
|
buffer_delete(&new_buffer);
|
|
|
|
return -1;
|
|
|
|
}
|
2016-06-09 12:35:36 +02:00
|
|
|
|
|
|
|
if (decompress(in_ptr, segments[i].len, buffer_get(&tbuff),
|
|
|
|
(int) buffer_size(&tbuff),
|
|
|
|
&decomp_size)) {
|
|
|
|
ERROR("Couldn't decompress payload segment %u\n", i);
|
|
|
|
buffer_delete(&new_buffer);
|
2016-08-05 17:32:23 +02:00
|
|
|
buffer_delete(&tbuff);
|
2016-06-09 12:35:36 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(out_ptr, buffer_get(&tbuff), decomp_size);
|
|
|
|
|
|
|
|
in_ptr += segments[i].len;
|
|
|
|
|
|
|
|
/* Update the offset of the segment. */
|
|
|
|
segments[i].offset = new_offset;
|
|
|
|
/* True decompressed size is just the data size. No metadata */
|
|
|
|
segments[i].len = decomp_size;
|
|
|
|
/* Segment is not compressed. */
|
|
|
|
segments[i].compression = CBFS_COMPRESS_NONE;
|
|
|
|
|
|
|
|
/* Update the offset and output buffer pointer. */
|
|
|
|
new_offset += decomp_size;
|
|
|
|
out_ptr += decomp_size;
|
|
|
|
|
|
|
|
buffer_delete(&tbuff);
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer_splice(&seg_buffer, &new_buffer, 0, 0);
|
|
|
|
xdr_segs(&seg_buffer, segments, num_seg);
|
|
|
|
|
|
|
|
buffer_delete(buff);
|
|
|
|
*buff = new_buffer;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-28 03:02:30 +01:00
|
|
|
static int init_elf_from_arch(Elf64_Ehdr *ehdr, uint32_t cbfs_arch)
|
|
|
|
{
|
|
|
|
int endian;
|
|
|
|
int nbits;
|
|
|
|
int machine;
|
|
|
|
|
|
|
|
switch (cbfs_arch) {
|
|
|
|
case CBFS_ARCHITECTURE_X86:
|
|
|
|
endian = ELFDATA2LSB;
|
|
|
|
nbits = ELFCLASS32;
|
|
|
|
machine = EM_386;
|
|
|
|
break;
|
|
|
|
case CBFS_ARCHITECTURE_ARM:
|
|
|
|
endian = ELFDATA2LSB;
|
|
|
|
nbits = ELFCLASS32;
|
|
|
|
machine = EM_ARM;
|
|
|
|
break;
|
|
|
|
case CBFS_ARCHITECTURE_AARCH64:
|
|
|
|
endian = ELFDATA2LSB;
|
|
|
|
nbits = ELFCLASS64;
|
|
|
|
machine = EM_AARCH64;
|
|
|
|
break;
|
|
|
|
case CBFS_ARCHITECTURE_MIPS:
|
|
|
|
endian = ELFDATA2LSB;
|
|
|
|
nbits = ELFCLASS32;
|
|
|
|
machine = EM_MIPS;
|
|
|
|
break;
|
|
|
|
case CBFS_ARCHITECTURE_RISCV:
|
|
|
|
endian = ELFDATA2LSB;
|
|
|
|
nbits = ELFCLASS32;
|
|
|
|
machine = EM_RISCV;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ERROR("Unsupported arch: %x\n", cbfs_arch);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
elf_init_eheader(ehdr, machine, nbits, endian);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cbfs_stage_make_elf(struct buffer *buff, uint32_t arch)
|
|
|
|
{
|
|
|
|
Elf64_Ehdr ehdr;
|
|
|
|
Elf64_Shdr shdr;
|
|
|
|
struct cbfs_stage stage;
|
|
|
|
struct elf_writer *ew;
|
|
|
|
struct buffer elf_out;
|
|
|
|
size_t empty_sz;
|
2015-10-28 17:39:34 +01:00
|
|
|
int rmod_ret;
|
2015-10-28 03:02:30 +01:00
|
|
|
|
2016-06-26 00:24:25 +02:00
|
|
|
if (arch == CBFS_ARCHITECTURE_UNKNOWN) {
|
|
|
|
ERROR("You need to specify -m ARCH.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-10-28 03:02:30 +01:00
|
|
|
if (cbfs_stage_decompress(&stage, buff)) {
|
|
|
|
ERROR("Failed to decompress stage.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (init_elf_from_arch(&ehdr, arch))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ehdr.e_entry = stage.entry;
|
|
|
|
|
2015-10-28 17:39:34 +01:00
|
|
|
/* Attempt rmodule translation first. */
|
|
|
|
rmod_ret = rmodule_stage_to_elf(&ehdr, buff);
|
|
|
|
|
|
|
|
if (rmod_ret < 0) {
|
|
|
|
ERROR("rmodule parsing failed\n");
|
|
|
|
return -1;
|
|
|
|
} else if (rmod_ret == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Rmodule couldn't do anything with the data. Continue on with SELF. */
|
|
|
|
|
2015-10-28 03:02:30 +01:00
|
|
|
ew = elf_writer_init(&ehdr);
|
|
|
|
if (ew == NULL) {
|
|
|
|
ERROR("Unable to init ELF writer.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&shdr, 0, sizeof(shdr));
|
|
|
|
shdr.sh_type = SHT_PROGBITS;
|
|
|
|
shdr.sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR;
|
|
|
|
shdr.sh_addr = stage.load;
|
|
|
|
shdr.sh_size = stage.len;
|
|
|
|
empty_sz = stage.memlen - stage.len;
|
|
|
|
|
|
|
|
if (elf_writer_add_section(ew, &shdr, buff, ".program")) {
|
|
|
|
ERROR("Unable to add ELF section: .program\n");
|
|
|
|
elf_writer_destroy(ew);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (empty_sz != 0) {
|
|
|
|
struct buffer b;
|
|
|
|
|
|
|
|
buffer_init(&b, NULL, NULL, 0);
|
|
|
|
memset(&shdr, 0, sizeof(shdr));
|
|
|
|
shdr.sh_type = SHT_NOBITS;
|
|
|
|
shdr.sh_flags = SHF_WRITE | SHF_ALLOC;
|
|
|
|
shdr.sh_addr = stage.load + stage.len;
|
|
|
|
shdr.sh_size = empty_sz;
|
|
|
|
if (elf_writer_add_section(ew, &shdr, &b, ".empty")) {
|
|
|
|
ERROR("Unable to add ELF section: .empty\n");
|
|
|
|
elf_writer_destroy(ew);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (elf_writer_serialize(ew, &elf_out)) {
|
|
|
|
ERROR("Unable to create ELF file from stage.\n");
|
|
|
|
elf_writer_destroy(ew);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Flip buffer with the created ELF one. */
|
|
|
|
buffer_delete(buff);
|
|
|
|
*buff = elf_out;
|
|
|
|
|
|
|
|
elf_writer_destroy(ew);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-09 12:35:36 +02:00
|
|
|
static int cbfs_payload_make_elf(struct buffer *buff, uint32_t arch)
|
|
|
|
{
|
|
|
|
Elf64_Ehdr ehdr;
|
|
|
|
Elf64_Shdr shdr;
|
2016-08-05 17:20:37 +02:00
|
|
|
struct cbfs_payload_segment *segs = NULL;
|
2016-08-09 15:01:58 +02:00
|
|
|
struct elf_writer *ew = NULL;
|
2016-06-09 12:35:36 +02:00
|
|
|
struct buffer elf_out;
|
|
|
|
int segments = 0;
|
2016-08-05 17:20:37 +02:00
|
|
|
int retval = -1;
|
2016-06-09 12:35:36 +02:00
|
|
|
|
2016-06-26 00:24:25 +02:00
|
|
|
if (arch == CBFS_ARCHITECTURE_UNKNOWN) {
|
|
|
|
ERROR("You need to specify -m ARCH.\n");
|
2016-08-05 17:20:37 +02:00
|
|
|
goto out;
|
2016-06-26 00:24:25 +02:00
|
|
|
}
|
|
|
|
|
2016-06-09 12:35:36 +02:00
|
|
|
/* Count the number of segments inside buffer */
|
|
|
|
while (true) {
|
|
|
|
uint32_t payload_type = 0;
|
|
|
|
|
|
|
|
struct cbfs_payload_segment *seg;
|
|
|
|
|
|
|
|
seg = buffer_get(buff);
|
|
|
|
payload_type = read_be32(&seg[segments].type);
|
|
|
|
|
|
|
|
if (payload_type == PAYLOAD_SEGMENT_CODE) {
|
|
|
|
segments++;
|
|
|
|
} else if (payload_type == PAYLOAD_SEGMENT_DATA) {
|
|
|
|
segments++;
|
|
|
|
} else if (payload_type == PAYLOAD_SEGMENT_BSS) {
|
|
|
|
segments++;
|
|
|
|
} else if (payload_type == PAYLOAD_SEGMENT_PARAMS) {
|
|
|
|
segments++;
|
|
|
|
} else if (payload_type == PAYLOAD_SEGMENT_ENTRY) {
|
|
|
|
/* The last segment in a payload is always ENTRY as
|
|
|
|
* specified by the parse_elf_to_payload() function.
|
|
|
|
* Therefore there is no need to continue looking for
|
|
|
|
* segments.*/
|
|
|
|
segments++;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
ERROR("Unknown payload segment type: %x\n",
|
|
|
|
payload_type);
|
2016-08-05 17:20:37 +02:00
|
|
|
goto out;
|
2016-06-09 12:35:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
segs = malloc(segments * sizeof(*segs));
|
|
|
|
|
|
|
|
/* Decode xdr segments */
|
|
|
|
for (int i = 0; i < segments; i++) {
|
|
|
|
struct cbfs_payload_segment *serialized_seg = buffer_get(buff);
|
|
|
|
xdr_get_seg(&segs[i], &serialized_seg[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cbfs_payload_decompress(segs, buff, segments)) {
|
|
|
|
ERROR("Failed to decompress payload.\n");
|
2016-08-05 17:20:37 +02:00
|
|
|
goto out;
|
2016-06-09 12:35:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (init_elf_from_arch(&ehdr, arch))
|
2016-08-05 17:20:37 +02:00
|
|
|
goto out;
|
2016-06-09 12:35:36 +02:00
|
|
|
|
|
|
|
ehdr.e_entry = segs[segments-1].load_addr;
|
|
|
|
|
|
|
|
ew = elf_writer_init(&ehdr);
|
|
|
|
if (ew == NULL) {
|
|
|
|
ERROR("Unable to init ELF writer.\n");
|
2016-08-05 17:20:37 +02:00
|
|
|
goto out;
|
2016-06-09 12:35:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < segments; i++) {
|
|
|
|
struct buffer tbuff;
|
2016-08-05 17:12:31 +02:00
|
|
|
size_t empty_sz = 0;
|
2016-06-09 12:35:36 +02:00
|
|
|
|
|
|
|
memset(&shdr, 0, sizeof(shdr));
|
|
|
|
char *name = NULL;
|
|
|
|
|
|
|
|
if (segs[i].type == PAYLOAD_SEGMENT_CODE) {
|
|
|
|
shdr.sh_type = SHT_PROGBITS;
|
|
|
|
shdr.sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR;
|
|
|
|
shdr.sh_addr = segs[i].load_addr;
|
|
|
|
shdr.sh_size = segs[i].len;
|
|
|
|
empty_sz = segs[i].mem_len - segs[i].len;
|
|
|
|
name = strdup(".text");
|
|
|
|
buffer_splice(&tbuff, buff, segs[i].offset,
|
|
|
|
segs[i].len);
|
|
|
|
} else if (segs[i].type == PAYLOAD_SEGMENT_DATA) {
|
|
|
|
shdr.sh_type = SHT_PROGBITS;
|
|
|
|
shdr.sh_flags = SHF_ALLOC | SHF_WRITE;
|
|
|
|
shdr.sh_addr = segs[i].load_addr;
|
|
|
|
shdr.sh_size = segs[i].len;
|
|
|
|
empty_sz = segs[i].mem_len - segs[i].len;
|
|
|
|
name = strdup(".data");
|
|
|
|
buffer_splice(&tbuff, buff, segs[i].offset,
|
|
|
|
segs[i].len);
|
|
|
|
} else if (segs[i].type == PAYLOAD_SEGMENT_BSS) {
|
|
|
|
shdr.sh_type = SHT_NOBITS;
|
|
|
|
shdr.sh_flags = SHF_ALLOC | SHF_WRITE;
|
|
|
|
shdr.sh_addr = segs[i].load_addr;
|
|
|
|
shdr.sh_size = segs[i].len;
|
|
|
|
name = strdup(".bss");
|
|
|
|
buffer_splice(&tbuff, buff, 0, 0);
|
|
|
|
} else if (segs[i].type == PAYLOAD_SEGMENT_PARAMS) {
|
|
|
|
shdr.sh_type = SHT_NOTE;
|
|
|
|
shdr.sh_flags = 0;
|
|
|
|
shdr.sh_size = segs[i].len;
|
|
|
|
name = strdup(".note.pinfo");
|
|
|
|
buffer_splice(&tbuff, buff, segs[i].offset,
|
|
|
|
segs[i].len);
|
|
|
|
} else if (segs[i].type == PAYLOAD_SEGMENT_ENTRY) {
|
|
|
|
break;
|
2017-01-13 13:30:54 +01:00
|
|
|
} else {
|
|
|
|
ERROR("unknown ELF segment type\n");
|
|
|
|
goto out;
|
2016-06-09 12:35:36 +02:00
|
|
|
}
|
|
|
|
|
2017-01-13 13:30:54 +01:00
|
|
|
if (!name) {
|
|
|
|
ERROR("out of memory\n");
|
|
|
|
goto out;
|
|
|
|
}
|
2016-06-09 12:35:36 +02:00
|
|
|
|
|
|
|
if (elf_writer_add_section(ew, &shdr, &tbuff, name)) {
|
|
|
|
ERROR("Unable to add ELF section: %s\n", name);
|
2017-01-13 13:30:54 +01:00
|
|
|
free(name);
|
2016-08-05 17:20:37 +02:00
|
|
|
goto out;
|
2016-06-09 12:35:36 +02:00
|
|
|
}
|
2017-01-13 13:30:54 +01:00
|
|
|
free(name);
|
2016-06-09 12:35:36 +02:00
|
|
|
|
|
|
|
if (empty_sz != 0) {
|
|
|
|
struct buffer b;
|
|
|
|
|
|
|
|
buffer_init(&b, NULL, NULL, 0);
|
|
|
|
memset(&shdr, 0, sizeof(shdr));
|
|
|
|
shdr.sh_type = SHT_NOBITS;
|
|
|
|
shdr.sh_flags = SHF_WRITE | SHF_ALLOC;
|
|
|
|
shdr.sh_addr = segs[i].load_addr + segs[i].len;
|
|
|
|
shdr.sh_size = empty_sz;
|
|
|
|
name = strdup(".empty");
|
2017-01-13 13:30:54 +01:00
|
|
|
if (!name) {
|
|
|
|
ERROR("out of memory\n");
|
|
|
|
goto out;
|
|
|
|
}
|
2016-06-09 12:35:36 +02:00
|
|
|
if (elf_writer_add_section(ew, &shdr, &b, name)) {
|
|
|
|
ERROR("Unable to add ELF section: %s\n", name);
|
2017-01-13 13:30:54 +01:00
|
|
|
free(name);
|
2016-08-05 17:20:37 +02:00
|
|
|
goto out;
|
2016-06-09 12:35:36 +02:00
|
|
|
}
|
2017-01-13 13:30:54 +01:00
|
|
|
free(name);
|
2016-06-09 12:35:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (elf_writer_serialize(ew, &elf_out)) {
|
|
|
|
ERROR("Unable to create ELF file from stage.\n");
|
2016-08-05 17:20:37 +02:00
|
|
|
goto out;
|
2016-06-09 12:35:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Flip buffer with the created ELF one. */
|
|
|
|
buffer_delete(buff);
|
|
|
|
*buff = elf_out;
|
2016-08-05 17:20:37 +02:00
|
|
|
retval = 0;
|
2016-06-09 12:35:36 +02:00
|
|
|
|
2016-08-05 17:20:37 +02:00
|
|
|
out:
|
|
|
|
free(segs);
|
2016-06-09 12:35:36 +02:00
|
|
|
elf_writer_destroy(ew);
|
2016-08-05 17:20:37 +02:00
|
|
|
return retval;
|
2016-06-09 12:35:36 +02:00
|
|
|
}
|
|
|
|
|
2013-01-28 19:29:49 +01:00
|
|
|
int cbfs_export_entry(struct cbfs_image *image, const char *entry_name,
|
2018-08-09 11:49:52 +02:00
|
|
|
const char *filename, uint32_t arch, bool do_processing)
|
2013-03-26 20:51:36 +01:00
|
|
|
{
|
2013-01-28 19:29:49 +01:00
|
|
|
struct cbfs_file *entry = cbfs_get_entry(image, entry_name);
|
|
|
|
struct buffer buffer;
|
|
|
|
if (!entry) {
|
|
|
|
ERROR("File not found: %s\n", entry_name);
|
|
|
|
return -1;
|
|
|
|
}
|
2015-08-26 13:01:10 +02:00
|
|
|
|
2018-08-09 11:49:52 +02:00
|
|
|
unsigned int compressed_size = ntohl(entry->len);
|
2015-08-26 13:01:10 +02:00
|
|
|
unsigned int decompressed_size = 0;
|
|
|
|
unsigned int compression = cbfs_file_get_compression_info(entry,
|
|
|
|
&decompressed_size);
|
2018-11-21 13:07:50 +01:00
|
|
|
unsigned int buffer_len;
|
2018-08-09 11:49:52 +02:00
|
|
|
decomp_func_ptr decompress;
|
2015-08-26 13:01:10 +02:00
|
|
|
|
2018-08-09 11:49:52 +02:00
|
|
|
if (do_processing) {
|
|
|
|
decompress = decompression_function(compression);
|
|
|
|
if (!decompress) {
|
|
|
|
ERROR("looking up decompression routine failed\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2018-11-21 13:07:50 +01:00
|
|
|
buffer_len = decompressed_size;
|
2018-08-09 11:49:52 +02:00
|
|
|
} else {
|
|
|
|
/* Force nop decompression */
|
|
|
|
decompress = decompression_function(CBFS_COMPRESS_NONE);
|
2018-11-21 13:07:50 +01:00
|
|
|
buffer_len = compressed_size;
|
2015-08-26 13:01:10 +02:00
|
|
|
}
|
|
|
|
|
2018-08-09 11:49:52 +02:00
|
|
|
LOG("Found file %.30s at 0x%x, type %.12s, compressed %d, size %d\n",
|
2013-01-28 19:29:49 +01:00
|
|
|
entry_name, cbfs_get_entry_addr(image, entry),
|
2018-08-09 11:49:52 +02:00
|
|
|
get_cbfs_entry_type_name(ntohl(entry->type)), compressed_size,
|
|
|
|
decompressed_size);
|
2013-01-28 19:29:49 +01:00
|
|
|
|
2015-10-24 00:42:32 +02:00
|
|
|
buffer_init(&buffer, strdup("(cbfs_export_entry)"), NULL, 0);
|
2018-11-21 13:07:50 +01:00
|
|
|
buffer.data = malloc(buffer_len);
|
|
|
|
buffer.size = buffer_len;
|
2015-10-24 00:42:32 +02:00
|
|
|
|
2018-08-09 11:49:52 +02:00
|
|
|
if (decompress(CBFS_SUBHEADER(entry), compressed_size,
|
|
|
|
buffer.data, buffer.size, NULL)) {
|
2015-08-26 13:01:10 +02:00
|
|
|
ERROR("decompression failed for %s\n", entry_name);
|
2015-10-24 00:42:32 +02:00
|
|
|
buffer_delete(&buffer);
|
2015-08-26 13:01:10 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2015-10-24 00:42:32 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The stage metadata is never compressed proper for cbfs_stage
|
|
|
|
* files. The contents of the stage data can be though. Therefore
|
|
|
|
* one has to do a second pass for stages to potentially decompress
|
|
|
|
* the stage data to make it more meaningful.
|
|
|
|
*/
|
2018-08-09 11:49:52 +02:00
|
|
|
if (do_processing) {
|
|
|
|
int (*make_elf)(struct buffer *, uint32_t) = NULL;
|
|
|
|
switch (ntohl(entry->type)) {
|
|
|
|
case CBFS_COMPONENT_STAGE:
|
|
|
|
make_elf = cbfs_stage_make_elf;
|
|
|
|
break;
|
|
|
|
case CBFS_COMPONENT_SELF:
|
|
|
|
make_elf = cbfs_payload_make_elf;
|
|
|
|
break;
|
2015-10-24 00:42:32 +02:00
|
|
|
}
|
2018-08-09 11:49:52 +02:00
|
|
|
if (make_elf && make_elf(&buffer, arch)) {
|
|
|
|
ERROR("Failed to write %s into %s.\n",
|
|
|
|
entry_name, filename);
|
2016-06-09 12:35:36 +02:00
|
|
|
buffer_delete(&buffer);
|
|
|
|
return -1;
|
|
|
|
}
|
2015-10-24 00:42:32 +02:00
|
|
|
}
|
|
|
|
|
2013-01-28 19:29:49 +01:00
|
|
|
if (buffer_write_file(&buffer, filename) != 0) {
|
|
|
|
ERROR("Failed to write %s into %s.\n",
|
|
|
|
entry_name, filename);
|
2015-10-24 00:42:32 +02:00
|
|
|
buffer_delete(&buffer);
|
2013-01-28 19:29:49 +01:00
|
|
|
return -1;
|
|
|
|
}
|
2015-10-24 00:42:32 +02:00
|
|
|
|
|
|
|
buffer_delete(&buffer);
|
2013-01-28 19:29:49 +01:00
|
|
|
INFO("Successfully dumped the file to: %s\n", filename);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-26 20:51:36 +01:00
|
|
|
int cbfs_remove_entry(struct cbfs_image *image, const char *name)
|
|
|
|
{
|
2015-07-17 22:07:26 +02:00
|
|
|
struct cbfs_file *entry;
|
2013-01-28 19:38:40 +01:00
|
|
|
entry = cbfs_get_entry(image, name);
|
|
|
|
if (!entry) {
|
|
|
|
ERROR("CBFS file %s not found.\n", name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
DEBUG("cbfs_remove_entry: Removed %s @ 0x%x\n",
|
2015-07-15 16:42:38 +02:00
|
|
|
entry->filename, cbfs_get_entry_addr(image, entry));
|
2013-01-28 19:38:40 +01:00
|
|
|
entry->type = htonl(CBFS_COMPONENT_DELETED);
|
2015-07-17 22:07:26 +02:00
|
|
|
cbfs_walk(image, cbfs_merge_empty_entry, NULL);
|
2013-01-28 19:38:40 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-26 20:51:36 +01:00
|
|
|
int cbfs_print_header_info(struct cbfs_image *image)
|
|
|
|
{
|
2013-01-28 19:15:49 +01:00
|
|
|
char *name = strdup(image->buffer.name);
|
2015-05-06 00:40:15 +02:00
|
|
|
assert(image);
|
2013-01-28 19:15:49 +01:00
|
|
|
printf("%s: %zd kB, bootblocksize %d, romsize %d, offset 0x%x\n"
|
2013-11-13 23:34:57 +01:00
|
|
|
"alignment: %d bytes, architecture: %s\n\n",
|
2013-01-28 19:15:49 +01:00
|
|
|
basename(name),
|
|
|
|
image->buffer.size / 1024,
|
2015-05-06 00:40:15 +02:00
|
|
|
image->header.bootblocksize,
|
|
|
|
image->header.romsize,
|
|
|
|
image->header.offset,
|
|
|
|
image->header.align,
|
|
|
|
arch_to_string(image->header.architecture));
|
2013-01-28 19:15:49 +01:00
|
|
|
free(name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-26 20:51:36 +01:00
|
|
|
static int cbfs_print_stage_info(struct cbfs_stage *stage, FILE* fp)
|
|
|
|
{
|
2013-01-28 19:15:49 +01:00
|
|
|
fprintf(fp,
|
|
|
|
" %s compression, entry: 0x%" PRIx64 ", load: 0x%" PRIx64 ", "
|
|
|
|
"length: %d/%d\n",
|
|
|
|
lookup_name_by_type(types_cbfs_compression,
|
|
|
|
stage->compression, "(unknown)"),
|
|
|
|
stage->entry,
|
|
|
|
stage->load,
|
|
|
|
stage->len,
|
|
|
|
stage->memlen);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-05-16 04:14:05 +02:00
|
|
|
static int cbfs_print_decoded_payload_segment_info(
|
|
|
|
struct cbfs_payload_segment *seg, FILE *fp)
|
2013-01-28 19:15:49 +01:00
|
|
|
{
|
2014-05-16 04:14:05 +02:00
|
|
|
/* The input (seg) must be already decoded by
|
|
|
|
* cbfs_decode_payload_segment.
|
|
|
|
*/
|
|
|
|
switch (seg->type) {
|
2013-01-28 19:15:49 +01:00
|
|
|
case PAYLOAD_SEGMENT_CODE:
|
|
|
|
case PAYLOAD_SEGMENT_DATA:
|
|
|
|
fprintf(fp, " %s (%s compression, offset: 0x%x, "
|
|
|
|
"load: 0x%" PRIx64 ", length: %d/%d)\n",
|
2014-05-16 04:14:05 +02:00
|
|
|
(seg->type == PAYLOAD_SEGMENT_CODE ?
|
2013-01-28 19:15:49 +01:00
|
|
|
"code " : "data"),
|
|
|
|
lookup_name_by_type(types_cbfs_compression,
|
2014-05-16 04:14:05 +02:00
|
|
|
seg->compression,
|
2013-01-28 19:15:49 +01:00
|
|
|
"(unknown)"),
|
2014-05-16 04:14:05 +02:00
|
|
|
seg->offset, seg->load_addr, seg->len,
|
|
|
|
seg->mem_len);
|
2013-01-28 19:15:49 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PAYLOAD_SEGMENT_ENTRY:
|
|
|
|
fprintf(fp, " entry (0x%" PRIx64 ")\n",
|
2014-05-16 04:14:05 +02:00
|
|
|
seg->load_addr);
|
2013-01-28 19:15:49 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PAYLOAD_SEGMENT_BSS:
|
|
|
|
fprintf(fp, " BSS (address 0x%016" PRIx64 ", "
|
|
|
|
"length 0x%x)\n",
|
2014-05-16 04:14:05 +02:00
|
|
|
seg->load_addr, seg->len);
|
2013-01-28 19:15:49 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PAYLOAD_SEGMENT_PARAMS:
|
|
|
|
fprintf(fp, " parameters\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
fprintf(fp, " 0x%x (%s compression, offset: 0x%x, "
|
|
|
|
"load: 0x%" PRIx64 ", length: %d/%d\n",
|
2014-05-16 04:14:05 +02:00
|
|
|
seg->type,
|
2013-01-28 19:15:49 +01:00
|
|
|
lookup_name_by_type(types_cbfs_compression,
|
2014-05-16 04:14:05 +02:00
|
|
|
seg->compression,
|
2013-01-28 19:15:49 +01:00
|
|
|
"(unknown)"),
|
2014-05-16 04:14:05 +02:00
|
|
|
seg->offset, seg->load_addr, seg->len,
|
|
|
|
seg->mem_len);
|
2013-01-28 19:15:49 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cbfs_print_entry_info(struct cbfs_image *image, struct cbfs_file *entry,
|
2013-03-26 20:51:36 +01:00
|
|
|
void *arg)
|
|
|
|
{
|
2015-07-15 16:42:38 +02:00
|
|
|
const char *name = entry->filename;
|
2013-01-28 19:15:49 +01:00
|
|
|
struct cbfs_payload_segment *payload;
|
|
|
|
FILE *fp = (FILE *)arg;
|
|
|
|
|
2013-02-09 03:38:55 +01:00
|
|
|
if (!cbfs_is_valid_entry(image, entry)) {
|
2013-01-28 19:15:49 +01:00
|
|
|
ERROR("cbfs_print_entry_info: Invalid entry at 0x%x\n",
|
|
|
|
cbfs_get_entry_addr(image, entry));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!fp)
|
|
|
|
fp = stdout;
|
|
|
|
|
2015-08-26 12:13:03 +02:00
|
|
|
unsigned int decompressed_size = 0;
|
2015-08-26 12:23:26 +02:00
|
|
|
unsigned int compression = cbfs_file_get_compression_info(entry,
|
|
|
|
&decompressed_size);
|
2017-10-27 02:40:41 +02:00
|
|
|
const char *compression_name = lookup_name_by_type(
|
|
|
|
types_cbfs_compression, compression, "????");
|
2015-08-26 12:13:03 +02:00
|
|
|
|
2017-10-27 02:40:41 +02:00
|
|
|
if (compression == CBFS_COMPRESS_NONE)
|
|
|
|
fprintf(fp, "%-30s 0x%-8x %-12s %8d %-4s\n",
|
2015-08-26 12:13:03 +02:00
|
|
|
*name ? name : "(empty)",
|
|
|
|
cbfs_get_entry_addr(image, entry),
|
|
|
|
get_cbfs_entry_type_name(ntohl(entry->type)),
|
2017-10-27 02:40:41 +02:00
|
|
|
ntohl(entry->len),
|
|
|
|
compression_name
|
|
|
|
);
|
|
|
|
else
|
|
|
|
fprintf(fp, "%-30s 0x%-8x %-12s %8d %-4s (%d decompressed)\n",
|
2015-08-26 12:13:03 +02:00
|
|
|
*name ? name : "(empty)",
|
|
|
|
cbfs_get_entry_addr(image, entry),
|
|
|
|
get_cbfs_entry_type_name(ntohl(entry->type)),
|
|
|
|
ntohl(entry->len),
|
2017-10-27 02:40:41 +02:00
|
|
|
compression_name,
|
|
|
|
decompressed_size
|
2015-08-26 12:13:03 +02:00
|
|
|
);
|
2013-01-28 19:15:49 +01:00
|
|
|
|
2015-10-01 15:54:04 +02:00
|
|
|
struct cbfs_file_attr_hash *hash = NULL;
|
|
|
|
while ((hash = cbfs_file_get_next_hash(entry, hash)) != NULL) {
|
|
|
|
unsigned int hash_type = ntohl(hash->hash_type);
|
2016-12-02 18:24:50 +01:00
|
|
|
if (hash_type >= CBFS_NUM_SUPPORTED_HASHES) {
|
2015-10-01 15:54:04 +02:00
|
|
|
fprintf(fp, "invalid hash type %d\n", hash_type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
size_t hash_len = widths_cbfs_hash[hash_type];
|
|
|
|
char *hash_str = bintohex(hash->hash_data, hash_len);
|
|
|
|
uint8_t local_hash[hash_len];
|
|
|
|
if (vb2_digest_buffer(CBFS_SUBHEADER(entry),
|
|
|
|
ntohl(entry->len), hash_type, local_hash,
|
|
|
|
hash_len) != VB2_SUCCESS) {
|
|
|
|
fprintf(fp, "failed to hash '%s'\n", name);
|
2016-12-14 16:10:00 +01:00
|
|
|
free(hash_str);
|
2015-10-01 15:54:04 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
int valid = memcmp(local_hash, hash->hash_data, hash_len) == 0;
|
|
|
|
const char *valid_str = valid ? "valid" : "invalid";
|
|
|
|
|
|
|
|
fprintf(fp, " hash %s:%s %s\n",
|
|
|
|
get_hash_attr_name(hash_type),
|
|
|
|
hash_str, valid_str);
|
|
|
|
free(hash_str);
|
|
|
|
}
|
|
|
|
|
2013-01-28 19:15:49 +01:00
|
|
|
if (!verbose)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
DEBUG(" cbfs_file=0x%x, offset=0x%x, content_address=0x%x+0x%x\n",
|
|
|
|
cbfs_get_entry_addr(image, entry), ntohl(entry->offset),
|
|
|
|
cbfs_get_entry_addr(image, entry) + ntohl(entry->offset),
|
|
|
|
ntohl(entry->len));
|
|
|
|
|
|
|
|
/* note the components of the subheader may be in host order ... */
|
|
|
|
switch (ntohl(entry->type)) {
|
|
|
|
case CBFS_COMPONENT_STAGE:
|
|
|
|
cbfs_print_stage_info((struct cbfs_stage *)
|
|
|
|
CBFS_SUBHEADER(entry), fp);
|
|
|
|
break;
|
|
|
|
|
2018-05-02 09:44:08 +02:00
|
|
|
case CBFS_COMPONENT_SELF:
|
2015-08-08 20:20:57 +02:00
|
|
|
payload = (struct cbfs_payload_segment *)
|
2013-01-28 19:15:49 +01:00
|
|
|
CBFS_SUBHEADER(entry);
|
|
|
|
while (payload) {
|
2014-05-16 04:14:05 +02:00
|
|
|
struct cbfs_payload_segment seg;
|
|
|
|
cbfs_decode_payload_segment(&seg, payload);
|
|
|
|
cbfs_print_decoded_payload_segment_info(
|
|
|
|
&seg, fp);
|
|
|
|
if (seg.type == PAYLOAD_SEGMENT_ENTRY)
|
2013-01-28 19:15:49 +01:00
|
|
|
break;
|
2014-05-16 04:14:05 +02:00
|
|
|
else
|
2014-08-05 17:48:20 +02:00
|
|
|
payload ++;
|
2013-01-28 19:15:49 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-26 22:35:34 +01:00
|
|
|
static int cbfs_print_parseable_entry_info(struct cbfs_image *image,
|
|
|
|
struct cbfs_file *entry, void *arg)
|
|
|
|
{
|
|
|
|
FILE *fp = (FILE *)arg;
|
|
|
|
const char *name;
|
|
|
|
const char *type;
|
|
|
|
size_t offset;
|
|
|
|
size_t metadata_size;
|
|
|
|
size_t data_size;
|
|
|
|
const char *sep = "\t";
|
|
|
|
|
|
|
|
if (!cbfs_is_valid_entry(image, entry)) {
|
|
|
|
ERROR("cbfs_print_entry_info: Invalid entry at 0x%x\n",
|
|
|
|
cbfs_get_entry_addr(image, entry));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
name = entry->filename;
|
|
|
|
if (*name == '\0')
|
|
|
|
name = "(empty)";
|
|
|
|
type = get_cbfs_entry_type_name(ntohl(entry->type)),
|
|
|
|
metadata_size = ntohl(entry->offset);
|
|
|
|
data_size = ntohl(entry->len);
|
|
|
|
offset = cbfs_get_entry_addr(image, entry);
|
|
|
|
|
|
|
|
fprintf(fp, "%s%s", name, sep);
|
|
|
|
fprintf(fp, "0x%zx%s", offset, sep);
|
|
|
|
fprintf(fp, "%s%s", type, sep);
|
|
|
|
fprintf(fp, "0x%zx%s", metadata_size, sep);
|
|
|
|
fprintf(fp, "0x%zx%s", data_size, sep);
|
|
|
|
fprintf(fp, "0x%zx\n", metadata_size + data_size);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-26 20:51:36 +01:00
|
|
|
int cbfs_print_directory(struct cbfs_image *image)
|
|
|
|
{
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
if (cbfs_is_legacy_cbfs(image))
|
|
|
|
cbfs_print_header_info(image);
|
2017-10-27 02:40:41 +02:00
|
|
|
printf("%-30s %-10s %-12s Size Comp\n", "Name", "Offset", "Type");
|
2013-01-28 19:15:49 +01:00
|
|
|
cbfs_walk(image, cbfs_print_entry_info, NULL);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-26 22:35:34 +01:00
|
|
|
int cbfs_print_parseable_directory(struct cbfs_image *image)
|
|
|
|
{
|
2016-05-26 23:41:02 +02:00
|
|
|
size_t i;
|
2016-01-26 22:35:34 +01:00
|
|
|
const char *header[] = {
|
|
|
|
"Name",
|
|
|
|
"Offset",
|
|
|
|
"Type",
|
|
|
|
"Metadata Size",
|
|
|
|
"Data Size",
|
|
|
|
"Total Size",
|
|
|
|
};
|
|
|
|
const char *sep = "\t";
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(header) - 1; i++)
|
|
|
|
fprintf(stdout, "%s%s", header[i], sep);
|
|
|
|
fprintf(stdout, "%s\n", header[i]);
|
|
|
|
cbfs_walk(image, cbfs_print_parseable_entry_info, stdout);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-01-28 20:46:02 +01:00
|
|
|
int cbfs_merge_empty_entry(struct cbfs_image *image, struct cbfs_file *entry,
|
2015-03-06 00:38:03 +01:00
|
|
|
unused void *arg)
|
2013-03-26 20:51:36 +01:00
|
|
|
{
|
2013-01-28 20:46:02 +01:00
|
|
|
struct cbfs_file *next;
|
2018-10-02 21:59:58 +02:00
|
|
|
uint32_t next_addr = 0;
|
|
|
|
|
|
|
|
/* We don't return here even if this entry is already empty because we
|
|
|
|
want to merge the empty entries following after it. */
|
|
|
|
|
|
|
|
/* Loop until non-empty entry is found, starting from the current entry.
|
|
|
|
After the loop, next_addr points to the next non-empty entry. */
|
|
|
|
next = entry;
|
|
|
|
while (ntohl(next->type) == CBFS_COMPONENT_DELETED ||
|
|
|
|
ntohl(next->type) == CBFS_COMPONENT_NULL) {
|
|
|
|
next = cbfs_find_next_entry(image, next);
|
|
|
|
if (!next)
|
|
|
|
break;
|
|
|
|
next_addr = cbfs_get_entry_addr(image, next);
|
|
|
|
if (!cbfs_is_valid_entry(image, next))
|
|
|
|
/* 'next' could be the end of cbfs */
|
|
|
|
break;
|
2013-01-28 20:46:02 +01:00
|
|
|
}
|
|
|
|
|
2018-10-02 21:59:58 +02:00
|
|
|
if (!next_addr)
|
|
|
|
/* Nothing to empty */
|
|
|
|
return 0;
|
2013-01-28 20:46:02 +01:00
|
|
|
|
2018-10-02 21:59:58 +02:00
|
|
|
/* We can return here if we find only a single empty entry.
|
|
|
|
For simplicity, we just proceed (and make it empty again). */
|
2013-01-28 20:46:02 +01:00
|
|
|
|
2018-10-02 21:59:58 +02:00
|
|
|
/* We're creating one empty entry for combined empty spaces */
|
|
|
|
uint32_t addr = cbfs_get_entry_addr(image, entry);
|
|
|
|
size_t len = next_addr - addr - cbfs_calculate_file_header_size("");
|
|
|
|
DEBUG("join_empty_entry: [0x%x, 0x%x) len=%zu\n", addr, next_addr, len);
|
|
|
|
cbfs_create_empty_entry(entry, CBFS_COMPONENT_NULL, len, "");
|
2013-01-28 20:46:02 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-01-28 19:15:49 +01:00
|
|
|
int cbfs_walk(struct cbfs_image *image, cbfs_entry_callback callback,
|
2013-03-26 20:51:36 +01:00
|
|
|
void *arg)
|
|
|
|
{
|
2013-01-28 19:15:49 +01:00
|
|
|
int count = 0;
|
|
|
|
struct cbfs_file *entry;
|
|
|
|
for (entry = cbfs_find_first_entry(image);
|
2013-02-09 03:38:55 +01:00
|
|
|
entry && cbfs_is_valid_entry(image, entry);
|
2013-01-28 19:15:49 +01:00
|
|
|
entry = cbfs_find_next_entry(image, entry)) {
|
|
|
|
count ++;
|
|
|
|
if (callback(image, entry, arg) != 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2015-11-11 15:35:24 +01:00
|
|
|
static int cbfs_header_valid(struct cbfs_header *header)
|
cbfstool: allow user to explicitly specify header location
There potentially could be multiple CBFS instances present in the
firmware image. cbfstool should be able to operate on any of them, not
just the first one present.
To accomplish that, allow all CBFS commands to accept the -H parameter
(which specifies the exact CBFS header location in the image).
If this parameter is specified, the image is not searched for the CBFS
header, only the specified location is checked for validity, If the
location is valid, it is considered to be the CBFS header, if not -
the tool exits with an error status.
Note, that default behavior of the tool does not change.
BRANCH=storm
BUG=chrome-os-partner:34161, chromium:445938
TEST=run the following experiments:
- examined an image with three CBFS instances, was able to print all
of them.
- built a rambi coreboot image and tried the following (cbfstool output abbreviated):
$ ./util/cbfstool/cbfstool /build/rambi/firmware/coreboot.rom print
coreboot.rom: 8192 kB, bootblocksize 2448, romsize 8388608, offset 0x700000
alignment: 64 bytes, architecture: x86
Name Offset Type Size
cmos_layout.bin 0x700000 cmos_layout 1164
...
(empty) 0x7ec600 null 77848
$ \od -tx4 -Ax /build/rambi/firmware/coreboot.rom | tail -2
7ffff0 fff67de9 000000ff fff6dfe9 fffff650
800000
$ ./util/cbfstool/cbfstool /build/rambi/firmware/coreboot.rom print -H 0x7ff650
coreboot.rom: 8192 kB, bootblocksize 2448, romsize 8388608, offset 0x700000
alignment: 64 bytes, architecture: x86
Name Offset Type Size
cmos_layout.bin 0x700000 cmos_layout 1164
...
(empty) 0x7ec600 null 77848
$ ./util/cbfstool/cbfstool /build/rambi/firmware/coreboot.rom print -H 0x7ff654
E: /build/rambi/firmware/coreboot.rom does not have CBFS master header.
E: Could not load ROM image '/build/rambi/firmware/coreboot.rom'.
$
Change-Id: I64cbdc79096f3c7a113762b641305542af7bbd60
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 86b88222df6eed25bb176d653305e2e57e18b73a
Original-Change-Id: I486092e222c96c65868ae7d41a9e8976ffcc93c4
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/237485
Original-Reviewed-by: David Hendricks <dhendrix@chromium.org>
Original-Reviewed-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Reviewed-by: Stefan Reinauer <reinauer@google.com>
Reviewed-on: http://review.coreboot.org/9741
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2014-12-24 00:10:12 +01:00
|
|
|
{
|
|
|
|
if ((ntohl(header->magic) == CBFS_HEADER_MAGIC) &&
|
|
|
|
((ntohl(header->version) == CBFS_HEADER_VERSION1) ||
|
|
|
|
(ntohl(header->version) == CBFS_HEADER_VERSION2)) &&
|
|
|
|
(ntohl(header->offset) < ntohl(header->romsize)))
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct cbfs_header *cbfs_find_header(char *data, size_t size,
|
|
|
|
uint32_t forced_offset)
|
2013-03-26 20:51:36 +01:00
|
|
|
{
|
2013-01-28 18:56:17 +01:00
|
|
|
size_t offset;
|
|
|
|
int found = 0;
|
2014-11-10 22:14:24 +01:00
|
|
|
int32_t rel_offset;
|
2013-01-28 18:56:17 +01:00
|
|
|
struct cbfs_header *header, *result = NULL;
|
|
|
|
|
cbfstool: allow user to explicitly specify header location
There potentially could be multiple CBFS instances present in the
firmware image. cbfstool should be able to operate on any of them, not
just the first one present.
To accomplish that, allow all CBFS commands to accept the -H parameter
(which specifies the exact CBFS header location in the image).
If this parameter is specified, the image is not searched for the CBFS
header, only the specified location is checked for validity, If the
location is valid, it is considered to be the CBFS header, if not -
the tool exits with an error status.
Note, that default behavior of the tool does not change.
BRANCH=storm
BUG=chrome-os-partner:34161, chromium:445938
TEST=run the following experiments:
- examined an image with three CBFS instances, was able to print all
of them.
- built a rambi coreboot image and tried the following (cbfstool output abbreviated):
$ ./util/cbfstool/cbfstool /build/rambi/firmware/coreboot.rom print
coreboot.rom: 8192 kB, bootblocksize 2448, romsize 8388608, offset 0x700000
alignment: 64 bytes, architecture: x86
Name Offset Type Size
cmos_layout.bin 0x700000 cmos_layout 1164
...
(empty) 0x7ec600 null 77848
$ \od -tx4 -Ax /build/rambi/firmware/coreboot.rom | tail -2
7ffff0 fff67de9 000000ff fff6dfe9 fffff650
800000
$ ./util/cbfstool/cbfstool /build/rambi/firmware/coreboot.rom print -H 0x7ff650
coreboot.rom: 8192 kB, bootblocksize 2448, romsize 8388608, offset 0x700000
alignment: 64 bytes, architecture: x86
Name Offset Type Size
cmos_layout.bin 0x700000 cmos_layout 1164
...
(empty) 0x7ec600 null 77848
$ ./util/cbfstool/cbfstool /build/rambi/firmware/coreboot.rom print -H 0x7ff654
E: /build/rambi/firmware/coreboot.rom does not have CBFS master header.
E: Could not load ROM image '/build/rambi/firmware/coreboot.rom'.
$
Change-Id: I64cbdc79096f3c7a113762b641305542af7bbd60
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 86b88222df6eed25bb176d653305e2e57e18b73a
Original-Change-Id: I486092e222c96c65868ae7d41a9e8976ffcc93c4
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/237485
Original-Reviewed-by: David Hendricks <dhendrix@chromium.org>
Original-Reviewed-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Reviewed-by: Stefan Reinauer <reinauer@google.com>
Reviewed-on: http://review.coreboot.org/9741
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2014-12-24 00:10:12 +01:00
|
|
|
if (forced_offset < (size - sizeof(struct cbfs_header))) {
|
|
|
|
/* Check if the forced header is valid. */
|
|
|
|
header = (struct cbfs_header *)(data + forced_offset);
|
2015-11-11 15:35:24 +01:00
|
|
|
if (cbfs_header_valid(header))
|
cbfstool: allow user to explicitly specify header location
There potentially could be multiple CBFS instances present in the
firmware image. cbfstool should be able to operate on any of them, not
just the first one present.
To accomplish that, allow all CBFS commands to accept the -H parameter
(which specifies the exact CBFS header location in the image).
If this parameter is specified, the image is not searched for the CBFS
header, only the specified location is checked for validity, If the
location is valid, it is considered to be the CBFS header, if not -
the tool exits with an error status.
Note, that default behavior of the tool does not change.
BRANCH=storm
BUG=chrome-os-partner:34161, chromium:445938
TEST=run the following experiments:
- examined an image with three CBFS instances, was able to print all
of them.
- built a rambi coreboot image and tried the following (cbfstool output abbreviated):
$ ./util/cbfstool/cbfstool /build/rambi/firmware/coreboot.rom print
coreboot.rom: 8192 kB, bootblocksize 2448, romsize 8388608, offset 0x700000
alignment: 64 bytes, architecture: x86
Name Offset Type Size
cmos_layout.bin 0x700000 cmos_layout 1164
...
(empty) 0x7ec600 null 77848
$ \od -tx4 -Ax /build/rambi/firmware/coreboot.rom | tail -2
7ffff0 fff67de9 000000ff fff6dfe9 fffff650
800000
$ ./util/cbfstool/cbfstool /build/rambi/firmware/coreboot.rom print -H 0x7ff650
coreboot.rom: 8192 kB, bootblocksize 2448, romsize 8388608, offset 0x700000
alignment: 64 bytes, architecture: x86
Name Offset Type Size
cmos_layout.bin 0x700000 cmos_layout 1164
...
(empty) 0x7ec600 null 77848
$ ./util/cbfstool/cbfstool /build/rambi/firmware/coreboot.rom print -H 0x7ff654
E: /build/rambi/firmware/coreboot.rom does not have CBFS master header.
E: Could not load ROM image '/build/rambi/firmware/coreboot.rom'.
$
Change-Id: I64cbdc79096f3c7a113762b641305542af7bbd60
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 86b88222df6eed25bb176d653305e2e57e18b73a
Original-Change-Id: I486092e222c96c65868ae7d41a9e8976ffcc93c4
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/237485
Original-Reviewed-by: David Hendricks <dhendrix@chromium.org>
Original-Reviewed-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Reviewed-by: Stefan Reinauer <reinauer@google.com>
Reviewed-on: http://review.coreboot.org/9741
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2014-12-24 00:10:12 +01:00
|
|
|
return header;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-11-10 22:14:24 +01:00
|
|
|
// Try finding relative offset of master header at end of file first.
|
|
|
|
rel_offset = *(int32_t *)(data + size - sizeof(int32_t));
|
|
|
|
offset = size + rel_offset;
|
|
|
|
DEBUG("relative offset: %#zx(-%#zx), offset: %#zx\n",
|
|
|
|
(size_t)rel_offset, (size_t)-rel_offset, offset);
|
cbfstool: allow user to explicitly specify header location
There potentially could be multiple CBFS instances present in the
firmware image. cbfstool should be able to operate on any of them, not
just the first one present.
To accomplish that, allow all CBFS commands to accept the -H parameter
(which specifies the exact CBFS header location in the image).
If this parameter is specified, the image is not searched for the CBFS
header, only the specified location is checked for validity, If the
location is valid, it is considered to be the CBFS header, if not -
the tool exits with an error status.
Note, that default behavior of the tool does not change.
BRANCH=storm
BUG=chrome-os-partner:34161, chromium:445938
TEST=run the following experiments:
- examined an image with three CBFS instances, was able to print all
of them.
- built a rambi coreboot image and tried the following (cbfstool output abbreviated):
$ ./util/cbfstool/cbfstool /build/rambi/firmware/coreboot.rom print
coreboot.rom: 8192 kB, bootblocksize 2448, romsize 8388608, offset 0x700000
alignment: 64 bytes, architecture: x86
Name Offset Type Size
cmos_layout.bin 0x700000 cmos_layout 1164
...
(empty) 0x7ec600 null 77848
$ \od -tx4 -Ax /build/rambi/firmware/coreboot.rom | tail -2
7ffff0 fff67de9 000000ff fff6dfe9 fffff650
800000
$ ./util/cbfstool/cbfstool /build/rambi/firmware/coreboot.rom print -H 0x7ff650
coreboot.rom: 8192 kB, bootblocksize 2448, romsize 8388608, offset 0x700000
alignment: 64 bytes, architecture: x86
Name Offset Type Size
cmos_layout.bin 0x700000 cmos_layout 1164
...
(empty) 0x7ec600 null 77848
$ ./util/cbfstool/cbfstool /build/rambi/firmware/coreboot.rom print -H 0x7ff654
E: /build/rambi/firmware/coreboot.rom does not have CBFS master header.
E: Could not load ROM image '/build/rambi/firmware/coreboot.rom'.
$
Change-Id: I64cbdc79096f3c7a113762b641305542af7bbd60
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 86b88222df6eed25bb176d653305e2e57e18b73a
Original-Change-Id: I486092e222c96c65868ae7d41a9e8976ffcc93c4
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/237485
Original-Reviewed-by: David Hendricks <dhendrix@chromium.org>
Original-Reviewed-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Reviewed-by: Stefan Reinauer <reinauer@google.com>
Reviewed-on: http://review.coreboot.org/9741
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2014-12-24 00:10:12 +01:00
|
|
|
|
2013-01-28 18:56:17 +01:00
|
|
|
if (offset >= size - sizeof(*header) ||
|
2015-11-11 15:35:24 +01:00
|
|
|
!cbfs_header_valid((struct cbfs_header *)(data + offset))) {
|
2014-11-10 22:14:24 +01:00
|
|
|
// Some use cases append non-CBFS data to the end of the ROM.
|
|
|
|
DEBUG("relative offset seems wrong, scanning whole image...\n");
|
2013-01-28 18:56:17 +01:00
|
|
|
offset = 0;
|
2014-11-10 22:14:24 +01:00
|
|
|
}
|
2013-01-28 18:56:17 +01:00
|
|
|
|
|
|
|
for (; offset + sizeof(*header) < size; offset++) {
|
|
|
|
header = (struct cbfs_header *)(data + offset);
|
2015-11-11 15:35:24 +01:00
|
|
|
if (!cbfs_header_valid(header))
|
2013-01-28 18:56:17 +01:00
|
|
|
continue;
|
2014-11-10 22:14:24 +01:00
|
|
|
if (!found++)
|
|
|
|
result = header;
|
2013-01-28 18:56:17 +01:00
|
|
|
}
|
2014-11-10 22:14:24 +01:00
|
|
|
if (found > 1)
|
|
|
|
// Top-aligned images usually have a working relative offset
|
|
|
|
// field, so this is more likely to happen on bottom-aligned
|
|
|
|
// ones (where the first header is the "outermost" one)
|
|
|
|
WARN("Multiple (%d) CBFS headers found, using the first one.\n",
|
2013-01-28 18:56:17 +01:00
|
|
|
found);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-26 20:51:36 +01:00
|
|
|
struct cbfs_file *cbfs_find_first_entry(struct cbfs_image *image)
|
|
|
|
{
|
2015-05-06 00:40:15 +02:00
|
|
|
assert(image);
|
2015-11-11 15:35:24 +01:00
|
|
|
if (image->has_header)
|
|
|
|
/* header.offset is relative to start of flash, not
|
|
|
|
* start of region, so use it with the full image.
|
|
|
|
*/
|
|
|
|
return (struct cbfs_file *)
|
|
|
|
(buffer_get_original_backing(&image->buffer) +
|
|
|
|
image->header.offset);
|
|
|
|
else
|
|
|
|
return (struct cbfs_file *)buffer_get(&image->buffer);
|
2013-01-28 18:56:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
struct cbfs_file *cbfs_find_next_entry(struct cbfs_image *image,
|
2013-03-26 20:51:36 +01:00
|
|
|
struct cbfs_file *entry)
|
|
|
|
{
|
2013-01-28 18:56:17 +01:00
|
|
|
uint32_t addr = cbfs_get_entry_addr(image, entry);
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
int align = image->has_header ? image->header.align :
|
|
|
|
CBFS_ENTRY_ALIGNMENT;
|
2013-02-09 03:38:55 +01:00
|
|
|
assert(entry && cbfs_is_valid_entry(image, entry));
|
2013-01-28 18:56:17 +01:00
|
|
|
addr += ntohl(entry->offset) + ntohl(entry->len);
|
|
|
|
addr = align_up(addr, align);
|
|
|
|
return (struct cbfs_file *)(image->buffer.data + addr);
|
|
|
|
}
|
|
|
|
|
2013-03-26 20:51:36 +01:00
|
|
|
uint32_t cbfs_get_entry_addr(struct cbfs_image *image, struct cbfs_file *entry)
|
|
|
|
{
|
2013-01-28 18:56:17 +01:00
|
|
|
assert(image && image->buffer.data && entry);
|
|
|
|
return (int32_t)((char *)entry - image->buffer.data);
|
|
|
|
}
|
|
|
|
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
int cbfs_is_valid_cbfs(struct cbfs_image *image)
|
|
|
|
{
|
|
|
|
return buffer_check_magic(&image->buffer, CBFS_FILE_MAGIC,
|
|
|
|
strlen(CBFS_FILE_MAGIC));
|
|
|
|
}
|
|
|
|
|
|
|
|
int cbfs_is_legacy_cbfs(struct cbfs_image *image)
|
|
|
|
{
|
|
|
|
return image->has_header;
|
|
|
|
}
|
|
|
|
|
2013-03-26 20:51:36 +01:00
|
|
|
int cbfs_is_valid_entry(struct cbfs_image *image, struct cbfs_file *entry)
|
|
|
|
{
|
cbfstool: Restructure around support for reading/writing portions of files
The buffer API that cbfstool uses to read and write files only directly supports
one-shot operations on whole files. This adds an intermediate partitioned_file
module that sits on top of the buffer system and has an awareness of FMAP
entries. It provides an easy way to get a buffer for an individual region of a
larger image file based on FMAP section name, as well as incrementally write
those smaller buffers back to the backing file at the appropriate offset. The
module has two distinct modes of operation:
- For new images whose layout is described exclusively by an FMAP section, all
the aforementioned functionality will be available.
- For images in the current format, where the CBFS master header serves as the
root of knowledge of the image's size and layout, the module falls back to a
legacy operation mode, where it only allows manipulation of the entire image
as one unit, but exposes this support through the same interface by mapping
the region named SECTION_NAME_PRIMARY_CBFS ("COREBOOT") to the whole file.
The tool is presently only ported onto the new module running in legacy mode:
higher-level support for true "partitioned" images will be forthcoming. However,
as part of this change, the crusty cbfs_image_from_file() and
cbfs_image_write_file() abstractions are removed and replaced with a single
cbfs_image function, cbfs_image_from_buffer(), as well as centralized image
reading/writing directly in cbfstool's main() function. This reduces the
boilerplate required to implement each new action, makes the create action much
more similar to the others, and will make implementing additional actions and
adding in support for the new format much easier.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom images with and without this patch
and diff their hexdumps. Ensure that no differences occur at different locations
from the diffs between subsequent builds of an identical source tree. Then flash
a full new build onto nyan_big and watch it boot normally.
BRANCH=None
Change-Id: I25578c7b223bc8434c3074cb0dd8894534f8c500
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 7e1c96a48e7a27fc6b90289d35e6e169d5e7ad20
Original-Change-Id: Ia4a1a4c48df42b9ec2d6b9471b3a10eb7b24bb39
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265581
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10134
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
2015-03-25 21:40:08 +01:00
|
|
|
uint32_t offset = cbfs_get_entry_addr(image, entry);
|
|
|
|
|
|
|
|
if (offset >= image->buffer.size)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
struct buffer entry_data;
|
|
|
|
buffer_clone(&entry_data, &image->buffer);
|
|
|
|
buffer_seek(&entry_data, offset);
|
|
|
|
return buffer_check_magic(&entry_data, CBFS_FILE_MAGIC,
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
strlen(CBFS_FILE_MAGIC));
|
2013-01-28 18:56:17 +01:00
|
|
|
}
|
|
|
|
|
2015-08-12 09:20:11 +02:00
|
|
|
struct cbfs_file *cbfs_create_file_header(int type,
|
2014-12-24 00:59:57 +01:00
|
|
|
size_t len, const char *name)
|
2013-03-26 20:51:36 +01:00
|
|
|
{
|
2015-07-15 20:49:00 +02:00
|
|
|
struct cbfs_file *entry = malloc(MAX_CBFS_FILE_HEADER_BUFFER);
|
|
|
|
memset(entry, CBFS_CONTENT_DEFAULT_VALUE, MAX_CBFS_FILE_HEADER_BUFFER);
|
2013-01-28 20:46:02 +01:00
|
|
|
memcpy(entry->magic, CBFS_FILE_MAGIC, sizeof(entry->magic));
|
2015-08-12 09:12:06 +02:00
|
|
|
entry->type = htonl(type);
|
2013-01-28 20:46:02 +01:00
|
|
|
entry->len = htonl(len);
|
2015-07-15 18:28:23 +02:00
|
|
|
entry->attributes_offset = 0;
|
2013-01-28 20:46:02 +01:00
|
|
|
entry->offset = htonl(cbfs_calculate_file_header_size(name));
|
2015-07-15 16:42:38 +02:00
|
|
|
memset(entry->filename, 0, ntohl(entry->offset) - sizeof(*entry));
|
|
|
|
strcpy(entry->filename, name);
|
2015-08-12 09:20:11 +02:00
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cbfs_create_empty_entry(struct cbfs_file *entry, int type,
|
|
|
|
size_t len, const char *name)
|
|
|
|
{
|
|
|
|
struct cbfs_file *tmp = cbfs_create_file_header(type, len, name);
|
|
|
|
memcpy(entry, tmp, ntohl(tmp->offset));
|
|
|
|
free(tmp);
|
2013-01-28 20:46:02 +01:00
|
|
|
memset(CBFS_SUBHEADER(entry), CBFS_CONTENT_DEFAULT_VALUE, len);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-15 20:49:00 +02:00
|
|
|
struct cbfs_file_attribute *cbfs_file_first_attr(struct cbfs_file *file)
|
|
|
|
{
|
|
|
|
/* attributes_offset should be 0 when there is no attribute, but all
|
|
|
|
* values that point into the cbfs_file header are invalid, too. */
|
|
|
|
if (ntohl(file->attributes_offset) <= sizeof(*file))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* There needs to be enough space for the file header and one
|
|
|
|
* attribute header for this to make sense. */
|
|
|
|
if (ntohl(file->offset) <=
|
|
|
|
sizeof(*file) + sizeof(struct cbfs_file_attribute))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return (struct cbfs_file_attribute *)
|
|
|
|
(((uint8_t *)file) + ntohl(file->attributes_offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
struct cbfs_file_attribute *cbfs_file_next_attr(struct cbfs_file *file,
|
|
|
|
struct cbfs_file_attribute *attr)
|
|
|
|
{
|
|
|
|
/* ex falso sequitur quodlibet */
|
|
|
|
if (attr == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Is there enough space for another attribute? */
|
|
|
|
if ((uint8_t *)attr + ntohl(attr->len) +
|
2019-02-14 11:19:07 +01:00
|
|
|
sizeof(struct cbfs_file_attribute) >
|
2015-07-15 20:49:00 +02:00
|
|
|
(uint8_t *)file + ntohl(file->offset))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
struct cbfs_file_attribute *next = (struct cbfs_file_attribute *)
|
|
|
|
(((uint8_t *)attr) + ntohl(attr->len));
|
|
|
|
/* If any, "unused" attributes must come last. */
|
|
|
|
if (ntohl(next->tag) == CBFS_FILE_ATTR_TAG_UNUSED)
|
|
|
|
return NULL;
|
|
|
|
if (ntohl(next->tag) == CBFS_FILE_ATTR_TAG_UNUSED2)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return next;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct cbfs_file_attribute *cbfs_add_file_attr(struct cbfs_file *header,
|
|
|
|
uint32_t tag,
|
|
|
|
uint32_t size)
|
|
|
|
{
|
|
|
|
struct cbfs_file_attribute *attr, *next;
|
|
|
|
next = cbfs_file_first_attr(header);
|
|
|
|
do {
|
|
|
|
attr = next;
|
|
|
|
next = cbfs_file_next_attr(header, attr);
|
|
|
|
} while (next != NULL);
|
|
|
|
uint32_t header_size = ntohl(header->offset) + size;
|
|
|
|
if (header_size > MAX_CBFS_FILE_HEADER_BUFFER) {
|
|
|
|
DEBUG("exceeding allocated space for cbfs_file headers");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* attr points to the last valid attribute now.
|
|
|
|
* If NULL, we have to create the first one. */
|
|
|
|
if (attr == NULL) {
|
|
|
|
/* New attributes start where the header ends.
|
2018-08-23 18:08:20 +02:00
|
|
|
* header->offset is later set to accommodate the
|
2015-07-15 20:49:00 +02:00
|
|
|
* additional structure.
|
2018-08-23 18:08:20 +02:00
|
|
|
* No endianness translation necessary here, because both
|
2015-07-15 20:49:00 +02:00
|
|
|
* fields are encoded the same way. */
|
|
|
|
header->attributes_offset = header->offset;
|
|
|
|
attr = (struct cbfs_file_attribute *)
|
|
|
|
(((uint8_t *)header) +
|
|
|
|
ntohl(header->attributes_offset));
|
|
|
|
} else {
|
|
|
|
attr = (struct cbfs_file_attribute *)
|
|
|
|
(((uint8_t *)attr) +
|
|
|
|
ntohl(attr->len));
|
|
|
|
}
|
|
|
|
header->offset = htonl(header_size);
|
|
|
|
memset(attr, CBFS_CONTENT_DEFAULT_VALUE, size);
|
|
|
|
attr->tag = htonl(tag);
|
|
|
|
attr->len = htonl(size);
|
|
|
|
return attr;
|
|
|
|
}
|
|
|
|
|
2015-10-01 15:54:04 +02:00
|
|
|
int cbfs_add_file_hash(struct cbfs_file *header, struct buffer *buffer,
|
|
|
|
enum vb2_hash_algorithm hash_type)
|
|
|
|
{
|
2015-11-05 07:35:57 +01:00
|
|
|
uint32_t hash_index = hash_type;
|
|
|
|
|
|
|
|
if (hash_index >= CBFS_NUM_SUPPORTED_HASHES)
|
2015-10-01 15:54:04 +02:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
unsigned hash_size = widths_cbfs_hash[hash_type];
|
|
|
|
if (hash_size == 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
struct cbfs_file_attr_hash *attrs =
|
|
|
|
(struct cbfs_file_attr_hash *)cbfs_add_file_attr(header,
|
|
|
|
CBFS_FILE_ATTR_TAG_HASH,
|
|
|
|
sizeof(struct cbfs_file_attr_hash) + hash_size);
|
|
|
|
|
|
|
|
if (attrs == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
attrs->hash_type = htonl(hash_type);
|
|
|
|
if (vb2_digest_buffer(buffer_get(buffer), buffer_size(buffer),
|
|
|
|
hash_type, attrs->hash_data, hash_size) != VB2_SUCCESS)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-26 20:51:36 +01:00
|
|
|
/* Finds a place to hold whole data in same memory page. */
|
|
|
|
static int is_in_same_page(uint32_t start, uint32_t size, uint32_t page)
|
|
|
|
{
|
2013-01-28 20:46:02 +01:00
|
|
|
if (!page)
|
|
|
|
return 1;
|
|
|
|
return (start / page) == (start + size - 1) / page;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:24:43 +01:00
|
|
|
/* Tests if data can fit in a range by given offset:
|
2015-09-15 19:50:14 +02:00
|
|
|
* start ->| metadata_size | offset (+ size) |<- end
|
2013-03-19 05:24:43 +01:00
|
|
|
*/
|
2015-09-15 19:50:14 +02:00
|
|
|
static int is_in_range(size_t start, size_t end, size_t metadata_size,
|
|
|
|
size_t offset, size_t size)
|
2013-03-26 20:51:36 +01:00
|
|
|
{
|
2015-09-15 19:50:14 +02:00
|
|
|
return (offset >= start + metadata_size && offset + size <= end);
|
2013-03-19 05:24:43 +01:00
|
|
|
}
|
|
|
|
|
2016-01-25 12:47:20 +01:00
|
|
|
static size_t absolute_align(const struct cbfs_image *image, size_t val,
|
|
|
|
size_t align)
|
|
|
|
{
|
|
|
|
const size_t region_offset = buffer_offset(&image->buffer);
|
|
|
|
/* To perform alignment on absolute address, take the region offset */
|
|
|
|
/* of the image into account. */
|
|
|
|
return align_up(val + region_offset, align) - region_offset;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-09-15 19:50:14 +02:00
|
|
|
int32_t cbfs_locate_entry(struct cbfs_image *image, size_t size,
|
|
|
|
size_t page_size, size_t align, size_t metadata_size)
|
2013-03-26 20:51:36 +01:00
|
|
|
{
|
2013-01-28 20:46:02 +01:00
|
|
|
struct cbfs_file *entry;
|
|
|
|
size_t need_len;
|
2015-09-15 19:50:14 +02:00
|
|
|
size_t addr, addr_next, addr2, addr3, offset;
|
2013-03-19 05:24:43 +01:00
|
|
|
|
|
|
|
/* Default values: allow fitting anywhere in ROM. */
|
|
|
|
if (!page_size)
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
page_size = image->has_header ? image->header.romsize :
|
|
|
|
image->buffer.size;
|
2013-03-19 05:24:43 +01:00
|
|
|
if (!align)
|
|
|
|
align = 1;
|
|
|
|
|
|
|
|
if (size > page_size)
|
2015-09-15 19:50:14 +02:00
|
|
|
ERROR("Input file size (%zd) greater than page size (%zd).\n",
|
2013-03-19 05:24:43 +01:00
|
|
|
size, page_size);
|
2013-01-28 20:46:02 +01:00
|
|
|
|
2015-09-15 19:50:14 +02:00
|
|
|
size_t image_align = image->has_header ? image->header.align :
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
CBFS_ENTRY_ALIGNMENT;
|
|
|
|
if (page_size % image_align)
|
2015-09-15 19:50:14 +02:00
|
|
|
WARN("%s: Page size (%#zx) not aligned with CBFS image (%#zx).\n",
|
cbfstool: New image format w/ required FMAP and w/o CBFS master header
These new-style firmware images use the FMAP of the root of knowledge
about their layout, which allows them to have sections containing raw
data whose offset and size can easily be determined at runtime or when
modifying or flashing the image. Furthermore, they can even have
multiple CBFSes, each of which occupies a different FMAP region. It is
assumed that the first entry of each CBFS, including the primary one,
will be located right at the start of its region. This means that the
bootblock needs to be moved into its own FMAP region, but makes the
CBFS master header obsolete because, with the exception of the version
and alignment, all its fields are redundant once its CBFS has an entry
in the FMAP. The version code will be addressed in a future commit
before the new format comes into use, while the alignment will just be
defined to 64 bytes in both cbfstool and coreboot itself, since
there's almost no reason to ever change it in practice. The version
code field and all necessary coreboot changes will come separately.
BUG=chromium:470407
TEST=Build panther and nyan_big coreboot.rom and image.bin images with
and without this patch, diff their hexdumps, and note that no
locations differ except for those that do between subsequent builds of
the same codebase. Try working with new-style images: use fmaptool to
produce an FMAP section from an fmd file having raw sections and
multiple CBFSes, pass the resulting file to cbfstool create -M -F,
then try printing its layout and CBFSes' contents, add and remove CBFS
files, and read and write raw sections.
BRANCH=None
Change-Id: I7dd2578d2143d0cedd652fdba5b22221fcc2184a
Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Commit-Id: 8a670322297f83135b929a5b20ff2bd0e7d2abd3
Original-Change-Id: Ib86fb50edc66632f4e6f717909bbe4efb6c874e5
Original-Signed-off-by: Sol Boucher <solb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/265863
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10135
Tested-by: build bot (Jenkins)
2015-03-18 20:36:27 +01:00
|
|
|
__func__, page_size, image_align);
|
2013-01-28 20:46:02 +01:00
|
|
|
|
2015-09-15 19:50:14 +02:00
|
|
|
need_len = metadata_size + size;
|
2013-01-28 20:46:02 +01:00
|
|
|
|
2013-03-19 05:24:43 +01:00
|
|
|
// Merge empty entries to build get max available space.
|
2013-01-28 20:46:02 +01:00
|
|
|
cbfs_walk(image, cbfs_merge_empty_entry, NULL);
|
|
|
|
|
|
|
|
/* Three cases of content location on memory page:
|
|
|
|
* case 1.
|
|
|
|
* | PAGE 1 | PAGE 2 |
|
|
|
|
* | <header><content>| Fit. Return start of content.
|
|
|
|
*
|
|
|
|
* case 2.
|
|
|
|
* | PAGE 1 | PAGE 2 |
|
|
|
|
* | <header><content> | Fits when we shift content to align
|
|
|
|
* shift-> | <header>|<content> | at starting of PAGE 2.
|
|
|
|
*
|
|
|
|
* case 3. (large content filling whole page)
|
2013-03-19 05:24:43 +01:00
|
|
|
* | PAGE 1 | PAGE 2 | PAGE 3 |
|
|
|
|
* | <header>< content > | Can't fit. If we shift content to
|
|
|
|
* |trial-> <header>< content > | PAGE 2, header can't fit in free
|
|
|
|
* | shift-> <header><content> space, so we must use PAGE 3.
|
2013-01-28 20:46:02 +01:00
|
|
|
*
|
2013-03-19 05:24:43 +01:00
|
|
|
* The returned address can be then used as "base-address" (-b) in add-*
|
|
|
|
* commands (will be re-calculated and positioned by cbfs_add_entry_at).
|
|
|
|
* For stage targets, the address is also used to re-link stage before
|
|
|
|
* being added into CBFS.
|
2013-01-28 20:46:02 +01:00
|
|
|
*/
|
|
|
|
for (entry = cbfs_find_first_entry(image);
|
2013-02-09 03:38:55 +01:00
|
|
|
entry && cbfs_is_valid_entry(image, entry);
|
2013-01-28 20:46:02 +01:00
|
|
|
entry = cbfs_find_next_entry(image, entry)) {
|
|
|
|
|
|
|
|
uint32_t type = ntohl(entry->type);
|
|
|
|
if (type != CBFS_COMPONENT_NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
addr = cbfs_get_entry_addr(image, entry);
|
|
|
|
addr_next = cbfs_get_entry_addr(image, cbfs_find_next_entry(
|
|
|
|
image, entry));
|
|
|
|
if (addr_next - addr < need_len)
|
|
|
|
continue;
|
2013-03-19 05:24:43 +01:00
|
|
|
|
2016-01-25 12:47:20 +01:00
|
|
|
offset = absolute_align(image, addr + metadata_size, align);
|
2013-03-19 05:24:43 +01:00
|
|
|
if (is_in_same_page(offset, size, page_size) &&
|
2015-09-15 19:50:14 +02:00
|
|
|
is_in_range(addr, addr_next, metadata_size, offset, size)) {
|
2013-01-28 20:46:02 +01:00
|
|
|
DEBUG("cbfs_locate_entry: FIT (PAGE1).");
|
2013-03-19 05:24:43 +01:00
|
|
|
return offset;
|
2013-01-28 20:46:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
addr2 = align_up(addr, page_size);
|
2016-01-25 12:47:20 +01:00
|
|
|
offset = absolute_align(image, addr2, align);
|
2015-09-15 19:50:14 +02:00
|
|
|
if (is_in_range(addr, addr_next, metadata_size, offset, size)) {
|
2013-01-28 20:46:02 +01:00
|
|
|
DEBUG("cbfs_locate_entry: OVERLAP (PAGE2).");
|
2013-03-19 05:24:43 +01:00
|
|
|
return offset;
|
2013-01-28 20:46:02 +01:00
|
|
|
}
|
|
|
|
|
2015-09-15 19:50:14 +02:00
|
|
|
/* Assume page_size >= metadata_size so adding one page will
|
2013-03-19 05:24:43 +01:00
|
|
|
* definitely provide the space for header. */
|
2015-09-15 19:50:14 +02:00
|
|
|
assert(page_size >= metadata_size);
|
2013-01-28 20:46:02 +01:00
|
|
|
addr3 = addr2 + page_size;
|
2016-01-25 12:47:20 +01:00
|
|
|
offset = absolute_align(image, addr3, align);
|
2015-09-15 19:50:14 +02:00
|
|
|
if (is_in_range(addr, addr_next, metadata_size, offset, size)) {
|
2013-01-28 20:46:02 +01:00
|
|
|
DEBUG("cbfs_locate_entry: OVERLAP+ (PAGE3).");
|
2013-03-19 05:24:43 +01:00
|
|
|
return offset;
|
2013-01-28 20:46:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|