mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-21 14:41:31 +00:00
Merge git://git.denx.de/u-boot-dm
This commit is contained in:
commit
a30691a538
98 changed files with 3014 additions and 350 deletions
|
@ -8,7 +8,7 @@
|
|||
filename = "spl/sunxi-spl.bin";
|
||||
};
|
||||
u-boot-img {
|
||||
pos = <CONFIG_SPL_PAD_TO>;
|
||||
offset = <CONFIG_SPL_PAD_TO>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
u-boot-spl {
|
||||
};
|
||||
u-boot {
|
||||
pos = <(U_BOOT_OFFSET)>;
|
||||
offset = <(U_BOOT_OFFSET)>;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
|||
u-boot-spl {
|
||||
};
|
||||
u-boot {
|
||||
pos = <(U_BOOT_OFFSET)>;
|
||||
offset = <(U_BOOT_OFFSET)>;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -36,7 +36,7 @@
|
|||
u-boot-spl {
|
||||
};
|
||||
u-boot-nodtb {
|
||||
pos = <(U_BOOT_OFFSET)>;
|
||||
offset = <(U_BOOT_OFFSET)>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
binman {
|
||||
filename = "u-boot.rom";
|
||||
end-at-4gb;
|
||||
sort-by-pos;
|
||||
sort-by-offset;
|
||||
pad-byte = <0xff>;
|
||||
size = <CONFIG_ROM_SIZE>;
|
||||
#ifdef CONFIG_HAVE_INTEL_ME
|
||||
|
@ -24,18 +24,18 @@
|
|||
#endif
|
||||
#ifdef CONFIG_SPL
|
||||
u-boot-spl-with-ucode-ptr {
|
||||
pos = <CONFIG_SPL_TEXT_BASE>;
|
||||
offset = <CONFIG_SPL_TEXT_BASE>;
|
||||
};
|
||||
|
||||
u-boot-dtb-with-ucode2 {
|
||||
type = "u-boot-dtb-with-ucode";
|
||||
};
|
||||
u-boot {
|
||||
pos = <0xfff00000>;
|
||||
offset = <0xfff00000>;
|
||||
};
|
||||
#else
|
||||
u-boot-with-ucode-ptr {
|
||||
pos = <CONFIG_SYS_TEXT_BASE>;
|
||||
offset = <CONFIG_SYS_TEXT_BASE>;
|
||||
};
|
||||
#endif
|
||||
u-boot-dtb-with-ucode {
|
||||
|
@ -45,45 +45,45 @@
|
|||
};
|
||||
#ifdef CONFIG_HAVE_MRC
|
||||
intel-mrc {
|
||||
pos = <CONFIG_X86_MRC_ADDR>;
|
||||
offset = <CONFIG_X86_MRC_ADDR>;
|
||||
};
|
||||
#endif
|
||||
#ifdef CONFIG_HAVE_FSP
|
||||
intel-fsp {
|
||||
filename = CONFIG_FSP_FILE;
|
||||
pos = <CONFIG_FSP_ADDR>;
|
||||
offset = <CONFIG_FSP_ADDR>;
|
||||
};
|
||||
#endif
|
||||
#ifdef CONFIG_HAVE_CMC
|
||||
intel-cmc {
|
||||
filename = CONFIG_CMC_FILE;
|
||||
pos = <CONFIG_CMC_ADDR>;
|
||||
offset = <CONFIG_CMC_ADDR>;
|
||||
};
|
||||
#endif
|
||||
#ifdef CONFIG_HAVE_VGA_BIOS
|
||||
intel-vga {
|
||||
filename = CONFIG_VGA_BIOS_FILE;
|
||||
pos = <CONFIG_VGA_BIOS_ADDR>;
|
||||
offset = <CONFIG_VGA_BIOS_ADDR>;
|
||||
};
|
||||
#endif
|
||||
#ifdef CONFIG_HAVE_VBT
|
||||
intel-vbt {
|
||||
filename = CONFIG_VBT_FILE;
|
||||
pos = <CONFIG_VBT_ADDR>;
|
||||
offset = <CONFIG_VBT_ADDR>;
|
||||
};
|
||||
#endif
|
||||
#ifdef CONFIG_HAVE_REFCODE
|
||||
intel-refcode {
|
||||
pos = <CONFIG_X86_REFCODE_ADDR>;
|
||||
offset = <CONFIG_X86_REFCODE_ADDR>;
|
||||
};
|
||||
#endif
|
||||
#ifdef CONFIG_SPL
|
||||
x86-start16-spl {
|
||||
pos = <CONFIG_SYS_X86_START16>;
|
||||
offset = <CONFIG_SYS_X86_START16>;
|
||||
};
|
||||
#else
|
||||
x86-start16 {
|
||||
pos = <CONFIG_SYS_X86_START16>;
|
||||
offset = <CONFIG_SYS_X86_START16>;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -34,7 +34,7 @@ DECLARE_GLOBAL_DATA_PTR;
|
|||
u32 *boot_params_ptr = NULL;
|
||||
|
||||
/* See spl.h for information about this */
|
||||
binman_sym_declare(ulong, u_boot_any, pos);
|
||||
binman_sym_declare(ulong, u_boot_any, image_pos);
|
||||
|
||||
/* Define board data structure */
|
||||
static bd_t bdata __attribute__ ((section(".data")));
|
||||
|
@ -129,7 +129,7 @@ __weak void spl_board_prepare_for_boot(void)
|
|||
|
||||
void spl_set_header_raw_uboot(struct spl_image_info *spl_image)
|
||||
{
|
||||
ulong u_boot_pos = binman_sym(ulong, u_boot_any, pos);
|
||||
ulong u_boot_pos = binman_sym(ulong, u_boot_any, image_pos);
|
||||
|
||||
spl_image->size = CONFIG_SYS_MONITOR_LEN;
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ static int spl_ram_load_image(struct spl_image_info *spl_image,
|
|||
load.read = spl_ram_load_read;
|
||||
spl_load_simple_fit(spl_image, &load, 0, header);
|
||||
} else {
|
||||
ulong u_boot_pos = binman_sym(ulong, u_boot_any, pos);
|
||||
ulong u_boot_pos = binman_sym(ulong, u_boot_any, image_pos);
|
||||
|
||||
debug("Legacy image\n");
|
||||
/*
|
||||
|
|
|
@ -60,7 +60,7 @@ struct spl_load_info {
|
|||
* image is found. For * example if u-boot.img is used we don't check that
|
||||
* spl_parse_image_header() can parse a valid header.
|
||||
*/
|
||||
binman_sym_extern(ulong, u_boot_any, pos);
|
||||
binman_sym_extern(ulong, u_boot_any, image_pos);
|
||||
|
||||
/**
|
||||
* spl_load_simple_fit() - Loads a fit image from a device.
|
||||
|
|
|
@ -238,7 +238,7 @@ below:
|
|||
filename = "spl/sunxi-spl.bin";
|
||||
};
|
||||
u-boot {
|
||||
pos = <CONFIG_SPL_PAD_TO>;
|
||||
offset = <CONFIG_SPL_PAD_TO>;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -257,7 +257,7 @@ provide a filename. For 'u-boot', binman knows that this means 'u-boot.bin'.
|
|||
|
||||
Entries are normally placed into the image sequentially, one after the other.
|
||||
The image size is the total size of all entries. As you can see, you can
|
||||
specify the start position of an entry using the 'pos' property.
|
||||
specify the start offset of an entry using the 'offset' property.
|
||||
|
||||
Note that due to a device tree requirement, all entries must have a unique
|
||||
name. If you want to put the same binary in the image multiple times, you can
|
||||
|
@ -265,14 +265,15 @@ use any unique name, with the 'type' property providing the type.
|
|||
|
||||
The attributes supported for entries are described below.
|
||||
|
||||
pos:
|
||||
This sets the position of an entry within the image. The first byte
|
||||
of the image is normally at position 0. If 'pos' is not provided,
|
||||
binman sets it to the end of the previous region, or the start of
|
||||
the image's entry area (normally 0) if there is no previous region.
|
||||
offset:
|
||||
This sets the offset of an entry within the image or section containing
|
||||
it. The first byte of the image is normally at offset 0. If 'offset' is
|
||||
not provided, binman sets it to the end of the previous region, or the
|
||||
start of the image's entry area (normally 0) if there is no previous
|
||||
region.
|
||||
|
||||
align:
|
||||
This sets the alignment of the entry. The entry position is adjusted
|
||||
This sets the alignment of the entry. The entry offset is adjusted
|
||||
so that the entry starts on an aligned boundary within the image. For
|
||||
example 'align = <16>' means that the entry will start on a 16-byte
|
||||
boundary. Alignment shold be a power of 2. If 'align' is not
|
||||
|
@ -316,12 +317,18 @@ type:
|
|||
possible to use any name, and then add (for example) 'type = "u-boot"'
|
||||
to specify the type.
|
||||
|
||||
pos-unset:
|
||||
Indicates that the position of this entry should not be set by placing
|
||||
offset-unset:
|
||||
Indicates that the offset of this entry should not be set by placing
|
||||
it immediately after the entry before. Instead, is set by another
|
||||
entry which knows where this entry should go. When this boolean
|
||||
property is present, binman will give an error if another entry does
|
||||
not set the position (with the GetPositions() method).
|
||||
not set the offset (with the GetOffsets() method).
|
||||
|
||||
image-pos:
|
||||
This cannot be set on entry (or at least it is ignored if it is), but
|
||||
with the -u option, binman will set it to the absolute image position
|
||||
for each entry. This makes it easy to find out exactly where the entry
|
||||
ended up in the image, regardless of parent sections, etc.
|
||||
|
||||
|
||||
The attributes supported for images are described below. Several are similar
|
||||
|
@ -338,7 +345,7 @@ align-size:
|
|||
|
||||
pad-before:
|
||||
This sets the padding before the image entries. The first entry will
|
||||
be positionad after the padding. This defaults to 0.
|
||||
be positioned after the padding. This defaults to 0.
|
||||
|
||||
pad-after:
|
||||
This sets the padding after the image entries. The padding will be
|
||||
|
@ -351,15 +358,15 @@ pad-byte:
|
|||
filename:
|
||||
This specifies the image filename. It defaults to 'image.bin'.
|
||||
|
||||
sort-by-pos:
|
||||
sort-by-offset:
|
||||
This causes binman to reorder the entries as needed to make sure they
|
||||
are in increasing positional order. This can be used when your entry
|
||||
order may not match the positional order. A common situation is where
|
||||
the 'pos' properties are set by CONFIG options, so their ordering is
|
||||
the 'offset' properties are set by CONFIG options, so their ordering is
|
||||
not known a priori.
|
||||
|
||||
This is a boolean property so needs no value. To enable it, add a
|
||||
line 'sort-by-pos;' to your description.
|
||||
line 'sort-by-offset;' to your description.
|
||||
|
||||
multiple-images:
|
||||
Normally only a single image is generated. To create more than one
|
||||
|
@ -383,11 +390,11 @@ multiple-images:
|
|||
};
|
||||
|
||||
end-at-4gb:
|
||||
For x86 machines the ROM positions start just before 4GB and extend
|
||||
For x86 machines the ROM offsets start just before 4GB and extend
|
||||
up so that the image finished at the 4GB boundary. This boolean
|
||||
option can be enabled to support this. The image size must be
|
||||
provided so that binman knows when the image should start. For an
|
||||
8MB ROM, the position of the first entry would be 0xfff80000 with
|
||||
8MB ROM, the offset of the first entry would be 0xfff80000 with
|
||||
this option, instead of 0 without this option.
|
||||
|
||||
|
||||
|
@ -446,6 +453,15 @@ name-prefix:
|
|||
distinguish binaries with otherwise identical names.
|
||||
|
||||
|
||||
Entry Documentation
|
||||
-------------------
|
||||
|
||||
For details on the various entry types supported by binman and how to use them,
|
||||
see README.entries. This is generated from the source code using:
|
||||
|
||||
binman -E >tools/binman/README.entries
|
||||
|
||||
|
||||
Special properties
|
||||
------------------
|
||||
|
||||
|
@ -463,7 +479,7 @@ Order of image creation
|
|||
Image creation proceeds in the following order, for each entry in the image.
|
||||
|
||||
1. AddMissingProperties() - binman can add calculated values to the device
|
||||
tree as part of its processing, for example the position and size of each
|
||||
tree as part of its processing, for example the offset and size of each
|
||||
entry. This method adds any properties associated with this, expanding the
|
||||
device tree as needed. These properties can have placeholder values which are
|
||||
set later by SetCalculatedProperties(). By that stage the size of sections
|
||||
|
@ -486,15 +502,15 @@ functions must return True when they have read the contents. Binman will
|
|||
retry calling the functions a few times if False is returned, allowing
|
||||
dependencies between the contents of different entries.
|
||||
|
||||
4. GetEntryPositions() - calls Entry.GetPositions() for each entry. This can
|
||||
4. GetEntryOffsets() - calls Entry.GetOffsets() for each entry. This can
|
||||
return a dict containing entries that need updating. The key should be the
|
||||
entry name and the value is a tuple (pos, size). This allows an entry to
|
||||
provide the position and size for other entries. The default implementation
|
||||
of GetEntryPositions() returns {}.
|
||||
entry name and the value is a tuple (offset, size). This allows an entry to
|
||||
provide the offset and size for other entries. The default implementation
|
||||
of GetEntryOffsets() returns {}.
|
||||
|
||||
5. PackEntries() - calls Entry.Pack() which figures out the position and
|
||||
size of an entry. The 'current' image position is passed in, and the function
|
||||
returns the position immediately after the entry being packed. The default
|
||||
5. PackEntries() - calls Entry.Pack() which figures out the offset and
|
||||
size of an entry. The 'current' image offset is passed in, and the function
|
||||
returns the offset immediately after the entry being packed. The default
|
||||
implementation of Pack() is usually sufficient.
|
||||
|
||||
6. CheckSize() - checks that the contents of all the entries fits within
|
||||
|
@ -505,16 +521,16 @@ large enough to hold all the entries.
|
|||
outside the image.
|
||||
|
||||
8. SetCalculatedProperties() - update any calculated properties in the device
|
||||
tree. This sets the correct 'pos' and 'size' vaues, for example.
|
||||
tree. This sets the correct 'offset' and 'size' vaues, for example.
|
||||
|
||||
9. ProcessEntryContents() - this calls Entry.ProcessContents() on each entry.
|
||||
The default implementatoin does nothing. This can be overriden to adjust the
|
||||
contents of an entry in some way. For example, it would be possible to create
|
||||
an entry containing a hash of the contents of some other entries. At this
|
||||
stage the position and size of entries should not be adjusted.
|
||||
stage the offset and size of entries should not be adjusted.
|
||||
|
||||
10. WriteSymbols() - write the value of symbols into the U-Boot SPL binary.
|
||||
See 'Access to binman entry positions at run time' below for a description of
|
||||
See 'Access to binman entry offsets at run time' below for a description of
|
||||
what happens in this stage.
|
||||
|
||||
11. BuildImage() - builds the image and writes it to a file. This is the final
|
||||
|
@ -549,8 +565,8 @@ the 'warning' line in scripts/Makefile.lib to see what it has found:
|
|||
# u_boot_dtsi_options_debug = $(u_boot_dtsi_options_raw)
|
||||
|
||||
|
||||
Access to binman entry positions at run time
|
||||
--------------------------------------------
|
||||
Access to binman entry offsets at run time (symbols)
|
||||
----------------------------------------------------
|
||||
|
||||
Binman assembles images and determines where each entry is placed in the image.
|
||||
This information may be useful to U-Boot at run time. For example, in SPL it
|
||||
|
@ -560,15 +576,15 @@ when SPL is finished.
|
|||
Binman allows you to declare symbols in the SPL image which are filled in
|
||||
with their correct values during the build. For example:
|
||||
|
||||
binman_sym_declare(ulong, u_boot_any, pos);
|
||||
binman_sym_declare(ulong, u_boot_any, offset);
|
||||
|
||||
declares a ulong value which will be assigned to the position of any U-Boot
|
||||
declares a ulong value which will be assigned to the offset of any U-Boot
|
||||
image (u-boot.bin, u-boot.img, u-boot-nodtb.bin) that is present in the image.
|
||||
You can access this value with something like:
|
||||
|
||||
ulong u_boot_pos = binman_sym(ulong, u_boot_any, pos);
|
||||
ulong u_boot_offset = binman_sym(ulong, u_boot_any, offset);
|
||||
|
||||
Thus u_boot_pos will be set to the position of U-Boot in memory, assuming that
|
||||
Thus u_boot_offset will be set to the offset of U-Boot in memory, assuming that
|
||||
the whole image has been loaded, or is available in flash. You can then jump to
|
||||
that address to start U-Boot.
|
||||
|
||||
|
@ -576,25 +592,58 @@ At present this feature is only supported in SPL. In principle it is possible
|
|||
to fill in such symbols in U-Boot proper, as well.
|
||||
|
||||
|
||||
Access to binman entry offsets at run time (fdt)
|
||||
------------------------------------------------
|
||||
|
||||
Binman can update the U-Boot FDT to include the final position and size of
|
||||
each entry in the images it processes. The option to enable this is -u and it
|
||||
causes binman to make sure that the 'offset', 'image-pos' and 'size' properties
|
||||
are set correctly for every entry. Since it is not necessary to specify these in
|
||||
the image definition, binman calculates the final values and writes these to
|
||||
the device tree. These can be used by U-Boot at run-time to find the location
|
||||
of each entry.
|
||||
|
||||
|
||||
Map files
|
||||
---------
|
||||
|
||||
The -m option causes binman to output a .map file for each image that it
|
||||
generates. This shows the position and size of each entry. For example:
|
||||
generates. This shows the offset and size of each entry. For example:
|
||||
|
||||
Position Size Name
|
||||
00000000 00000010 section@0
|
||||
00000000 00000004 u-boot
|
||||
00000010 00000010 section@1
|
||||
00000000 00000004 u-boot
|
||||
Offset Size Name
|
||||
00000000 00000028 main-section
|
||||
00000000 00000010 section@0
|
||||
00000000 00000004 u-boot
|
||||
00000010 00000010 section@1
|
||||
00000000 00000004 u-boot
|
||||
|
||||
This shows a hierarchical image with two sections, each with a single entry. The
|
||||
positions of the sections are absolute hex byte offsets within the image. The
|
||||
positions of the entries are relative to their respective sections. The size of
|
||||
offsets of the sections are absolute hex byte offsets within the image. The
|
||||
offsets of the entries are relative to their respective sections. The size of
|
||||
each entry is also shown, in bytes (hex). The indentation shows the entries
|
||||
nested inside their sections.
|
||||
|
||||
|
||||
Passing command-line arguments to entries
|
||||
-----------------------------------------
|
||||
|
||||
Sometimes it is useful to pass binman the value of an entry property from the
|
||||
command line. For example some entries need access to files and it is not
|
||||
always convenient to put these filenames in the image definition (device tree).
|
||||
|
||||
The-a option supports this:
|
||||
|
||||
-a<prop>=<value>
|
||||
|
||||
where
|
||||
|
||||
<prop> is the property to set
|
||||
<value> is the value to set it to
|
||||
|
||||
Not all properties can be provided this way. Only some entries support it,
|
||||
typically for filenames.
|
||||
|
||||
|
||||
Code coverage
|
||||
-------------
|
||||
|
||||
|
@ -623,7 +672,7 @@ Entry properties are documented in entry.py. The entry subclasses are free
|
|||
to change the values of properties to support special behaviour. For example,
|
||||
when Entry_blob loads a file, it sets content_size to the size of the file.
|
||||
Entry classes can adjust other entries. For example, an entry that knows
|
||||
where other entries should be positioned can set up those entries' positions
|
||||
where other entries should be positioned can set up those entries' offsets
|
||||
so they don't need to be set in the binman decription. It can also adjust
|
||||
entry contents.
|
||||
|
||||
|
|
585
tools/binman/README.entries
Normal file
585
tools/binman/README.entries
Normal file
|
@ -0,0 +1,585 @@
|
|||
Binman Entry Documentation
|
||||
===========================
|
||||
|
||||
This file describes the entry types supported by binman. These entry types can
|
||||
be placed in an image one by one to build up a final firmware image. It is
|
||||
fairly easy to create new entry types. Just add a new file to the 'etype'
|
||||
directory. You can use the existing entries as examples.
|
||||
|
||||
Note that some entries are subclasses of others, using and extending their
|
||||
features to produce new behaviours.
|
||||
|
||||
|
||||
|
||||
Entry: blob: Entry containing an arbitrary binary blob
|
||||
------------------------------------------------------
|
||||
|
||||
Note: This should not be used by itself. It is normally used as a parent
|
||||
class by other entry types.
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of file to read into entry
|
||||
|
||||
This entry reads data from a file and places it in the entry. The
|
||||
default filename is often specified specified by the subclass. See for
|
||||
example the 'u_boot' entry which provides the filename 'u-boot.bin'.
|
||||
|
||||
|
||||
|
||||
Entry: blob-named-by-arg: A blob entry which gets its filename property from its subclass
|
||||
-----------------------------------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- <xxx>-path: Filename containing the contents of this entry (optional,
|
||||
defaults to 0)
|
||||
|
||||
where <xxx> is the blob_fname argument to the constructor.
|
||||
|
||||
This entry cannot be used directly. Instead, it is used as a parent class
|
||||
for another entry, which defined blob_fname. This parameter is used to
|
||||
set the entry-arg or property containing the filename. The entry-arg or
|
||||
property is in turn used to set the actual filename.
|
||||
|
||||
See cros_ec_rw for an example of this.
|
||||
|
||||
|
||||
|
||||
Entry: cros-ec-rw: A blob entry which contains a Chromium OS read-write EC image
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- cros-ec-rw-path: Filename containing the EC image
|
||||
|
||||
This entry holds a Chromium OS EC (embedded controller) image, for use in
|
||||
updating the EC on startup via software sync.
|
||||
|
||||
|
||||
|
||||
Entry: fill: An entry which is filled to a particular byte value
|
||||
----------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- fill-byte: Byte to use to fill the entry
|
||||
|
||||
Note that the size property must be set since otherwise this entry does not
|
||||
know how large it should be.
|
||||
|
||||
You can often achieve the same effect using the pad-byte property of the
|
||||
overall image, in that the space between entries will then be padded with
|
||||
that byte. But this entry is sometimes useful for explicitly setting the
|
||||
byte value of a region.
|
||||
|
||||
|
||||
|
||||
Entry: fmap: An entry which contains an Fmap section
|
||||
----------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
None
|
||||
|
||||
FMAP is a simple format used by flashrom, an open-source utility for
|
||||
reading and writing the SPI flash, typically on x86 CPUs. The format
|
||||
provides flashrom with a list of areas, so it knows what it in the flash.
|
||||
It can then read or write just a single area, instead of the whole flash.
|
||||
|
||||
The format is defined by the flashrom project, in the file lib/fmap.h -
|
||||
see www.flashrom.org/Flashrom for more information.
|
||||
|
||||
When used, this entry will be populated with an FMAP which reflects the
|
||||
entries in the current image. Note that any hierarchy is squashed, since
|
||||
FMAP does not support this.
|
||||
|
||||
|
||||
|
||||
Entry: gbb: An entry which contains a Chromium OS Google Binary Block
|
||||
---------------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- hardware-id: Hardware ID to use for this build (a string)
|
||||
- keydir: Directory containing the public keys to use
|
||||
- bmpblk: Filename containing images used by recovery
|
||||
|
||||
Chromium OS uses a GBB to store various pieces of information, in particular
|
||||
the root and recovery keys that are used to verify the boot process. Some
|
||||
more details are here:
|
||||
|
||||
https://www.chromium.org/chromium-os/firmware-porting-guide/2-concepts
|
||||
|
||||
but note that the page dates from 2013 so is quite out of date. See
|
||||
README.chromium for how to obtain the required keys and tools.
|
||||
|
||||
|
||||
|
||||
Entry: intel-cmc: Entry containing an Intel Chipset Micro Code (CMC) file
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of file to read into entry
|
||||
|
||||
This file contains microcode for some devices in a special format. An
|
||||
example filename is 'Microcode/C0_22211.BIN'.
|
||||
|
||||
See README.x86 for information about x86 binary blobs.
|
||||
|
||||
|
||||
|
||||
Entry: intel-descriptor: Intel flash descriptor block (4KB)
|
||||
-----------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
filename: Filename of file containing the descriptor. This is typically
|
||||
a 4KB binary file, sometimes called 'descriptor.bin'
|
||||
|
||||
This entry is placed at the start of flash and provides information about
|
||||
the SPI flash regions. In particular it provides the base address and
|
||||
size of the ME (Management Engine) region, allowing us to place the ME
|
||||
binary in the right place.
|
||||
|
||||
With this entry in your image, the position of the 'intel-me' entry will be
|
||||
fixed in the image, which avoids you needed to specify an offset for that
|
||||
region. This is useful, because it is not possible to change the position
|
||||
of the ME region without updating the descriptor.
|
||||
|
||||
See README.x86 for information about x86 binary blobs.
|
||||
|
||||
|
||||
|
||||
Entry: intel-fsp: Entry containing an Intel Firmware Support Package (FSP) file
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of file to read into entry
|
||||
|
||||
This file contains binary blobs which are used on some devices to make the
|
||||
platform work. U-Boot executes this code since it is not possible to set up
|
||||
the hardware using U-Boot open-source code. Documentation is typically not
|
||||
available in sufficient detail to allow this.
|
||||
|
||||
An example filename is 'FSP/QUEENSBAY_FSP_GOLD_001_20-DECEMBER-2013.fd'
|
||||
|
||||
See README.x86 for information about x86 binary blobs.
|
||||
|
||||
|
||||
|
||||
Entry: intel-me: Entry containing an Intel Management Engine (ME) file
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of file to read into entry
|
||||
|
||||
This file contains code used by the SoC that is required to make it work.
|
||||
The Management Engine is like a background task that runs things that are
|
||||
not clearly documented, but may include keyboard, deplay and network
|
||||
access. For platform that use ME it is not possible to disable it. U-Boot
|
||||
does not directly execute code in the ME binary.
|
||||
|
||||
A typical filename is 'me.bin'.
|
||||
|
||||
See README.x86 for information about x86 binary blobs.
|
||||
|
||||
|
||||
|
||||
Entry: intel-mrc: Entry containing an Intel Memory Reference Code (MRC) file
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of file to read into entry
|
||||
|
||||
This file contains code for setting up the SDRAM on some Intel systems. This
|
||||
is executed by U-Boot when needed early during startup. A typical filename
|
||||
is 'mrc.bin'.
|
||||
|
||||
See README.x86 for information about x86 binary blobs.
|
||||
|
||||
|
||||
|
||||
Entry: intel-vbt: Entry containing an Intel Video BIOS Table (VBT) file
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of file to read into entry
|
||||
|
||||
This file contains code that sets up the integrated graphics subsystem on
|
||||
some Intel SoCs. U-Boot executes this when the display is started up.
|
||||
|
||||
See README.x86 for information about Intel binary blobs.
|
||||
|
||||
|
||||
|
||||
Entry: intel-vga: Entry containing an Intel Video Graphics Adaptor (VGA) file
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of file to read into entry
|
||||
|
||||
This file contains code that sets up the integrated graphics subsystem on
|
||||
some Intel SoCs. U-Boot executes this when the display is started up.
|
||||
|
||||
This is similar to the VBT file but in a different format.
|
||||
|
||||
See README.x86 for information about Intel binary blobs.
|
||||
|
||||
|
||||
|
||||
Entry: section: Entry that contains other entries
|
||||
-------------------------------------------------
|
||||
|
||||
Properties / Entry arguments: (see binman README for more information)
|
||||
- size: Size of section in bytes
|
||||
- align-size: Align size to a particular power of two
|
||||
- pad-before: Add padding before the entry
|
||||
- pad-after: Add padding after the entry
|
||||
- pad-byte: Pad byte to use when padding
|
||||
- sort-by-offset: Reorder the entries by offset
|
||||
- end-at-4gb: Used to build an x86 ROM which ends at 4GB (2^32)
|
||||
- name-prefix: Adds a prefix to the name of every entry in the section
|
||||
when writing out the map
|
||||
|
||||
A section is an entry which can contain other entries, thus allowing
|
||||
hierarchical images to be created. See 'Sections and hierarchical images'
|
||||
in the binman README for more information.
|
||||
|
||||
|
||||
|
||||
Entry: text: An entry which contains text
|
||||
-----------------------------------------
|
||||
|
||||
The text can be provided either in the node itself or by a command-line
|
||||
argument. There is a level of indirection to allow multiple text strings
|
||||
and sharing of text.
|
||||
|
||||
Properties / Entry arguments:
|
||||
text-label: The value of this string indicates the property / entry-arg
|
||||
that contains the string to place in the entry
|
||||
<xxx> (actual name is the value of text-label): contains the string to
|
||||
place in the entry.
|
||||
|
||||
Example node:
|
||||
|
||||
text {
|
||||
size = <50>;
|
||||
text-label = "message";
|
||||
};
|
||||
|
||||
You can then use:
|
||||
|
||||
binman -amessage="this is my message"
|
||||
|
||||
and binman will insert that string into the entry.
|
||||
|
||||
It is also possible to put the string directly in the node:
|
||||
|
||||
text {
|
||||
size = <8>;
|
||||
text-label = "message";
|
||||
message = "a message directly in the node"
|
||||
};
|
||||
|
||||
The text is not itself nul-terminated. This can be achieved, if required,
|
||||
by setting the size of the entry to something larger than the text.
|
||||
|
||||
|
||||
|
||||
Entry: u-boot: U-Boot flat binary
|
||||
---------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot.bin (default 'u-boot.bin')
|
||||
|
||||
This is the U-Boot binary, containing relocation information to allow it
|
||||
to relocate itself at runtime. The binary typically includes a device tree
|
||||
blob at the end of it. Use u_boot_nodtb if you want to package the device
|
||||
tree separately.
|
||||
|
||||
U-Boot can access binman symbols at runtime. See:
|
||||
|
||||
'Access to binman entry offsets at run time (fdt)'
|
||||
|
||||
in the binman README for more information.
|
||||
|
||||
|
||||
|
||||
Entry: u-boot-dtb: U-Boot device tree
|
||||
-------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot.dtb (default 'u-boot.dtb')
|
||||
|
||||
This is the U-Boot device tree, containing configuration information for
|
||||
U-Boot. U-Boot needs this to know what devices are present and which drivers
|
||||
to activate.
|
||||
|
||||
|
||||
|
||||
Entry: u-boot-dtb-with-ucode: A U-Boot device tree file, with the microcode removed
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot.dtb (default 'u-boot.dtb')
|
||||
|
||||
See Entry_u_boot_ucode for full details of the three entries involved in
|
||||
this process. This entry provides the U-Boot device-tree file, which
|
||||
contains the microcode. If the microcode is not being collated into one
|
||||
place then the offset and size of the microcode is recorded by this entry,
|
||||
for use by u_boot_with_ucode_ptr. If it is being collated, then this
|
||||
entry deletes the microcode from the device tree (to save space) and makes
|
||||
it available to u_boot_ucode.
|
||||
|
||||
|
||||
|
||||
Entry: u-boot-img: U-Boot legacy image
|
||||
--------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot.img (default 'u-boot.img')
|
||||
|
||||
This is the U-Boot binary as a packaged image, in legacy format. It has a
|
||||
header which allows it to be loaded at the correct address for execution.
|
||||
|
||||
You should use FIT (Flat Image Tree) instead of the legacy image for new
|
||||
applications.
|
||||
|
||||
|
||||
|
||||
Entry: u-boot-nodtb: U-Boot flat binary without device tree appended
|
||||
--------------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot.bin (default 'u-boot-nodtb.bin')
|
||||
|
||||
This is the U-Boot binary, containing relocation information to allow it
|
||||
to relocate itself at runtime. It does not include a device tree blob at
|
||||
the end of it so normally cannot work without it. You can add a u_boot_dtb
|
||||
entry after this one, or use a u_boot entry instead (which contains both
|
||||
U-Boot and the device tree).
|
||||
|
||||
|
||||
|
||||
Entry: u-boot-spl: U-Boot SPL binary
|
||||
------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot-spl.bin (default 'spl/u-boot-spl.bin')
|
||||
|
||||
This is the U-Boot SPL (Secondary Program Loader) binary. This is a small
|
||||
binary which loads before U-Boot proper, typically into on-chip SRAM. It is
|
||||
responsible for locating, loading and jumping to U-Boot. Note that SPL is
|
||||
not relocatable so must be loaded to the correct address in SRAM, or written
|
||||
to run from the correct address if direct flash execution is possible (e.g.
|
||||
on x86 devices).
|
||||
|
||||
SPL can access binman symbols at runtime. See:
|
||||
|
||||
'Access to binman entry offsets at run time (symbols)'
|
||||
|
||||
in the binman README for more information.
|
||||
|
||||
The ELF file 'spl/u-boot-spl' must also be available for this to work, since
|
||||
binman uses that to look up symbols to write into the SPL binary.
|
||||
|
||||
|
||||
|
||||
Entry: u-boot-spl-bss-pad: U-Boot SPL binary padded with a BSS region
|
||||
---------------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
None
|
||||
|
||||
This is similar to u_boot_spl except that padding is added after the SPL
|
||||
binary to cover the BSS (Block Started by Symbol) region. This region holds
|
||||
the various used by SPL. It is set to 0 by SPL when it starts up. If you
|
||||
want to append data to the SPL image (such as a device tree file), you must
|
||||
pad out the BSS region to avoid the data overlapping with U-Boot variables.
|
||||
This entry is useful in that case. It automatically pads out the entry size
|
||||
to cover both the code, data and BSS.
|
||||
|
||||
The ELF file 'spl/u-boot-spl' must also be available for this to work, since
|
||||
binman uses that to look up the BSS address.
|
||||
|
||||
|
||||
|
||||
Entry: u-boot-spl-dtb: U-Boot SPL device tree
|
||||
---------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot.dtb (default 'spl/u-boot-spl.dtb')
|
||||
|
||||
This is the SPL device tree, containing configuration information for
|
||||
SPL. SPL needs this to know what devices are present and which drivers
|
||||
to activate.
|
||||
|
||||
|
||||
|
||||
Entry: u-boot-spl-nodtb: SPL binary without device tree appended
|
||||
----------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of spl/u-boot-spl-nodtb.bin (default
|
||||
'spl/u-boot-spl-nodtb.bin')
|
||||
|
||||
This is the U-Boot SPL binary, It does not include a device tree blob at
|
||||
the end of it so may not be able to work without it, assuming SPL needs
|
||||
a device tree to operation on your platform. You can add a u_boot_spl_dtb
|
||||
entry after this one, or use a u_boot_spl entry instead (which contains
|
||||
both SPL and the device tree).
|
||||
|
||||
|
||||
|
||||
Entry: u-boot-spl-with-ucode-ptr: U-Boot SPL with embedded microcode pointer
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
See Entry_u_boot_ucode for full details of the entries involved in this
|
||||
process.
|
||||
|
||||
|
||||
|
||||
Entry: u-boot-tpl: U-Boot TPL binary
|
||||
------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot-tpl.bin (default 'tpl/u-boot-tpl.bin')
|
||||
|
||||
This is the U-Boot TPL (Tertiary Program Loader) binary. This is a small
|
||||
binary which loads before SPL, typically into on-chip SRAM. It is
|
||||
responsible for locating, loading and jumping to SPL, the next-stage
|
||||
loader. Note that SPL is not relocatable so must be loaded to the correct
|
||||
address in SRAM, or written to run from the correct address if direct
|
||||
flash execution is possible (e.g. on x86 devices).
|
||||
|
||||
SPL can access binman symbols at runtime. See:
|
||||
|
||||
'Access to binman entry offsets at run time (symbols)'
|
||||
|
||||
in the binman README for more information.
|
||||
|
||||
The ELF file 'tpl/u-boot-tpl' must also be available for this to work, since
|
||||
binman uses that to look up symbols to write into the TPL binary.
|
||||
|
||||
|
||||
|
||||
Entry: u-boot-tpl-dtb: U-Boot TPL device tree
|
||||
---------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot.dtb (default 'tpl/u-boot-tpl.dtb')
|
||||
|
||||
This is the TPL device tree, containing configuration information for
|
||||
TPL. TPL needs this to know what devices are present and which drivers
|
||||
to activate.
|
||||
|
||||
|
||||
|
||||
Entry: u-boot-ucode: U-Boot microcode block
|
||||
-------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
None
|
||||
|
||||
The contents of this entry are filled in automatically by other entries
|
||||
which must also be in the image.
|
||||
|
||||
U-Boot on x86 needs a single block of microcode. This is collected from
|
||||
the various microcode update nodes in the device tree. It is also unable
|
||||
to read the microcode from the device tree on platforms that use FSP
|
||||
(Firmware Support Package) binaries, because the API requires that the
|
||||
microcode is supplied before there is any SRAM available to use (i.e.
|
||||
the FSP sets up the SRAM / cache-as-RAM but does so in the call that
|
||||
requires the microcode!). To keep things simple, all x86 platforms handle
|
||||
microcode the same way in U-Boot (even non-FSP platforms). This is that
|
||||
a table is placed at _dt_ucode_base_size containing the base address and
|
||||
size of the microcode. This is either passed to the FSP (for FSP
|
||||
platforms), or used to set up the microcode (for non-FSP platforms).
|
||||
This all happens in the build system since it is the only way to get
|
||||
the microcode into a single blob and accessible without SRAM.
|
||||
|
||||
There are two cases to handle. If there is only one microcode blob in
|
||||
the device tree, then the ucode pointer it set to point to that. This
|
||||
entry (u-boot-ucode) is empty. If there is more than one update, then
|
||||
this entry holds the concatenation of all updates, and the device tree
|
||||
entry (u-boot-dtb-with-ucode) is updated to remove the microcode. This
|
||||
last step ensures that that the microcode appears in one contiguous
|
||||
block in the image and is not unnecessarily duplicated in the device
|
||||
tree. It is referred to as 'collation' here.
|
||||
|
||||
Entry types that have a part to play in handling microcode:
|
||||
|
||||
Entry_u_boot_with_ucode_ptr:
|
||||
Contains u-boot-nodtb.bin (i.e. U-Boot without the device tree).
|
||||
It updates it with the address and size of the microcode so that
|
||||
U-Boot can find it early on start-up.
|
||||
Entry_u_boot_dtb_with_ucode:
|
||||
Contains u-boot.dtb. It stores the microcode in a
|
||||
'self.ucode_data' property, which is then read by this class to
|
||||
obtain the microcode if needed. If collation is performed, it
|
||||
removes the microcode from the device tree.
|
||||
Entry_u_boot_ucode:
|
||||
This class. If collation is enabled it reads the microcode from
|
||||
the Entry_u_boot_dtb_with_ucode entry, and uses it as the
|
||||
contents of this entry.
|
||||
|
||||
|
||||
|
||||
Entry: u-boot-with-ucode-ptr: U-Boot with embedded microcode pointer
|
||||
--------------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot-nodtb.dtb (default 'u-boot-nodtb.dtb')
|
||||
|
||||
See Entry_u_boot_ucode for full details of the three entries involved in
|
||||
this process. This entry updates U-Boot with the offset and size of the
|
||||
microcode, to allow early x86 boot code to find it without doing anything
|
||||
complicated. Otherwise it is the same as the u_boot entry.
|
||||
|
||||
|
||||
|
||||
Entry: vblock: An entry which contains a Chromium OS verified boot block
|
||||
------------------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- keydir: Directory containing the public keys to use
|
||||
- keyblock: Name of the key file to use (inside keydir)
|
||||
- signprivate: Name of provide key file to use (inside keydir)
|
||||
- version: Version number of the vblock (typically 1)
|
||||
- kernelkey: Name of the kernel key to use (inside keydir)
|
||||
- preamble-flags: Value of the vboot preamble flags (typically 0)
|
||||
|
||||
Chromium OS signs the read-write firmware and kernel, writing the signature
|
||||
in this block. This allows U-Boot to verify that the next firmware stage
|
||||
and kernel are genuine.
|
||||
|
||||
|
||||
|
||||
Entry: x86-start16: x86 16-bit start-up code for U-Boot
|
||||
-------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot-x86-16bit.bin (default
|
||||
'u-boot-x86-16bit.bin')
|
||||
|
||||
x86 CPUs start up in 16-bit mode, even if they are 32-bit CPUs. This code
|
||||
must be placed at a particular address. This entry holds that code. It is
|
||||
typically placed at offset CONFIG_SYS_X86_START16. The code is responsible
|
||||
for changing to 32-bit mode and jumping to U-Boot's entry point, which
|
||||
requires 32-bit mode (for 32-bit U-Boot).
|
||||
|
||||
For 64-bit U-Boot, the 'x86_start16_spl' entry type is used instead.
|
||||
|
||||
|
||||
|
||||
Entry: x86-start16-spl: x86 16-bit start-up code for SPL
|
||||
--------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of spl/u-boot-x86-16bit-spl.bin (default
|
||||
'spl/u-boot-x86-16bit-spl.bin')
|
||||
|
||||
x86 CPUs start up in 16-bit mode, even if they are 64-bit CPUs. This code
|
||||
must be placed at a particular address. This entry holds that code. It is
|
||||
typically placed at offset CONFIG_SYS_X86_START16. The code is responsible
|
||||
for changing to 32-bit mode and starting SPL, which in turn changes to
|
||||
64-bit mode and jumps to U-Boot (for 64-bit U-Boot).
|
||||
|
||||
For 32-bit U-Boot, the 'x86_start16' entry type is used instead.
|
||||
|
||||
|
||||
|
|
@ -77,9 +77,20 @@ def RunTests(debug, args):
|
|||
return 1
|
||||
return 0
|
||||
|
||||
def GetEntryModules(include_testing=True):
|
||||
"""Get a set of entry class implementations
|
||||
|
||||
Returns:
|
||||
Set of paths to entry class filenames
|
||||
"""
|
||||
glob_list = glob.glob(os.path.join(our_path, 'etype/*.py'))
|
||||
return set([os.path.splitext(os.path.basename(item))[0]
|
||||
for item in glob_list
|
||||
if include_testing or '_testing' not in item])
|
||||
|
||||
def RunTestCoverage():
|
||||
"""Run the tests and check that we get 100% coverage"""
|
||||
glob_list = glob.glob(os.path.join(our_path, 'etype/*.py'))
|
||||
glob_list = GetEntryModules(False)
|
||||
all_set = set([os.path.splitext(os.path.basename(item))[0]
|
||||
for item in glob_list if '_testing' not in item])
|
||||
test_util.RunTestCoverage('tools/binman/binman.py', None,
|
||||
|
@ -107,13 +118,8 @@ def RunBinman(options, args):
|
|||
elif options.test_coverage:
|
||||
RunTestCoverage()
|
||||
|
||||
elif options.full_help:
|
||||
pager = os.getenv('PAGER')
|
||||
if not pager:
|
||||
pager = 'more'
|
||||
fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
|
||||
'README')
|
||||
command.Run(pager, fname)
|
||||
elif options.entry_docs:
|
||||
control.WriteEntryDocs(GetEntryModules())
|
||||
|
||||
else:
|
||||
try:
|
||||
|
|
|
@ -25,22 +25,21 @@ class Section(object):
|
|||
_size: Section size in bytes, or None if not known yet
|
||||
_align_size: Section size alignment, or None
|
||||
_pad_before: Number of bytes before the first entry starts. This
|
||||
effectively changes the place where entry position 0 starts
|
||||
effectively changes the place where entry offset 0 starts
|
||||
_pad_after: Number of bytes after the last entry ends. The last
|
||||
entry will finish on or before this boundary
|
||||
_pad_byte: Byte to use to pad the section where there is no entry
|
||||
_sort: True if entries should be sorted by position, False if they
|
||||
_sort: True if entries should be sorted by offset, False if they
|
||||
must be in-order in the device tree description
|
||||
_skip_at_start: Number of bytes before the first entry starts. These
|
||||
effectively adjust the starting position of entries. For example,
|
||||
effectively adjust the starting offset of entries. For example,
|
||||
if _pad_before is 16, then the first entry would start at 16.
|
||||
An entry with pos = 20 would in fact be written at position 4
|
||||
An entry with offset = 20 would in fact be written at offset 4
|
||||
in the image file.
|
||||
_end_4gb: Indicates that the section ends at the 4GB boundary. This is
|
||||
used for x86 images, which want to use positions such that a
|
||||
memory address (like 0xff800000) is the first entry position.
|
||||
This causes _skip_at_start to be set to the starting memory
|
||||
address.
|
||||
used for x86 images, which want to use offsets such that a memory
|
||||
address (like 0xff800000) is the first entry offset. This causes
|
||||
_skip_at_start to be set to the starting memory address.
|
||||
_name_prefix: Prefix to add to the name of all entries within this
|
||||
section
|
||||
_entries: OrderedDict() of entries
|
||||
|
@ -51,7 +50,9 @@ class Section(object):
|
|||
import entry
|
||||
from entry import Entry
|
||||
|
||||
self._name = name
|
||||
self._node = node
|
||||
self._offset = 0
|
||||
self._size = None
|
||||
self._align_size = None
|
||||
self._pad_before = 0
|
||||
|
@ -76,7 +77,7 @@ class Section(object):
|
|||
self._pad_before = fdt_util.GetInt(self._node, 'pad-before', 0)
|
||||
self._pad_after = fdt_util.GetInt(self._node, 'pad-after', 0)
|
||||
self._pad_byte = fdt_util.GetInt(self._node, 'pad-byte', 0)
|
||||
self._sort = fdt_util.GetBool(self._node, 'sort-by-pos')
|
||||
self._sort = fdt_util.GetBool(self._node, 'sort-by-offset')
|
||||
self._end_4gb = fdt_util.GetBool(self._node, 'end-at-4gb')
|
||||
if self._end_4gb and not self._size:
|
||||
self._Raise("Section size must be provided when using end-at-4gb")
|
||||
|
@ -90,11 +91,21 @@ class Section(object):
|
|||
entry.SetPrefix(self._name_prefix)
|
||||
self._entries[node.name] = entry
|
||||
|
||||
def SetOffset(self, offset):
|
||||
self._offset = offset
|
||||
|
||||
def AddMissingProperties(self):
|
||||
"""Add new properties to the device tree as needed for this entry"""
|
||||
for prop in ['offset', 'size', 'image-pos']:
|
||||
if not prop in self._node.props:
|
||||
self._node.AddZeroProp(prop)
|
||||
for entry in self._entries.values():
|
||||
entry.AddMissingProperties()
|
||||
|
||||
def SetCalculatedProperties(self):
|
||||
self._node.SetInt('offset', self._offset)
|
||||
self._node.SetInt('size', self._size)
|
||||
self._node.SetInt('image-pos', self._image_pos)
|
||||
for entry in self._entries.values():
|
||||
entry.SetCalculatedProperties()
|
||||
|
||||
|
@ -117,7 +128,7 @@ class Section(object):
|
|||
"""Check that the section contents does not exceed its size, etc."""
|
||||
contents_size = 0
|
||||
for entry in self._entries.values():
|
||||
contents_size = max(contents_size, entry.pos + entry.size)
|
||||
contents_size = max(contents_size, entry.offset + entry.size)
|
||||
|
||||
contents_size -= self._skip_at_start
|
||||
|
||||
|
@ -190,39 +201,41 @@ class Section(object):
|
|||
'contents: remaining %s' % todo)
|
||||
return True
|
||||
|
||||
def _SetEntryPosSize(self, name, pos, size):
|
||||
"""Set the position and size of an entry
|
||||
def _SetEntryOffsetSize(self, name, offset, size):
|
||||
"""Set the offset and size of an entry
|
||||
|
||||
Args:
|
||||
name: Entry name to update
|
||||
pos: New position
|
||||
offset: New offset
|
||||
size: New size
|
||||
"""
|
||||
entry = self._entries.get(name)
|
||||
if not entry:
|
||||
self._Raise("Unable to set pos/size for unknown entry '%s'" % name)
|
||||
entry.SetPositionSize(self._skip_at_start + pos, size)
|
||||
self._Raise("Unable to set offset/size for unknown entry '%s'" %
|
||||
name)
|
||||
entry.SetOffsetSize(self._skip_at_start + offset, size)
|
||||
|
||||
def GetEntryPositions(self):
|
||||
"""Handle entries that want to set the position/size of other entries
|
||||
def GetEntryOffsets(self):
|
||||
"""Handle entries that want to set the offset/size of other entries
|
||||
|
||||
This calls each entry's GetPositions() method. If it returns a list
|
||||
This calls each entry's GetOffsets() method. If it returns a list
|
||||
of entries to update, it updates them.
|
||||
"""
|
||||
for entry in self._entries.values():
|
||||
pos_dict = entry.GetPositions()
|
||||
for name, info in pos_dict.iteritems():
|
||||
self._SetEntryPosSize(name, *info)
|
||||
offset_dict = entry.GetOffsets()
|
||||
for name, info in offset_dict.iteritems():
|
||||
self._SetEntryOffsetSize(name, *info)
|
||||
|
||||
def PackEntries(self):
|
||||
"""Pack all entries into the section"""
|
||||
pos = self._skip_at_start
|
||||
offset = self._skip_at_start
|
||||
for entry in self._entries.values():
|
||||
pos = entry.Pack(pos)
|
||||
offset = entry.Pack(offset)
|
||||
self._size = self.CheckSize()
|
||||
|
||||
def _SortEntries(self):
|
||||
"""Sort entries by position"""
|
||||
entries = sorted(self._entries.values(), key=lambda entry: entry.pos)
|
||||
"""Sort entries by offset"""
|
||||
entries = sorted(self._entries.values(), key=lambda entry: entry.offset)
|
||||
self._entries.clear()
|
||||
for entry in entries:
|
||||
self._entries[entry._node.name] = entry
|
||||
|
@ -231,23 +244,28 @@ class Section(object):
|
|||
"""Check that entries do not overlap or extend outside the section"""
|
||||
if self._sort:
|
||||
self._SortEntries()
|
||||
pos = 0
|
||||
offset = 0
|
||||
prev_name = 'None'
|
||||
for entry in self._entries.values():
|
||||
entry.CheckPosition()
|
||||
if (entry.pos < self._skip_at_start or
|
||||
entry.pos >= self._skip_at_start + self._size):
|
||||
entry.Raise("Position %#x (%d) is outside the section starting "
|
||||
entry.CheckOffset()
|
||||
if (entry.offset < self._skip_at_start or
|
||||
entry.offset >= self._skip_at_start + self._size):
|
||||
entry.Raise("Offset %#x (%d) is outside the section starting "
|
||||
"at %#x (%d)" %
|
||||
(entry.pos, entry.pos, self._skip_at_start,
|
||||
(entry.offset, entry.offset, self._skip_at_start,
|
||||
self._skip_at_start))
|
||||
if entry.pos < pos:
|
||||
entry.Raise("Position %#x (%d) overlaps with previous entry '%s' "
|
||||
if entry.offset < offset:
|
||||
entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' "
|
||||
"ending at %#x (%d)" %
|
||||
(entry.pos, entry.pos, prev_name, pos, pos))
|
||||
pos = entry.pos + entry.size
|
||||
(entry.offset, entry.offset, prev_name, offset, offset))
|
||||
offset = entry.offset + entry.size
|
||||
prev_name = entry.GetPath()
|
||||
|
||||
def SetImagePos(self, image_pos):
|
||||
self._image_pos = image_pos
|
||||
for entry in self._entries.values():
|
||||
entry.SetImagePos(image_pos)
|
||||
|
||||
def ProcessEntryContents(self):
|
||||
"""Call the ProcessContents() method for each entry
|
||||
|
||||
|
@ -261,18 +279,18 @@ class Section(object):
|
|||
for entry in self._entries.values():
|
||||
entry.WriteSymbols(self)
|
||||
|
||||
def BuildSection(self, fd, base_pos):
|
||||
def BuildSection(self, fd, base_offset):
|
||||
"""Write the section to a file"""
|
||||
fd.seek(base_pos)
|
||||
fd.seek(base_offset)
|
||||
fd.write(self.GetData())
|
||||
|
||||
def GetData(self):
|
||||
"""Write the section to a file"""
|
||||
"""Get the contents of the section"""
|
||||
section_data = chr(self._pad_byte) * self._size
|
||||
|
||||
for entry in self._entries.values():
|
||||
data = entry.GetData()
|
||||
base = self._pad_before + entry.pos - self._skip_at_start
|
||||
base = self._pad_before + entry.offset - self._skip_at_start
|
||||
section_data = (section_data[:base] + data +
|
||||
section_data[base + len(data):])
|
||||
return section_data
|
||||
|
@ -283,15 +301,15 @@ class Section(object):
|
|||
Looks up a symbol in an ELF file. Only entry types which come from an
|
||||
ELF image can be used by this function.
|
||||
|
||||
At present the only entry property supported is pos.
|
||||
At present the only entry property supported is offset.
|
||||
|
||||
Args:
|
||||
sym_name: Symbol name in the ELF file to look up in the format
|
||||
_binman_<entry>_prop_<property> where <entry> is the name of
|
||||
the entry and <property> is the property to find (e.g.
|
||||
_binman_u_boot_prop_pos). As a special case, you can append
|
||||
_binman_u_boot_prop_offset). As a special case, you can append
|
||||
_any to <entry> to have it search for any matching entry. E.g.
|
||||
_binman_u_boot_any_prop_pos will match entries called u-boot,
|
||||
_binman_u_boot_any_prop_offset will match entries called u-boot,
|
||||
u-boot-img and u-boot-nodtb)
|
||||
optional: True if the symbol is optional. If False this function
|
||||
will raise if the symbol is not found
|
||||
|
@ -327,19 +345,64 @@ class Section(object):
|
|||
print('Warning: %s' % err, file=sys.stderr)
|
||||
return None
|
||||
raise ValueError(err)
|
||||
if prop_name == 'pos':
|
||||
return entry.pos
|
||||
if prop_name == 'offset':
|
||||
return entry.offset
|
||||
elif prop_name == 'image_pos':
|
||||
return entry.image_pos
|
||||
else:
|
||||
raise ValueError("%s: No such property '%s'" % (msg, prop_name))
|
||||
|
||||
def GetEntries(self):
|
||||
"""Get the number of entries in a section
|
||||
|
||||
Returns:
|
||||
Number of entries in a section
|
||||
"""
|
||||
return self._entries
|
||||
|
||||
def GetSize(self):
|
||||
"""Get the size of a section in bytes
|
||||
|
||||
This is only meaningful if the section has a pre-defined size, or the
|
||||
entries within it have been packed, so that the size has been
|
||||
calculated.
|
||||
|
||||
Returns:
|
||||
Entry size in bytes
|
||||
"""
|
||||
return self._size
|
||||
|
||||
def WriteMap(self, fd, indent):
|
||||
"""Write a map of the section to a .map file
|
||||
|
||||
Args:
|
||||
fd: File to write the map to
|
||||
"""
|
||||
Entry.WriteMapLine(fd, indent, self._name, self._offset, self._size,
|
||||
self._image_pos)
|
||||
for entry in self._entries.values():
|
||||
entry.WriteMap(fd, indent)
|
||||
entry.WriteMap(fd, indent + 1)
|
||||
|
||||
def GetContentsByPhandle(self, phandle, source_entry):
|
||||
"""Get the data contents of an entry specified by a phandle
|
||||
|
||||
This uses a phandle to look up a node and and find the entry
|
||||
associated with it. Then it returnst he contents of that entry.
|
||||
|
||||
Args:
|
||||
phandle: Phandle to look up (integer)
|
||||
source_entry: Entry containing that phandle (used for error
|
||||
reporting)
|
||||
|
||||
Returns:
|
||||
data from associated entry (as a string), or None if not found
|
||||
"""
|
||||
node = self._node.GetFdt().LookupPhandle(phandle)
|
||||
if not node:
|
||||
source_entry.Raise("Cannot find node for phandle %d" % phandle)
|
||||
for entry in self._entries.values():
|
||||
if entry._node == node:
|
||||
if entry.data is None:
|
||||
return None
|
||||
return entry.data
|
||||
source_entry.Raise("Cannot find entry for node '%s'" % node.name)
|
||||
|
|
|
@ -18,6 +18,8 @@ def ParseArgs(argv):
|
|||
args is a list of string arguments
|
||||
"""
|
||||
parser = OptionParser()
|
||||
parser.add_option('-a', '--entry-arg', type='string', action='append',
|
||||
help='Set argument value arg=value')
|
||||
parser.add_option('-b', '--board', type='string',
|
||||
help='Board name to build')
|
||||
parser.add_option('-B', '--build-dir', type='string', default='b',
|
||||
|
@ -26,6 +28,8 @@ def ParseArgs(argv):
|
|||
help='Configuration file (.dtb) to use')
|
||||
parser.add_option('-D', '--debug', action='store_true',
|
||||
help='Enabling debugging (provides a full traceback on error)')
|
||||
parser.add_option('-E', '--entry-docs', action='store_true',
|
||||
help='Write out entry documentation (see README.entries)')
|
||||
parser.add_option('-I', '--indir', action='append',
|
||||
help='Add a path to a directory to use for input files')
|
||||
parser.add_option('-H', '--full-help', action='store_true',
|
||||
|
@ -43,7 +47,7 @@ def ParseArgs(argv):
|
|||
parser.add_option('-T', '--test-coverage', action='store_true',
|
||||
default=False, help='run tests and check for 100% coverage')
|
||||
parser.add_option('-u', '--update-fdt', action='store_true',
|
||||
default=False, help='Update the binman node with position/size info')
|
||||
default=False, help='Update the binman node with offset/size info')
|
||||
parser.add_option('-v', '--verbosity', default=1,
|
||||
type='int', help='Control verbosity: 0=silent, 1=progress, 3=full, '
|
||||
'4=debug')
|
||||
|
|
|
@ -7,13 +7,12 @@
|
|||
|
||||
from collections import OrderedDict
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import tools
|
||||
|
||||
import command
|
||||
import elf
|
||||
import fdt
|
||||
import fdt_util
|
||||
from image import Image
|
||||
import tout
|
||||
|
||||
|
@ -25,6 +24,9 @@ images = OrderedDict()
|
|||
# 'u-boot-spl.dtb')
|
||||
fdt_files = {}
|
||||
|
||||
# Arguments passed to binman to provide arguments to entries
|
||||
entry_args = {}
|
||||
|
||||
|
||||
def _ReadImageDesc(binman_node):
|
||||
"""Read the image descriptions from the /binman node
|
||||
|
@ -76,6 +78,24 @@ def GetFdt(fname):
|
|||
def GetFdtPath(fname):
|
||||
return fdt_files[fname]._fname
|
||||
|
||||
def SetEntryArgs(args):
|
||||
global entry_args
|
||||
|
||||
entry_args = {}
|
||||
if args:
|
||||
for arg in args:
|
||||
m = re.match('([^=]*)=(.*)', arg)
|
||||
if not m:
|
||||
raise ValueError("Invalid entry arguemnt '%s'" % arg)
|
||||
entry_args[m.group(1)] = m.group(2)
|
||||
|
||||
def GetEntryArg(name):
|
||||
return entry_args.get(name)
|
||||
|
||||
def WriteEntryDocs(modules, test_missing=None):
|
||||
from entry import Entry
|
||||
Entry.WriteDocs(modules, test_missing)
|
||||
|
||||
def Binman(options, args):
|
||||
"""The main control code for binman
|
||||
|
||||
|
@ -111,11 +131,17 @@ def Binman(options, args):
|
|||
options.indir.append(board_pathname)
|
||||
|
||||
try:
|
||||
# Import these here in case libfdt.py is not available, in which case
|
||||
# the above help option still works.
|
||||
import fdt
|
||||
import fdt_util
|
||||
|
||||
tout.Init(options.verbosity)
|
||||
elf.debug = options.debug
|
||||
try:
|
||||
tools.SetInputDirs(options.indir)
|
||||
tools.PrepareOutputDir(options.outdir, options.preserve)
|
||||
SetEntryArgs(options.entry_arg)
|
||||
|
||||
# Get the device tree ready by compiling it and copying the compiled
|
||||
# output into a file in our output directly. Then scan it for use
|
||||
|
@ -142,7 +168,7 @@ def Binman(options, args):
|
|||
# size of the device tree is correct. Later, in
|
||||
# SetCalculatedProperties() we will insert the correct values
|
||||
# without changing the device-tree size, thus ensuring that our
|
||||
# entry positions remain the same.
|
||||
# entry offsets remain the same.
|
||||
for image in images.values():
|
||||
if options.update_fdt:
|
||||
image.AddMissingProperties()
|
||||
|
@ -157,10 +183,11 @@ def Binman(options, args):
|
|||
# image will be reported after earlier images are already
|
||||
# completed and written, but that does not seem important.
|
||||
image.GetEntryContents()
|
||||
image.GetEntryPositions()
|
||||
image.GetEntryOffsets()
|
||||
image.PackEntries()
|
||||
image.CheckSize()
|
||||
image.CheckEntries()
|
||||
image.SetImagePos()
|
||||
if options.update_fdt:
|
||||
image.SetCalculatedProperties()
|
||||
image.ProcessEntryContents()
|
||||
|
|
|
@ -57,7 +57,9 @@ def GetSymbols(fname, patterns):
|
|||
name = parts[2]
|
||||
syms[name] = Symbol(section, int(value, 16), int(size,16),
|
||||
flags[1] == 'w')
|
||||
return syms
|
||||
|
||||
# Sort dict by address
|
||||
return OrderedDict(sorted(syms.iteritems(), key=lambda x: x[1].address))
|
||||
|
||||
def GetSymbolAddress(fname, sym_name):
|
||||
"""Get a value of a symbol from an ELF file
|
||||
|
@ -79,9 +81,9 @@ def LookupAndWriteSymbols(elf_fname, entry, section):
|
|||
"""Replace all symbols in an entry with their correct values
|
||||
|
||||
The entry contents is updated so that values for referenced symbols will be
|
||||
visible at run time. This is done by finding out the symbols positions in
|
||||
the entry (using the ELF file) and replacing them with values from binman's
|
||||
data structures.
|
||||
visible at run time. This is done by finding out the symbols offsets in the
|
||||
entry (using the ELF file) and replacing them with values from binman's data
|
||||
structures.
|
||||
|
||||
Args:
|
||||
elf_fname: Filename of ELF image containing the symbol information for
|
||||
|
|
|
@ -15,6 +15,10 @@ binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
|
|||
|
||||
|
||||
class FakeEntry:
|
||||
"""A fake Entry object, usedfor testing
|
||||
|
||||
This supports an entry with a given size.
|
||||
"""
|
||||
def __init__(self, contents_size):
|
||||
self.contents_size = contents_size
|
||||
self.data = 'a' * contents_size
|
||||
|
@ -22,7 +26,14 @@ class FakeEntry:
|
|||
def GetPath(self):
|
||||
return 'entry_path'
|
||||
|
||||
|
||||
class FakeSection:
|
||||
"""A fake Section object, used for testing
|
||||
|
||||
This has the minimum feature set needed to support testing elf functions.
|
||||
A LookupSymbol() function is provided which returns a fake value for amu
|
||||
symbol requested.
|
||||
"""
|
||||
def __init__(self, sym_value=1):
|
||||
self.sym_value = sym_value
|
||||
|
||||
|
@ -30,15 +41,19 @@ class FakeSection:
|
|||
return 'section_path'
|
||||
|
||||
def LookupSymbol(self, name, weak, msg):
|
||||
"""Fake implementation which returns the same value for all symbols"""
|
||||
return self.sym_value
|
||||
|
||||
|
||||
class TestElf(unittest.TestCase):
|
||||
def testAllSymbols(self):
|
||||
"""Test that we can obtain a symbol from the ELF file"""
|
||||
fname = os.path.join(binman_dir, 'test', 'u_boot_ucode_ptr')
|
||||
syms = elf.GetSymbols(fname, [])
|
||||
self.assertIn('.ucode', syms)
|
||||
|
||||
def testRegexSymbols(self):
|
||||
"""Test that we can obtain from the ELF file by regular expression"""
|
||||
fname = os.path.join(binman_dir, 'test', 'u_boot_ucode_ptr')
|
||||
syms = elf.GetSymbols(fname, ['ucode'])
|
||||
self.assertIn('.ucode', syms)
|
||||
|
@ -48,6 +63,7 @@ class TestElf(unittest.TestCase):
|
|||
self.assertIn('.ucode', syms)
|
||||
|
||||
def testMissingFile(self):
|
||||
"""Test that a missing file is detected"""
|
||||
entry = FakeEntry(10)
|
||||
section = FakeSection()
|
||||
with self.assertRaises(ValueError) as e:
|
||||
|
@ -56,6 +72,7 @@ class TestElf(unittest.TestCase):
|
|||
str(e.exception))
|
||||
|
||||
def testOutsideFile(self):
|
||||
"""Test a symbol which extends outside the entry area is detected"""
|
||||
entry = FakeEntry(10)
|
||||
section = FakeSection()
|
||||
elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms')
|
||||
|
@ -65,6 +82,11 @@ class TestElf(unittest.TestCase):
|
|||
'is a', str(e.exception))
|
||||
|
||||
def testMissingImageStart(self):
|
||||
"""Test that we detect a missing __image_copy_start symbol
|
||||
|
||||
This is needed to mark the start of the image. Without it we cannot
|
||||
locate the offset of a binman symbol within the image.
|
||||
"""
|
||||
entry = FakeEntry(10)
|
||||
section = FakeSection()
|
||||
elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms_bad')
|
||||
|
@ -72,6 +94,11 @@ class TestElf(unittest.TestCase):
|
|||
None)
|
||||
|
||||
def testBadSymbolSize(self):
|
||||
"""Test that an attempt to use an 8-bit symbol are detected
|
||||
|
||||
Only 32 and 64 bits are supported, since we need to store an offset
|
||||
into the image.
|
||||
"""
|
||||
entry = FakeEntry(10)
|
||||
section = FakeSection()
|
||||
elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms_size')
|
||||
|
@ -81,6 +108,11 @@ class TestElf(unittest.TestCase):
|
|||
str(e.exception))
|
||||
|
||||
def testNoValue(self):
|
||||
"""Test the case where we have no value for the symbol
|
||||
|
||||
This should produce -1 values for all thress symbols, taking up the
|
||||
first 16 bytes of the image.
|
||||
"""
|
||||
entry = FakeEntry(20)
|
||||
section = FakeSection(sym_value=None)
|
||||
elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms')
|
||||
|
@ -88,6 +120,7 @@ class TestElf(unittest.TestCase):
|
|||
self.assertEqual(chr(255) * 16 + 'a' * 4, entry.data)
|
||||
|
||||
def testDebug(self):
|
||||
"""Check that enabling debug in the elf module produced debug output"""
|
||||
elf.debug = True
|
||||
entry = FakeEntry(20)
|
||||
section = FakeSection()
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
from __future__ import print_function
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
# importlib was introduced in Python 2.7 but there was a report of it not
|
||||
# working in 2.7.12, so we work around this:
|
||||
# http://lists.denx.de/pipermail/u-boot/2016-October/269729.html
|
||||
|
@ -16,6 +18,7 @@ except:
|
|||
have_importlib = False
|
||||
|
||||
import fdt_util
|
||||
import control
|
||||
import os
|
||||
import sys
|
||||
import tools
|
||||
|
@ -24,6 +27,12 @@ modules = {}
|
|||
|
||||
our_path = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
|
||||
# An argument which can be passed to entries on the command line, in lieu of
|
||||
# device-tree properties.
|
||||
EntryArg = namedtuple('EntryArg', ['name', 'datatype'])
|
||||
|
||||
|
||||
class Entry(object):
|
||||
"""An Entry in the section
|
||||
|
||||
|
@ -36,14 +45,15 @@ class Entry(object):
|
|||
Entry.
|
||||
|
||||
Attributes:
|
||||
section: The section containing this entry
|
||||
section: Section object containing this entry
|
||||
node: The node that created this entry
|
||||
pos: Absolute position of entry within the section, None if not known
|
||||
offset: Offset of entry within the section, None if not known yet (in
|
||||
which case it will be calculated by Pack())
|
||||
size: Entry size in bytes, None if not known
|
||||
contents_size: Size of contents in bytes, 0 by default
|
||||
align: Entry start position alignment, or None
|
||||
align: Entry start offset alignment, or None
|
||||
align_size: Entry size alignment, or None
|
||||
align_end: Entry end position alignment, or None
|
||||
align_end: Entry end offset alignment, or None
|
||||
pad_before: Number of pad bytes before the contents, 0 if none
|
||||
pad_after: Number of pad bytes after the contents, 0 if none
|
||||
data: Contents of entry (string of bytes)
|
||||
|
@ -53,34 +63,33 @@ class Entry(object):
|
|||
self.etype = etype
|
||||
self._node = node
|
||||
self.name = node and (name_prefix + node.name) or 'none'
|
||||
self.pos = None
|
||||
self.offset = None
|
||||
self.size = None
|
||||
self.data = ''
|
||||
self.data = None
|
||||
self.contents_size = 0
|
||||
self.align = None
|
||||
self.align_size = None
|
||||
self.align_end = None
|
||||
self.pad_before = 0
|
||||
self.pad_after = 0
|
||||
self.pos_unset = False
|
||||
self.offset_unset = False
|
||||
self.image_pos = None
|
||||
if read_node:
|
||||
self.ReadNode()
|
||||
|
||||
@staticmethod
|
||||
def Create(section, node, etype=None):
|
||||
"""Create a new entry for a node.
|
||||
def Lookup(section, node_path, etype):
|
||||
"""Look up the entry class for a node.
|
||||
|
||||
Args:
|
||||
section: Image object containing this node
|
||||
node: Node object containing information about the entry to create
|
||||
etype: Entry type to use, or None to work it out (used for tests)
|
||||
section: Section object containing this node
|
||||
node_node: Path name of Node object containing information about
|
||||
the entry to create (used for errors)
|
||||
etype: Entry type to use
|
||||
|
||||
Returns:
|
||||
A new Entry object of the correct type (a subclass of Entry)
|
||||
The entry class object if found, else None
|
||||
"""
|
||||
if not etype:
|
||||
etype = fdt_util.GetString(node, 'type', node.name)
|
||||
|
||||
# Convert something like 'u-boot@0' to 'u_boot' since we are only
|
||||
# interested in the type.
|
||||
module_name = etype.replace('-', '_')
|
||||
|
@ -99,15 +108,34 @@ class Entry(object):
|
|||
module = importlib.import_module(module_name)
|
||||
else:
|
||||
module = __import__(module_name)
|
||||
except ImportError:
|
||||
raise ValueError("Unknown entry type '%s' in node '%s'" %
|
||||
(etype, node.path))
|
||||
except ImportError as e:
|
||||
raise ValueError("Unknown entry type '%s' in node '%s' (expected etype/%s.py, error '%s'" %
|
||||
(etype, node_path, module_name, e))
|
||||
finally:
|
||||
sys.path = old_path
|
||||
modules[module_name] = module
|
||||
|
||||
# Look up the expected class name
|
||||
return getattr(module, 'Entry_%s' % module_name)
|
||||
|
||||
@staticmethod
|
||||
def Create(section, node, etype=None):
|
||||
"""Create a new entry for a node.
|
||||
|
||||
Args:
|
||||
section: Section object containing this node
|
||||
node: Node object containing information about the entry to
|
||||
create
|
||||
etype: Entry type to use, or None to work it out (used for tests)
|
||||
|
||||
Returns:
|
||||
A new Entry object of the correct type (a subclass of Entry)
|
||||
"""
|
||||
if not etype:
|
||||
etype = fdt_util.GetString(node, 'type', node.name)
|
||||
obj = Entry.Lookup(section, node.path, etype)
|
||||
|
||||
# Call its constructor to get the object we want.
|
||||
obj = getattr(module, 'Entry_%s' % module_name)
|
||||
return obj(section, etype, node)
|
||||
|
||||
def ReadNode(self):
|
||||
|
@ -115,7 +143,9 @@ class Entry(object):
|
|||
|
||||
This reads all the fields we recognise from the node, ready for use.
|
||||
"""
|
||||
self.pos = fdt_util.GetInt(self._node, 'pos')
|
||||
if 'pos' in self._node.props:
|
||||
self.Raise("Please use 'offset' instead of 'pos'")
|
||||
self.offset = fdt_util.GetInt(self._node, 'offset')
|
||||
self.size = fdt_util.GetInt(self._node, 'size')
|
||||
self.align = fdt_util.GetInt(self._node, 'align')
|
||||
if tools.NotPowerOfTwo(self.align):
|
||||
|
@ -128,18 +158,19 @@ class Entry(object):
|
|||
raise ValueError("Node '%s': Alignment size %s must be a power "
|
||||
"of two" % (self._node.path, self.align_size))
|
||||
self.align_end = fdt_util.GetInt(self._node, 'align-end')
|
||||
self.pos_unset = fdt_util.GetBool(self._node, 'pos-unset')
|
||||
self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
|
||||
|
||||
def AddMissingProperties(self):
|
||||
"""Add new properties to the device tree as needed for this entry"""
|
||||
for prop in ['pos', 'size']:
|
||||
for prop in ['offset', 'size', 'image-pos']:
|
||||
if not prop in self._node.props:
|
||||
self._node.AddZeroProp(prop)
|
||||
|
||||
def SetCalculatedProperties(self):
|
||||
"""Set the value of device-tree properties calculated by binman"""
|
||||
self._node.SetInt('pos', self.pos)
|
||||
self._node.SetInt('offset', self.offset)
|
||||
self._node.SetInt('size', self.size)
|
||||
self._node.SetInt('image-pos', self.image_pos)
|
||||
|
||||
def ProcessFdt(self, fdt):
|
||||
return True
|
||||
|
@ -190,39 +221,39 @@ class Entry(object):
|
|||
# No contents by default: subclasses can implement this
|
||||
return True
|
||||
|
||||
def Pack(self, pos):
|
||||
def Pack(self, offset):
|
||||
"""Figure out how to pack the entry into the section
|
||||
|
||||
Most of the time the entries are not fully specified. There may be
|
||||
an alignment but no size. In that case we take the size from the
|
||||
contents of the entry.
|
||||
|
||||
If an entry has no hard-coded position, it will be placed at @pos.
|
||||
If an entry has no hard-coded offset, it will be placed at @offset.
|
||||
|
||||
Once this function is complete, both the position and size of the
|
||||
Once this function is complete, both the offset and size of the
|
||||
entry will be know.
|
||||
|
||||
Args:
|
||||
Current section position pointer
|
||||
Current section offset pointer
|
||||
|
||||
Returns:
|
||||
New section position pointer (after this entry)
|
||||
New section offset pointer (after this entry)
|
||||
"""
|
||||
if self.pos is None:
|
||||
if self.pos_unset:
|
||||
self.Raise('No position set with pos-unset: should another '
|
||||
'entry provide this correct position?')
|
||||
self.pos = tools.Align(pos, self.align)
|
||||
if self.offset is None:
|
||||
if self.offset_unset:
|
||||
self.Raise('No offset set with offset-unset: should another '
|
||||
'entry provide this correct offset?')
|
||||
self.offset = tools.Align(offset, self.align)
|
||||
needed = self.pad_before + self.contents_size + self.pad_after
|
||||
needed = tools.Align(needed, self.align_size)
|
||||
size = self.size
|
||||
if not size:
|
||||
size = needed
|
||||
new_pos = self.pos + size
|
||||
aligned_pos = tools.Align(new_pos, self.align_end)
|
||||
if aligned_pos != new_pos:
|
||||
size = aligned_pos - self.pos
|
||||
new_pos = aligned_pos
|
||||
new_offset = self.offset + size
|
||||
aligned_offset = tools.Align(new_offset, self.align_end)
|
||||
if aligned_offset != new_offset:
|
||||
size = aligned_offset - self.offset
|
||||
new_offset = aligned_offset
|
||||
|
||||
if not self.size:
|
||||
self.size = size
|
||||
|
@ -231,21 +262,48 @@ class Entry(object):
|
|||
self.Raise("Entry contents size is %#x (%d) but entry size is "
|
||||
"%#x (%d)" % (needed, needed, self.size, self.size))
|
||||
# Check that the alignment is correct. It could be wrong if the
|
||||
# and pos or size values were provided (i.e. not calculated), but
|
||||
# and offset or size values were provided (i.e. not calculated), but
|
||||
# conflict with the provided alignment values
|
||||
if self.size != tools.Align(self.size, self.align_size):
|
||||
self.Raise("Size %#x (%d) does not match align-size %#x (%d)" %
|
||||
(self.size, self.size, self.align_size, self.align_size))
|
||||
if self.pos != tools.Align(self.pos, self.align):
|
||||
self.Raise("Position %#x (%d) does not match align %#x (%d)" %
|
||||
(self.pos, self.pos, self.align, self.align))
|
||||
if self.offset != tools.Align(self.offset, self.align):
|
||||
self.Raise("Offset %#x (%d) does not match align %#x (%d)" %
|
||||
(self.offset, self.offset, self.align, self.align))
|
||||
|
||||
return new_pos
|
||||
return new_offset
|
||||
|
||||
def Raise(self, msg):
|
||||
"""Convenience function to raise an error referencing a node"""
|
||||
raise ValueError("Node '%s': %s" % (self._node.path, msg))
|
||||
|
||||
def GetEntryArgsOrProps(self, props, required=False):
|
||||
"""Return the values of a set of properties
|
||||
|
||||
Args:
|
||||
props: List of EntryArg objects
|
||||
|
||||
Raises:
|
||||
ValueError if a property is not found
|
||||
"""
|
||||
values = []
|
||||
missing = []
|
||||
for prop in props:
|
||||
python_prop = prop.name.replace('-', '_')
|
||||
if hasattr(self, python_prop):
|
||||
value = getattr(self, python_prop)
|
||||
else:
|
||||
value = None
|
||||
if value is None:
|
||||
value = self.GetArg(prop.name, prop.datatype)
|
||||
if value is None and required:
|
||||
missing.append(prop.name)
|
||||
values.append(value)
|
||||
if missing:
|
||||
self.Raise('Missing required properties/entry args: %s' %
|
||||
(', '.join(missing)))
|
||||
return values
|
||||
|
||||
def GetPath(self):
|
||||
"""Get the path of a node
|
||||
|
||||
|
@ -257,13 +315,21 @@ class Entry(object):
|
|||
def GetData(self):
|
||||
return self.data
|
||||
|
||||
def GetPositions(self):
|
||||
def GetOffsets(self):
|
||||
return {}
|
||||
|
||||
def SetPositionSize(self, pos, size):
|
||||
self.pos = pos
|
||||
def SetOffsetSize(self, pos, size):
|
||||
self.offset = pos
|
||||
self.size = size
|
||||
|
||||
def SetImagePos(self, image_pos):
|
||||
"""Set the position in the image
|
||||
|
||||
Args:
|
||||
image_pos: Position of this entry in the image
|
||||
"""
|
||||
self.image_pos = image_pos + self.offset
|
||||
|
||||
def ProcessContents(self):
|
||||
pass
|
||||
|
||||
|
@ -275,15 +341,20 @@ class Entry(object):
|
|||
"""
|
||||
pass
|
||||
|
||||
def CheckPosition(self):
|
||||
"""Check that the entry positions are correct
|
||||
def CheckOffset(self):
|
||||
"""Check that the entry offsets are correct
|
||||
|
||||
This is used for entries which have extra position requirements (other
|
||||
This is used for entries which have extra offset requirements (other
|
||||
than having to be fully inside their section). Sub-classes can implement
|
||||
this function and raise if there is a problem.
|
||||
"""
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def WriteMapLine(fd, indent, name, offset, size, image_pos):
|
||||
print('%08x %s%08x %08x %s' % (image_pos, ' ' * indent, offset,
|
||||
size, name), file=fd)
|
||||
|
||||
def WriteMap(self, fd, indent):
|
||||
"""Write a map of the entry to a .map file
|
||||
|
||||
|
@ -291,5 +362,97 @@ class Entry(object):
|
|||
fd: File to write the map to
|
||||
indent: Curent indent level of map (0=none, 1=one level, etc.)
|
||||
"""
|
||||
print('%s%08x %08x %s' % (' ' * indent, self.pos, self.size,
|
||||
self.name), file=fd)
|
||||
self.WriteMapLine(fd, indent, self.name, self.offset, self.size,
|
||||
self.image_pos)
|
||||
|
||||
def GetEntries(self):
|
||||
"""Return a list of entries contained by this entry
|
||||
|
||||
Returns:
|
||||
List of entries, or None if none. A normal entry has no entries
|
||||
within it so will return None
|
||||
"""
|
||||
return None
|
||||
|
||||
def GetArg(self, name, datatype=str):
|
||||
"""Get the value of an entry argument or device-tree-node property
|
||||
|
||||
Some node properties can be provided as arguments to binman. First check
|
||||
the entry arguments, and fall back to the device tree if not found
|
||||
|
||||
Args:
|
||||
name: Argument name
|
||||
datatype: Data type (str or int)
|
||||
|
||||
Returns:
|
||||
Value of argument as a string or int, or None if no value
|
||||
|
||||
Raises:
|
||||
ValueError if the argument cannot be converted to in
|
||||
"""
|
||||
value = control.GetEntryArg(name)
|
||||
if value is not None:
|
||||
if datatype == int:
|
||||
try:
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
self.Raise("Cannot convert entry arg '%s' (value '%s') to integer" %
|
||||
(name, value))
|
||||
elif datatype == str:
|
||||
pass
|
||||
else:
|
||||
raise ValueError("GetArg() internal error: Unknown data type '%s'" %
|
||||
datatype)
|
||||
else:
|
||||
value = fdt_util.GetDatatype(self._node, name, datatype)
|
||||
return value
|
||||
|
||||
@staticmethod
|
||||
def WriteDocs(modules, test_missing=None):
|
||||
"""Write out documentation about the various entry types to stdout
|
||||
|
||||
Args:
|
||||
modules: List of modules to include
|
||||
test_missing: Used for testing. This is a module to report
|
||||
as missing
|
||||
"""
|
||||
print('''Binman Entry Documentation
|
||||
===========================
|
||||
|
||||
This file describes the entry types supported by binman. These entry types can
|
||||
be placed in an image one by one to build up a final firmware image. It is
|
||||
fairly easy to create new entry types. Just add a new file to the 'etype'
|
||||
directory. You can use the existing entries as examples.
|
||||
|
||||
Note that some entries are subclasses of others, using and extending their
|
||||
features to produce new behaviours.
|
||||
|
||||
|
||||
''')
|
||||
modules = sorted(modules)
|
||||
|
||||
# Don't show the test entry
|
||||
if '_testing' in modules:
|
||||
modules.remove('_testing')
|
||||
missing = []
|
||||
for name in modules:
|
||||
module = Entry.Lookup(name, name, name)
|
||||
docs = getattr(module, '__doc__')
|
||||
if test_missing == name:
|
||||
docs = None
|
||||
if docs:
|
||||
lines = docs.splitlines()
|
||||
first_line = lines[0]
|
||||
rest = [line[4:] for line in lines[1:]]
|
||||
hdr = 'Entry: %s: %s' % (name.replace('_', '-'), first_line)
|
||||
print(hdr)
|
||||
print('-' * len(hdr))
|
||||
print('\n'.join(rest))
|
||||
print()
|
||||
print()
|
||||
else:
|
||||
missing.append(name)
|
||||
|
||||
if missing:
|
||||
raise ValueError('Documentation is missing for modules: %s' %
|
||||
', '.join(missing))
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
# Entry-type module for testing purposes. Not used in real images.
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
from collections import OrderedDict
|
||||
|
||||
from entry import Entry, EntryArg
|
||||
import fdt_util
|
||||
import tools
|
||||
|
||||
|
@ -13,8 +15,30 @@ import tools
|
|||
class Entry__testing(Entry):
|
||||
"""A fake entry used for testing
|
||||
|
||||
This entry should not be used in normal images. It is a special entry with
|
||||
strange features used for testing.
|
||||
|
||||
Properties / Entry arguments
|
||||
test-str-fdt: Test string, normally in the node
|
||||
test-int-fdt: Test integer, normally in the node
|
||||
test-str-arg: Test string, normally in the entry arguments
|
||||
test-int-arg: Test integer, normally in the entry arguments
|
||||
|
||||
The entry has a single 'a' byte as its contents. Operation is controlled by
|
||||
a number of properties in the node, as follows:
|
||||
|
||||
Properties:
|
||||
return_invalid_entry: Return an invalid entry from GetPositions()
|
||||
return-invalid-entry: Return an invalid entry from GetOffsets()
|
||||
return-unknown-contents: Refuse to provide any contents (to cause a
|
||||
failure)
|
||||
bad-update-contents: Implement ProcessContents() incorrectly so as to
|
||||
cause a failure
|
||||
never-complete-process-fdt: Refund to process the FDT (to cause a
|
||||
failure)
|
||||
require-args: Require that all used args are present (generating an
|
||||
error if not)
|
||||
force-bad-datatype: Force a call to GetEntryArgsOrProps() with a bad
|
||||
data type (generating an error)
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry.__init__(self, section, etype, node)
|
||||
|
@ -24,9 +48,26 @@ class Entry__testing(Entry):
|
|||
'return-unknown-contents')
|
||||
self.bad_update_contents = fdt_util.GetBool(self._node,
|
||||
'bad-update-contents')
|
||||
|
||||
# Set to True when the entry is ready to process the FDT.
|
||||
self.process_fdt_ready = False
|
||||
self.never_complete_process_fdt = fdt_util.GetBool(self._node,
|
||||
'never-complete-process-fdt')
|
||||
self.require_args = fdt_util.GetBool(self._node, 'require-args')
|
||||
|
||||
# This should be picked up by GetEntryArgsOrProps()
|
||||
self.test_existing_prop = 'existing'
|
||||
self.force_bad_datatype = fdt_util.GetBool(self._node,
|
||||
'force-bad-datatype')
|
||||
(self.test_str_fdt, self.test_str_arg, self.test_int_fdt,
|
||||
self.test_int_arg, existing) = self.GetEntryArgsOrProps([
|
||||
EntryArg('test-str-fdt', str),
|
||||
EntryArg('test-str-arg', str),
|
||||
EntryArg('test-int-fdt', int),
|
||||
EntryArg('test-int-arg', int),
|
||||
EntryArg('test-existing-prop', str)], self.require_args)
|
||||
if self.force_bad_datatype:
|
||||
self.GetEntryArgsOrProps([EntryArg('test-bad-datatype-arg', bool)])
|
||||
|
||||
def ObtainContents(self):
|
||||
if self.return_unknown_contents:
|
||||
|
@ -35,7 +76,7 @@ class Entry__testing(Entry):
|
|||
self.contents_size = len(self.data)
|
||||
return True
|
||||
|
||||
def GetPositions(self):
|
||||
def GetOffsets(self):
|
||||
if self.return_invalid_entry :
|
||||
return {'invalid-entry': [1, 2]}
|
||||
return {}
|
||||
|
|
|
@ -10,6 +10,18 @@ import fdt_util
|
|||
import tools
|
||||
|
||||
class Entry_blob(Entry):
|
||||
"""Entry containing an arbitrary binary blob
|
||||
|
||||
Note: This should not be used by itself. It is normally used as a parent
|
||||
class by other entry types.
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of file to read into entry
|
||||
|
||||
This entry reads data from a file and places it in the entry. The
|
||||
default filename is often specified specified by the subclass. See for
|
||||
example the 'u_boot' entry which provides the filename 'u-boot.bin'.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry.__init__(self, section, etype, node)
|
||||
self._filename = fdt_util.GetString(self._node, "filename", self.etype)
|
||||
|
@ -17,10 +29,10 @@ class Entry_blob(Entry):
|
|||
def ObtainContents(self):
|
||||
self._filename = self.GetDefaultFilename()
|
||||
self._pathname = tools.GetInputFilename(self._filename)
|
||||
self.ReadContents()
|
||||
self.ReadBlobContents()
|
||||
return True
|
||||
|
||||
def ReadContents(self):
|
||||
def ReadBlobContents(self):
|
||||
with open(self._pathname) as fd:
|
||||
# We assume the data is small enough to fit into memory. If this
|
||||
# is used for large filesystem image that might not be true.
|
||||
|
|
34
tools/binman/etype/blob_named_by_arg.py
Normal file
34
tools/binman/etype/blob_named_by_arg.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2018 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# Entry-type module for a blob where the filename comes from a property in the
|
||||
# node or an entry argument. The property is called '<blob_fname>-path' where
|
||||
# <blob_fname> is provided by the subclass using this entry type.
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from blob import Entry_blob
|
||||
from entry import EntryArg
|
||||
|
||||
|
||||
class Entry_blob_named_by_arg(Entry_blob):
|
||||
"""A blob entry which gets its filename property from its subclass
|
||||
|
||||
Properties / Entry arguments:
|
||||
- <xxx>-path: Filename containing the contents of this entry (optional,
|
||||
defaults to 0)
|
||||
|
||||
where <xxx> is the blob_fname argument to the constructor.
|
||||
|
||||
This entry cannot be used directly. Instead, it is used as a parent class
|
||||
for another entry, which defined blob_fname. This parameter is used to
|
||||
set the entry-arg or property containing the filename. The entry-arg or
|
||||
property is in turn used to set the actual filename.
|
||||
|
||||
See cros_ec_rw for an example of this.
|
||||
"""
|
||||
def __init__(self, section, etype, node, blob_fname):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
self._filename, = self.GetEntryArgsOrProps(
|
||||
[EntryArg('%s-path' % blob_fname, str)])
|
22
tools/binman/etype/cros_ec_rw.py
Normal file
22
tools/binman/etype/cros_ec_rw.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2018 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# Entry-type module for a Chromium OS EC image (read-write section)
|
||||
#
|
||||
|
||||
from blob_named_by_arg import Entry_blob_named_by_arg
|
||||
|
||||
|
||||
class Entry_cros_ec_rw(Entry_blob_named_by_arg):
|
||||
"""A blob entry which contains a Chromium OS read-write EC image
|
||||
|
||||
Properties / Entry arguments:
|
||||
- cros-ec-rw-path: Filename containing the EC image
|
||||
|
||||
This entry holds a Chromium OS EC (embedded controller) image, for use in
|
||||
updating the EC on startup via software sync.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob_named_by_arg.__init__(self, section, etype, node,
|
||||
'cros-ec-rw')
|
32
tools/binman/etype/fill.py
Normal file
32
tools/binman/etype/fill.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2018 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
import fdt_util
|
||||
|
||||
|
||||
class Entry_fill(Entry):
|
||||
"""An entry which is filled to a particular byte value
|
||||
|
||||
Properties / Entry arguments:
|
||||
- fill-byte: Byte to use to fill the entry
|
||||
|
||||
Note that the size property must be set since otherwise this entry does not
|
||||
know how large it should be.
|
||||
|
||||
You can often achieve the same effect using the pad-byte property of the
|
||||
overall image, in that the space between entries will then be padded with
|
||||
that byte. But this entry is sometimes useful for explicitly setting the
|
||||
byte value of a region.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry.__init__(self, section, etype, node)
|
||||
if not self.size:
|
||||
self.Raise("'fill' entry must have a size property")
|
||||
self.fill_value = fdt_util.GetByte(self._node, 'fill-byte', 0)
|
||||
|
||||
def ObtainContents(self):
|
||||
self.SetContents(chr(self.fill_value) * self.size)
|
||||
return True
|
61
tools/binman/etype/fmap.py
Normal file
61
tools/binman/etype/fmap.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2018 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# Entry-type module for a Flash map, as used by the flashrom SPI flash tool
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
import fmap_util
|
||||
|
||||
|
||||
class Entry_fmap(Entry):
|
||||
"""An entry which contains an Fmap section
|
||||
|
||||
Properties / Entry arguments:
|
||||
None
|
||||
|
||||
FMAP is a simple format used by flashrom, an open-source utility for
|
||||
reading and writing the SPI flash, typically on x86 CPUs. The format
|
||||
provides flashrom with a list of areas, so it knows what it in the flash.
|
||||
It can then read or write just a single area, instead of the whole flash.
|
||||
|
||||
The format is defined by the flashrom project, in the file lib/fmap.h -
|
||||
see www.flashrom.org/Flashrom for more information.
|
||||
|
||||
When used, this entry will be populated with an FMAP which reflects the
|
||||
entries in the current image. Note that any hierarchy is squashed, since
|
||||
FMAP does not support this.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry.__init__(self, section, etype, node)
|
||||
|
||||
def _GetFmap(self):
|
||||
"""Build an FMAP from the entries in the current image
|
||||
|
||||
Returns:
|
||||
FMAP binary data
|
||||
"""
|
||||
def _AddEntries(areas, entry):
|
||||
entries = entry.GetEntries()
|
||||
if entries:
|
||||
for subentry in entries.values():
|
||||
_AddEntries(areas, subentry)
|
||||
else:
|
||||
areas.append(fmap_util.FmapArea(entry.image_pos or 0,
|
||||
entry.size or 0, entry.name, 0))
|
||||
|
||||
entries = self.section.GetEntries()
|
||||
areas = []
|
||||
for entry in entries.values():
|
||||
_AddEntries(areas, entry)
|
||||
return fmap_util.EncodeFmap(self.section.GetSize() or 0, self.name,
|
||||
areas)
|
||||
|
||||
def ObtainContents(self):
|
||||
"""Obtain a placeholder for the fmap contents"""
|
||||
self.SetContents(self._GetFmap())
|
||||
return True
|
||||
|
||||
def ProcessContents(self):
|
||||
self.SetContents(self._GetFmap())
|
96
tools/binman/etype/gbb.py
Normal file
96
tools/binman/etype/gbb.py
Normal file
|
@ -0,0 +1,96 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2018 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
|
||||
# Support for a Chromium OS Google Binary Block, used to record read-only
|
||||
# information mostly used by firmware.
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
import command
|
||||
from entry import Entry, EntryArg
|
||||
|
||||
import fdt_util
|
||||
import tools
|
||||
|
||||
# Build GBB flags.
|
||||
# (src/platform/vboot_reference/firmware/include/gbb_header.h)
|
||||
gbb_flag_properties = {
|
||||
'dev-screen-short-delay': 0x1,
|
||||
'load-option-roms': 0x2,
|
||||
'enable-alternate-os': 0x4,
|
||||
'force-dev-switch-on': 0x8,
|
||||
'force-dev-boot-usb': 0x10,
|
||||
'disable-fw-rollback-check': 0x20,
|
||||
'enter-triggers-tonorm': 0x40,
|
||||
'force-dev-boot-legacy': 0x80,
|
||||
'faft-key-override': 0x100,
|
||||
'disable-ec-software-sync': 0x200,
|
||||
'default-dev-boot-legacy': 0x400,
|
||||
'disable-pd-software-sync': 0x800,
|
||||
'disable-lid-shutdown': 0x1000,
|
||||
'force-dev-boot-fastboot-full-cap': 0x2000,
|
||||
'enable-serial': 0x4000,
|
||||
'disable-dwmp': 0x8000,
|
||||
}
|
||||
|
||||
|
||||
class Entry_gbb(Entry):
|
||||
"""An entry which contains a Chromium OS Google Binary Block
|
||||
|
||||
Properties / Entry arguments:
|
||||
- hardware-id: Hardware ID to use for this build (a string)
|
||||
- keydir: Directory containing the public keys to use
|
||||
- bmpblk: Filename containing images used by recovery
|
||||
|
||||
Chromium OS uses a GBB to store various pieces of information, in particular
|
||||
the root and recovery keys that are used to verify the boot process. Some
|
||||
more details are here:
|
||||
|
||||
https://www.chromium.org/chromium-os/firmware-porting-guide/2-concepts
|
||||
|
||||
but note that the page dates from 2013 so is quite out of date. See
|
||||
README.chromium for how to obtain the required keys and tools.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry.__init__(self, section, etype, node)
|
||||
self.hardware_id, self.keydir, self.bmpblk = self.GetEntryArgsOrProps(
|
||||
[EntryArg('hardware-id', str),
|
||||
EntryArg('keydir', str),
|
||||
EntryArg('bmpblk', str)])
|
||||
|
||||
# Read in the GBB flags from the config
|
||||
self.gbb_flags = 0
|
||||
flags_node = node.FindNode('flags')
|
||||
if flags_node:
|
||||
for flag, value in gbb_flag_properties.iteritems():
|
||||
if fdt_util.GetBool(flags_node, flag):
|
||||
self.gbb_flags |= value
|
||||
|
||||
def ObtainContents(self):
|
||||
gbb = 'gbb.bin'
|
||||
fname = tools.GetOutputFilename(gbb)
|
||||
if not self.size:
|
||||
self.Raise('GBB must have a fixed size')
|
||||
gbb_size = self.size
|
||||
bmpfv_size = gbb_size - 0x2180
|
||||
if bmpfv_size < 0:
|
||||
self.Raise('GBB is too small (minimum 0x2180 bytes)')
|
||||
sizes = [0x100, 0x1000, bmpfv_size, 0x1000]
|
||||
sizes = ['%#x' % size for size in sizes]
|
||||
keydir = tools.GetInputFilename(self.keydir)
|
||||
gbb_set_command = [
|
||||
'gbb_utility', '-s',
|
||||
'--hwid=%s' % self.hardware_id,
|
||||
'--rootkey=%s/root_key.vbpubk' % keydir,
|
||||
'--recoverykey=%s/recovery_key.vbpubk' % keydir,
|
||||
'--flags=%d' % self.gbb_flags,
|
||||
'--bmpfv=%s' % tools.GetInputFilename(self.bmpblk),
|
||||
fname]
|
||||
|
||||
tools.Run('futility', 'gbb_utility', '-c', ','.join(sizes), fname)
|
||||
tools.Run('futility', *gbb_set_command)
|
||||
|
||||
self.SetContents(tools.ReadFile(fname))
|
||||
return True
|
|
@ -9,5 +9,15 @@ from entry import Entry
|
|||
from blob import Entry_blob
|
||||
|
||||
class Entry_intel_cmc(Entry_blob):
|
||||
"""Entry containing an Intel Chipset Micro Code (CMC) file
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of file to read into entry
|
||||
|
||||
This file contains microcode for some devices in a special format. An
|
||||
example filename is 'Microcode/C0_22211.BIN'.
|
||||
|
||||
See README.x86 for information about x86 binary blobs.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
|
|
|
@ -13,6 +13,7 @@ from blob import Entry_blob
|
|||
FD_SIGNATURE = struct.pack('<L', 0x0ff0a55a)
|
||||
MAX_REGIONS = 5
|
||||
|
||||
# Region numbers supported by the Intel firmware format
|
||||
(REGION_DESCRIPTOR, REGION_BIOS, REGION_ME, REGION_GBE,
|
||||
REGION_PDATA) = range(5)
|
||||
|
||||
|
@ -27,21 +28,32 @@ class Region:
|
|||
class Entry_intel_descriptor(Entry_blob):
|
||||
"""Intel flash descriptor block (4KB)
|
||||
|
||||
This is placed at the start of flash and provides information about
|
||||
Properties / Entry arguments:
|
||||
filename: Filename of file containing the descriptor. This is typically
|
||||
a 4KB binary file, sometimes called 'descriptor.bin'
|
||||
|
||||
This entry is placed at the start of flash and provides information about
|
||||
the SPI flash regions. In particular it provides the base address and
|
||||
size of the ME region, allowing us to place the ME binary in the right
|
||||
place.
|
||||
size of the ME (Management Engine) region, allowing us to place the ME
|
||||
binary in the right place.
|
||||
|
||||
With this entry in your image, the position of the 'intel-me' entry will be
|
||||
fixed in the image, which avoids you needed to specify an offset for that
|
||||
region. This is useful, because it is not possible to change the position
|
||||
of the ME region without updating the descriptor.
|
||||
|
||||
See README.x86 for information about x86 binary blobs.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
self._regions = []
|
||||
|
||||
def GetPositions(self):
|
||||
pos = self.data.find(FD_SIGNATURE)
|
||||
if pos == -1:
|
||||
def GetOffsets(self):
|
||||
offset = self.data.find(FD_SIGNATURE)
|
||||
if offset == -1:
|
||||
self.Raise('Cannot find FD signature')
|
||||
flvalsig, flmap0, flmap1, flmap2 = struct.unpack('<LLLL',
|
||||
self.data[pos:pos + 16])
|
||||
self.data[offset:offset + 16])
|
||||
frba = ((flmap0 >> 16) & 0xff) << 4
|
||||
for i in range(MAX_REGIONS):
|
||||
self._regions.append(Region(self.data, frba, i))
|
||||
|
|
|
@ -9,5 +9,19 @@ from entry import Entry
|
|||
from blob import Entry_blob
|
||||
|
||||
class Entry_intel_fsp(Entry_blob):
|
||||
"""Entry containing an Intel Firmware Support Package (FSP) file
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of file to read into entry
|
||||
|
||||
This file contains binary blobs which are used on some devices to make the
|
||||
platform work. U-Boot executes this code since it is not possible to set up
|
||||
the hardware using U-Boot open-source code. Documentation is typically not
|
||||
available in sufficient detail to allow this.
|
||||
|
||||
An example filename is 'FSP/QUEENSBAY_FSP_GOLD_001_20-DECEMBER-2013.fd'
|
||||
|
||||
See README.x86 for information about x86 binary blobs.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
|
|
|
@ -9,5 +9,20 @@ from entry import Entry
|
|||
from blob import Entry_blob
|
||||
|
||||
class Entry_intel_me(Entry_blob):
|
||||
"""Entry containing an Intel Management Engine (ME) file
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of file to read into entry
|
||||
|
||||
This file contains code used by the SoC that is required to make it work.
|
||||
The Management Engine is like a background task that runs things that are
|
||||
not clearly documented, but may include keyboard, deplay and network
|
||||
access. For platform that use ME it is not possible to disable it. U-Boot
|
||||
does not directly execute code in the ME binary.
|
||||
|
||||
A typical filename is 'me.bin'.
|
||||
|
||||
See README.x86 for information about x86 binary blobs.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
|
|
|
@ -9,6 +9,17 @@ from entry import Entry
|
|||
from blob import Entry_blob
|
||||
|
||||
class Entry_intel_mrc(Entry_blob):
|
||||
"""Entry containing an Intel Memory Reference Code (MRC) file
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of file to read into entry
|
||||
|
||||
This file contains code for setting up the SDRAM on some Intel systems. This
|
||||
is executed by U-Boot when needed early during startup. A typical filename
|
||||
is 'mrc.bin'.
|
||||
|
||||
See README.x86 for information about x86 binary blobs.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
|
||||
|
|
|
@ -8,5 +8,15 @@ from entry import Entry
|
|||
from blob import Entry_blob
|
||||
|
||||
class Entry_intel_vbt(Entry_blob):
|
||||
"""Entry containing an Intel Video BIOS Table (VBT) file
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of file to read into entry
|
||||
|
||||
This file contains code that sets up the integrated graphics subsystem on
|
||||
some Intel SoCs. U-Boot executes this when the display is started up.
|
||||
|
||||
See README.x86 for information about Intel binary blobs.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
|
|
|
@ -9,5 +9,17 @@ from entry import Entry
|
|||
from blob import Entry_blob
|
||||
|
||||
class Entry_intel_vga(Entry_blob):
|
||||
"""Entry containing an Intel Video Graphics Adaptor (VGA) file
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of file to read into entry
|
||||
|
||||
This file contains code that sets up the integrated graphics subsystem on
|
||||
some Intel SoCs. U-Boot executes this when the display is started up.
|
||||
|
||||
This is similar to the VBT file but in a different format.
|
||||
|
||||
See README.x86 for information about Intel binary blobs.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
|
|
|
@ -13,8 +13,25 @@ import tools
|
|||
import bsection
|
||||
|
||||
class Entry_section(Entry):
|
||||
def __init__(self, image, etype, node):
|
||||
Entry.__init__(self, image, etype, node)
|
||||
"""Entry that contains other entries
|
||||
|
||||
Properties / Entry arguments: (see binman README for more information)
|
||||
- size: Size of section in bytes
|
||||
- align-size: Align size to a particular power of two
|
||||
- pad-before: Add padding before the entry
|
||||
- pad-after: Add padding after the entry
|
||||
- pad-byte: Pad byte to use when padding
|
||||
- sort-by-offset: Reorder the entries by offset
|
||||
- end-at-4gb: Used to build an x86 ROM which ends at 4GB (2^32)
|
||||
- name-prefix: Adds a prefix to the name of every entry in the section
|
||||
when writing out the map
|
||||
|
||||
A section is an entry which can contain other entries, thus allowing
|
||||
hierarchical images to be created. See 'Sections and hierarchical images'
|
||||
in the binman README for more information.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry.__init__(self, section, etype, node)
|
||||
self._section = bsection.Section(node.name, node)
|
||||
|
||||
def ProcessFdt(self, fdt):
|
||||
|
@ -30,20 +47,25 @@ class Entry_section(Entry):
|
|||
def GetData(self):
|
||||
return self._section.GetData()
|
||||
|
||||
def GetPositions(self):
|
||||
"""Handle entries that want to set the position/size of other entries
|
||||
def GetOffsets(self):
|
||||
"""Handle entries that want to set the offset/size of other entries
|
||||
|
||||
This calls each entry's GetPositions() method. If it returns a list
|
||||
This calls each entry's GetOffsets() method. If it returns a list
|
||||
of entries to update, it updates them.
|
||||
"""
|
||||
self._section.GetEntryPositions()
|
||||
self._section.GetEntryOffsets()
|
||||
return {}
|
||||
|
||||
def Pack(self, pos):
|
||||
def Pack(self, offset):
|
||||
"""Pack all entries into the section"""
|
||||
self._section.PackEntries()
|
||||
self.size = self._section.CheckSize()
|
||||
return super(Entry_section, self).Pack(pos)
|
||||
self._section.SetOffset(offset)
|
||||
self.size = self._section.GetSize()
|
||||
return super(Entry_section, self).Pack(offset)
|
||||
|
||||
def SetImagePos(self, image_pos):
|
||||
Entry.SetImagePos(self, image_pos)
|
||||
self._section.SetImagePos(image_pos + self.offset)
|
||||
|
||||
def WriteSymbols(self, section):
|
||||
"""Write symbol values into binary files for access at run time"""
|
||||
|
@ -57,7 +79,7 @@ class Entry_section(Entry):
|
|||
self._section.ProcessEntryContents()
|
||||
super(Entry_section, self).ProcessContents()
|
||||
|
||||
def CheckPosition(self):
|
||||
def CheckOffset(self):
|
||||
self._section.CheckEntries()
|
||||
|
||||
def WriteMap(self, fd, indent):
|
||||
|
@ -66,5 +88,7 @@ class Entry_section(Entry):
|
|||
Args:
|
||||
fd: File to write the map to
|
||||
"""
|
||||
super(Entry_section, self).WriteMap(fd, indent)
|
||||
self._section.WriteMap(fd, indent + 1)
|
||||
self._section.WriteMap(fd, indent)
|
||||
|
||||
def GetEntries(self):
|
||||
return self._section.GetEntries()
|
||||
|
|
57
tools/binman/etype/text.py
Normal file
57
tools/binman/etype/text.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2018 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from entry import Entry, EntryArg
|
||||
import fdt_util
|
||||
|
||||
|
||||
class Entry_text(Entry):
|
||||
"""An entry which contains text
|
||||
|
||||
The text can be provided either in the node itself or by a command-line
|
||||
argument. There is a level of indirection to allow multiple text strings
|
||||
and sharing of text.
|
||||
|
||||
Properties / Entry arguments:
|
||||
text-label: The value of this string indicates the property / entry-arg
|
||||
that contains the string to place in the entry
|
||||
<xxx> (actual name is the value of text-label): contains the string to
|
||||
place in the entry.
|
||||
|
||||
Example node:
|
||||
|
||||
text {
|
||||
size = <50>;
|
||||
text-label = "message";
|
||||
};
|
||||
|
||||
You can then use:
|
||||
|
||||
binman -amessage="this is my message"
|
||||
|
||||
and binman will insert that string into the entry.
|
||||
|
||||
It is also possible to put the string directly in the node:
|
||||
|
||||
text {
|
||||
size = <8>;
|
||||
text-label = "message";
|
||||
message = "a message directly in the node"
|
||||
};
|
||||
|
||||
The text is not itself nul-terminated. This can be achieved, if required,
|
||||
by setting the size of the entry to something larger than the text.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry.__init__(self, section, etype, node)
|
||||
self.text_label, = self.GetEntryArgsOrProps(
|
||||
[EntryArg('text-label', str)])
|
||||
self.value, = self.GetEntryArgsOrProps([EntryArg(self.text_label, str)])
|
||||
|
||||
def ObtainContents(self):
|
||||
self.SetContents(self.value)
|
||||
return True
|
|
@ -9,6 +9,22 @@ from entry import Entry
|
|||
from blob import Entry_blob
|
||||
|
||||
class Entry_u_boot(Entry_blob):
|
||||
"""U-Boot flat binary
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot.bin (default 'u-boot.bin')
|
||||
|
||||
This is the U-Boot binary, containing relocation information to allow it
|
||||
to relocate itself at runtime. The binary typically includes a device tree
|
||||
blob at the end of it. Use u_boot_nodtb if you want to package the device
|
||||
tree separately.
|
||||
|
||||
U-Boot can access binman symbols at runtime. See:
|
||||
|
||||
'Access to binman entry offsets at run time (fdt)'
|
||||
|
||||
in the binman README for more information.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
|
||||
|
|
|
@ -9,6 +9,15 @@ from entry import Entry
|
|||
from blob import Entry_blob
|
||||
|
||||
class Entry_u_boot_dtb(Entry_blob):
|
||||
"""U-Boot device tree
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot.dtb (default 'u-boot.dtb')
|
||||
|
||||
This is the U-Boot device tree, containing configuration information for
|
||||
U-Boot. U-Boot needs this to know what devices are present and which drivers
|
||||
to activate.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#
|
||||
|
||||
import control
|
||||
import fdt
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
import tools
|
||||
|
@ -14,8 +13,16 @@ import tools
|
|||
class Entry_u_boot_dtb_with_ucode(Entry_blob):
|
||||
"""A U-Boot device tree file, with the microcode removed
|
||||
|
||||
See Entry_u_boot_ucode for full details of the 3 entries involved in this
|
||||
process.
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot.dtb (default 'u-boot.dtb')
|
||||
|
||||
See Entry_u_boot_ucode for full details of the three entries involved in
|
||||
this process. This entry provides the U-Boot device-tree file, which
|
||||
contains the microcode. If the microcode is not being collated into one
|
||||
place then the offset and size of the microcode is recorded by this entry,
|
||||
for use by u_boot_with_ucode_ptr. If it is being collated, then this
|
||||
entry deletes the microcode from the device tree (to save space) and makes
|
||||
it available to u_boot_ucode.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
|
@ -30,13 +37,16 @@ class Entry_u_boot_dtb_with_ucode(Entry_blob):
|
|||
return 'u-boot.dtb'
|
||||
|
||||
def ProcessFdt(self, fdt):
|
||||
# So the module can be loaded without it
|
||||
import fdt
|
||||
|
||||
# If the section does not need microcode, there is nothing to do
|
||||
ucode_dest_entry = self.section.FindEntryType(
|
||||
'u-boot-spl-with-ucode-ptr')
|
||||
if not ucode_dest_entry or not ucode_dest_entry.target_pos:
|
||||
if not ucode_dest_entry or not ucode_dest_entry.target_offset:
|
||||
ucode_dest_entry = self.section.FindEntryType(
|
||||
'u-boot-with-ucode-ptr')
|
||||
if not ucode_dest_entry or not ucode_dest_entry.target_pos:
|
||||
if not ucode_dest_entry or not ucode_dest_entry.target_offset:
|
||||
return True
|
||||
|
||||
# Remove the microcode
|
||||
|
@ -61,7 +71,7 @@ class Entry_u_boot_dtb_with_ucode(Entry_blob):
|
|||
# Call the base class just in case it does something important.
|
||||
Entry_blob.ObtainContents(self)
|
||||
self._pathname = control.GetFdtPath(self._filename)
|
||||
self.ReadContents()
|
||||
self.ReadBlobContents()
|
||||
if self.ucode:
|
||||
for node in self.ucode.subnodes:
|
||||
data_prop = node.props.get('data')
|
||||
|
|
|
@ -9,6 +9,17 @@ from entry import Entry
|
|||
from blob import Entry_blob
|
||||
|
||||
class Entry_u_boot_img(Entry_blob):
|
||||
"""U-Boot legacy image
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot.img (default 'u-boot.img')
|
||||
|
||||
This is the U-Boot binary as a packaged image, in legacy format. It has a
|
||||
header which allows it to be loaded at the correct address for execution.
|
||||
|
||||
You should use FIT (Flat Image Tree) instead of the legacy image for new
|
||||
applications.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
|
||||
|
|
|
@ -9,6 +9,17 @@ from entry import Entry
|
|||
from blob import Entry_blob
|
||||
|
||||
class Entry_u_boot_nodtb(Entry_blob):
|
||||
"""U-Boot flat binary without device tree appended
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot.bin (default 'u-boot-nodtb.bin')
|
||||
|
||||
This is the U-Boot binary, containing relocation information to allow it
|
||||
to relocate itself at runtime. It does not include a device tree blob at
|
||||
the end of it so normally cannot work without it. You can add a u_boot_dtb
|
||||
entry after this one, or use a u_boot entry instead (which contains both
|
||||
U-Boot and the device tree).
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
|
||||
|
|
|
@ -11,6 +11,27 @@ from entry import Entry
|
|||
from blob import Entry_blob
|
||||
|
||||
class Entry_u_boot_spl(Entry_blob):
|
||||
"""U-Boot SPL binary
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot-spl.bin (default 'spl/u-boot-spl.bin')
|
||||
|
||||
This is the U-Boot SPL (Secondary Program Loader) binary. This is a small
|
||||
binary which loads before U-Boot proper, typically into on-chip SRAM. It is
|
||||
responsible for locating, loading and jumping to U-Boot. Note that SPL is
|
||||
not relocatable so must be loaded to the correct address in SRAM, or written
|
||||
to run from the correct address if direct flash execution is possible (e.g.
|
||||
on x86 devices).
|
||||
|
||||
SPL can access binman symbols at runtime. See:
|
||||
|
||||
'Access to binman entry offsets at run time (symbols)'
|
||||
|
||||
in the binman README for more information.
|
||||
|
||||
The ELF file 'spl/u-boot-spl' must also be available for this to work, since
|
||||
binman uses that to look up symbols to write into the SPL binary.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
self.elf_fname = 'spl/u-boot-spl'
|
||||
|
|
|
@ -14,6 +14,22 @@ from blob import Entry_blob
|
|||
import tools
|
||||
|
||||
class Entry_u_boot_spl_bss_pad(Entry_blob):
|
||||
"""U-Boot SPL binary padded with a BSS region
|
||||
|
||||
Properties / Entry arguments:
|
||||
None
|
||||
|
||||
This is similar to u_boot_spl except that padding is added after the SPL
|
||||
binary to cover the BSS (Block Started by Symbol) region. This region holds
|
||||
the various used by SPL. It is set to 0 by SPL when it starts up. If you
|
||||
want to append data to the SPL image (such as a device tree file), you must
|
||||
pad out the BSS region to avoid the data overlapping with U-Boot variables.
|
||||
This entry is useful in that case. It automatically pads out the entry size
|
||||
to cover both the code, data and BSS.
|
||||
|
||||
The ELF file 'spl/u-boot-spl' must also be available for this to work, since
|
||||
binman uses that to look up the BSS address.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
|
||||
|
|
|
@ -2,13 +2,22 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# Entry-type module for U-Boot device tree
|
||||
# Entry-type module for U-Boot device tree in SPL (Secondary Program Loader)
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
|
||||
class Entry_u_boot_spl_dtb(Entry_blob):
|
||||
"""U-Boot SPL device tree
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot.dtb (default 'spl/u-boot-spl.dtb')
|
||||
|
||||
This is the SPL device tree, containing configuration information for
|
||||
SPL. SPL needs this to know what devices are present and which drivers
|
||||
to activate.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
|
||||
|
|
|
@ -9,6 +9,18 @@ from entry import Entry
|
|||
from blob import Entry_blob
|
||||
|
||||
class Entry_u_boot_spl_nodtb(Entry_blob):
|
||||
"""SPL binary without device tree appended
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of spl/u-boot-spl-nodtb.bin (default
|
||||
'spl/u-boot-spl-nodtb.bin')
|
||||
|
||||
This is the U-Boot SPL binary, It does not include a device tree blob at
|
||||
the end of it so may not be able to work without it, assuming SPL needs
|
||||
a device tree to operation on your platform. You can add a u_boot_spl_dtb
|
||||
entry after this one, or use a u_boot_spl entry instead (which contains
|
||||
both SPL and the device tree).
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
|
||||
|
|
43
tools/binman/etype/u_boot_tpl.py
Normal file
43
tools/binman/etype/u_boot_tpl.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# Entry-type module for tpl/u-boot-tpl.bin
|
||||
#
|
||||
|
||||
import elf
|
||||
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
|
||||
class Entry_u_boot_tpl(Entry_blob):
|
||||
"""U-Boot TPL binary
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot-tpl.bin (default 'tpl/u-boot-tpl.bin')
|
||||
|
||||
This is the U-Boot TPL (Tertiary Program Loader) binary. This is a small
|
||||
binary which loads before SPL, typically into on-chip SRAM. It is
|
||||
responsible for locating, loading and jumping to SPL, the next-stage
|
||||
loader. Note that SPL is not relocatable so must be loaded to the correct
|
||||
address in SRAM, or written to run from the correct address if direct
|
||||
flash execution is possible (e.g. on x86 devices).
|
||||
|
||||
SPL can access binman symbols at runtime. See:
|
||||
|
||||
'Access to binman entry offsets at run time (symbols)'
|
||||
|
||||
in the binman README for more information.
|
||||
|
||||
The ELF file 'tpl/u-boot-tpl' must also be available for this to work, since
|
||||
binman uses that to look up symbols to write into the TPL binary.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
self.elf_fname = 'tpl/u-boot-tpl'
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'tpl/u-boot-tpl.bin'
|
||||
|
||||
def WriteSymbols(self, section):
|
||||
elf.LookupAndWriteSymbols(self.elf_fname, self, section)
|
25
tools/binman/etype/u_boot_tpl_dtb.py
Normal file
25
tools/binman/etype/u_boot_tpl_dtb.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2018 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# Entry-type module for U-Boot device tree in TPL (Tertiary Program Loader)
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
|
||||
class Entry_u_boot_tpl_dtb(Entry_blob):
|
||||
"""U-Boot TPL device tree
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot.dtb (default 'tpl/u-boot-tpl.dtb')
|
||||
|
||||
This is the TPL device tree, containing configuration information for
|
||||
TPL. TPL needs this to know what devices are present and which drivers
|
||||
to activate.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'tpl/u-boot-tpl.dtb'
|
|
@ -12,6 +12,12 @@ import tools
|
|||
class Entry_u_boot_ucode(Entry_blob):
|
||||
"""U-Boot microcode block
|
||||
|
||||
Properties / Entry arguments:
|
||||
None
|
||||
|
||||
The contents of this entry are filled in automatically by other entries
|
||||
which must also be in the image.
|
||||
|
||||
U-Boot on x86 needs a single block of microcode. This is collected from
|
||||
the various microcode update nodes in the device tree. It is also unable
|
||||
to read the microcode from the device tree on platforms that use FSP
|
||||
|
@ -59,8 +65,8 @@ class Entry_u_boot_ucode(Entry_blob):
|
|||
ucode_dest_entry = self.section.FindEntryType('u-boot-with-ucode-ptr')
|
||||
ucode_dest_entry_spl = self.section.FindEntryType(
|
||||
'u-boot-spl-with-ucode-ptr')
|
||||
if ((not ucode_dest_entry or not ucode_dest_entry.target_pos) and
|
||||
(not ucode_dest_entry_spl or not ucode_dest_entry_spl.target_pos)):
|
||||
if ((not ucode_dest_entry or not ucode_dest_entry.target_offset) and
|
||||
(not ucode_dest_entry_spl or not ucode_dest_entry_spl.target_offset)):
|
||||
self.data = ''
|
||||
return True
|
||||
|
||||
|
@ -86,6 +92,6 @@ class Entry_u_boot_ucode(Entry_blob):
|
|||
fd.write(fdt_entry.ucode_data)
|
||||
|
||||
self._pathname = fname
|
||||
self.ReadContents()
|
||||
self.ReadBlobContents()
|
||||
|
||||
return True
|
||||
|
|
|
@ -17,13 +17,18 @@ import tools
|
|||
class Entry_u_boot_with_ucode_ptr(Entry_blob):
|
||||
"""U-Boot with embedded microcode pointer
|
||||
|
||||
See Entry_u_boot_ucode for full details of the 3 entries involved in this
|
||||
process.
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot-nodtb.dtb (default 'u-boot-nodtb.dtb')
|
||||
|
||||
See Entry_u_boot_ucode for full details of the three entries involved in
|
||||
this process. This entry updates U-Boot with the offset and size of the
|
||||
microcode, to allow early x86 boot code to find it without doing anything
|
||||
complicated. Otherwise it is the same as the u_boot entry.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
self.elf_fname = 'u-boot'
|
||||
self.target_pos = None
|
||||
self.target_offset = None
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'u-boot-nodtb.bin'
|
||||
|
@ -33,52 +38,53 @@ class Entry_u_boot_with_ucode_ptr(Entry_blob):
|
|||
fname = tools.GetInputFilename(self.elf_fname)
|
||||
sym = elf.GetSymbolAddress(fname, '_dt_ucode_base_size')
|
||||
if sym:
|
||||
self.target_pos = sym
|
||||
self.target_offset = sym
|
||||
elif not fdt_util.GetBool(self._node, 'optional-ucode'):
|
||||
self.Raise('Cannot locate _dt_ucode_base_size symbol in u-boot')
|
||||
return True
|
||||
|
||||
def ProcessContents(self):
|
||||
# If the image does not need microcode, there is nothing to do
|
||||
if not self.target_pos:
|
||||
if not self.target_offset:
|
||||
return
|
||||
|
||||
# Get the position of the microcode
|
||||
# Get the offset of the microcode
|
||||
ucode_entry = self.section.FindEntryType('u-boot-ucode')
|
||||
if not ucode_entry:
|
||||
self.Raise('Cannot find microcode region u-boot-ucode')
|
||||
|
||||
# Check the target pos is in the section. If it is not, then U-Boot is
|
||||
# being linked incorrectly, or is being placed at the wrong position
|
||||
# being linked incorrectly, or is being placed at the wrong offset
|
||||
# in the section.
|
||||
#
|
||||
# The section must be set up so that U-Boot is placed at the
|
||||
# flash address to which it is linked. For example, if
|
||||
# CONFIG_SYS_TEXT_BASE is 0xfff00000, and the ROM is 8MB, then
|
||||
# the U-Boot region must start at position 7MB in the section. In this
|
||||
# case the ROM starts at 0xff800000, so the position of the first
|
||||
# the U-Boot region must start at offset 7MB in the section. In this
|
||||
# case the ROM starts at 0xff800000, so the offset of the first
|
||||
# entry in the section corresponds to that.
|
||||
if (self.target_pos < self.pos or
|
||||
self.target_pos >= self.pos + self.size):
|
||||
if (self.target_offset < self.offset or
|
||||
self.target_offset >= self.offset + self.size):
|
||||
self.Raise('Microcode pointer _dt_ucode_base_size at %08x is '
|
||||
'outside the section ranging from %08x to %08x' %
|
||||
(self.target_pos, self.pos, self.pos + self.size))
|
||||
(self.target_offset, self.offset, self.offset + self.size))
|
||||
|
||||
# Get the microcode, either from u-boot-ucode or u-boot-dtb-with-ucode.
|
||||
# If we have left the microcode in the device tree, then it will be
|
||||
# in the former. If we extracted the microcode from the device tree
|
||||
# and collated it in one place, it will be in the latter.
|
||||
if ucode_entry.size:
|
||||
pos, size = ucode_entry.pos, ucode_entry.size
|
||||
offset, size = ucode_entry.offset, ucode_entry.size
|
||||
else:
|
||||
dtb_entry = self.section.FindEntryType('u-boot-dtb-with-ucode')
|
||||
if not dtb_entry or not dtb_entry.ready:
|
||||
self.Raise('Cannot find microcode region u-boot-dtb-with-ucode')
|
||||
pos = dtb_entry.pos + dtb_entry.ucode_offset
|
||||
offset = dtb_entry.offset + dtb_entry.ucode_offset
|
||||
size = dtb_entry.ucode_size
|
||||
|
||||
# Write the microcode position and size into the entry
|
||||
pos_and_size = struct.pack('<2L', pos, size)
|
||||
self.target_pos -= self.pos
|
||||
self.ProcessContentsUpdate(self.data[:self.target_pos] + pos_and_size +
|
||||
self.data[self.target_pos + 8:])
|
||||
# Write the microcode offset and size into the entry
|
||||
offset_and_size = struct.pack('<2L', offset, size)
|
||||
self.target_offset -= self.offset
|
||||
self.ProcessContentsUpdate(self.data[:self.target_offset] +
|
||||
offset_and_size +
|
||||
self.data[self.target_offset + 8:])
|
||||
|
|
74
tools/binman/etype/vblock.py
Normal file
74
tools/binman/etype/vblock.py
Normal file
|
@ -0,0 +1,74 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2018 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
|
||||
# Support for a Chromium OS verified boot block, used to sign a read-write
|
||||
# section of the image.
|
||||
|
||||
from collections import OrderedDict
|
||||
import os
|
||||
|
||||
from entry import Entry, EntryArg
|
||||
|
||||
import fdt_util
|
||||
import tools
|
||||
|
||||
class Entry_vblock(Entry):
|
||||
"""An entry which contains a Chromium OS verified boot block
|
||||
|
||||
Properties / Entry arguments:
|
||||
- keydir: Directory containing the public keys to use
|
||||
- keyblock: Name of the key file to use (inside keydir)
|
||||
- signprivate: Name of provide key file to use (inside keydir)
|
||||
- version: Version number of the vblock (typically 1)
|
||||
- kernelkey: Name of the kernel key to use (inside keydir)
|
||||
- preamble-flags: Value of the vboot preamble flags (typically 0)
|
||||
|
||||
Chromium OS signs the read-write firmware and kernel, writing the signature
|
||||
in this block. This allows U-Boot to verify that the next firmware stage
|
||||
and kernel are genuine.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry.__init__(self, section, etype, node)
|
||||
self.content = fdt_util.GetPhandleList(self._node, 'content')
|
||||
if not self.content:
|
||||
self.Raise("Vblock must have a 'content' property")
|
||||
(self.keydir, self.keyblock, self.signprivate, self.version,
|
||||
self.kernelkey, self.preamble_flags) = self.GetEntryArgsOrProps([
|
||||
EntryArg('keydir', str),
|
||||
EntryArg('keyblock', str),
|
||||
EntryArg('signprivate', str),
|
||||
EntryArg('version', int),
|
||||
EntryArg('kernelkey', str),
|
||||
EntryArg('preamble-flags', int)])
|
||||
|
||||
def ObtainContents(self):
|
||||
# Join up the data files to be signed
|
||||
input_data = ''
|
||||
for entry_phandle in self.content:
|
||||
data = self.section.GetContentsByPhandle(entry_phandle, self)
|
||||
if data is None:
|
||||
# Data not available yet
|
||||
return False
|
||||
input_data += data
|
||||
|
||||
output_fname = tools.GetOutputFilename('vblock.%s' % self.name)
|
||||
input_fname = tools.GetOutputFilename('input.%s' % self.name)
|
||||
tools.WriteFile(input_fname, input_data)
|
||||
prefix = self.keydir + '/'
|
||||
args = [
|
||||
'vbutil_firmware',
|
||||
'--vblock', output_fname,
|
||||
'--keyblock', prefix + self.keyblock,
|
||||
'--signprivate', prefix + self.signprivate,
|
||||
'--version', '%d' % self.version,
|
||||
'--fv', input_fname,
|
||||
'--kernelkey', prefix + self.kernelkey,
|
||||
'--flags', '%d' % self.preamble_flags,
|
||||
]
|
||||
#out.Notice("Sign '%s' into %s" % (', '.join(self.value), self.label))
|
||||
stdout = tools.Run('futility', *args)
|
||||
#out.Debug(stdout)
|
||||
self.SetContents(tools.ReadFile(output_fname))
|
||||
return True
|
|
@ -9,6 +9,20 @@ from entry import Entry
|
|||
from blob import Entry_blob
|
||||
|
||||
class Entry_x86_start16(Entry_blob):
|
||||
"""x86 16-bit start-up code for U-Boot
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of u-boot-x86-16bit.bin (default
|
||||
'u-boot-x86-16bit.bin')
|
||||
|
||||
x86 CPUs start up in 16-bit mode, even if they are 32-bit CPUs. This code
|
||||
must be placed at a particular address. This entry holds that code. It is
|
||||
typically placed at offset CONFIG_SYS_X86_START16. The code is responsible
|
||||
for changing to 32-bit mode and jumping to U-Boot's entry point, which
|
||||
requires 32-bit mode (for 32-bit U-Boot).
|
||||
|
||||
For 64-bit U-Boot, the 'x86_start16_spl' entry type is used instead.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
|
||||
|
|
|
@ -9,6 +9,20 @@ from entry import Entry
|
|||
from blob import Entry_blob
|
||||
|
||||
class Entry_x86_start16_spl(Entry_blob):
|
||||
"""x86 16-bit start-up code for SPL
|
||||
|
||||
Properties / Entry arguments:
|
||||
- filename: Filename of spl/u-boot-x86-16bit-spl.bin (default
|
||||
'spl/u-boot-x86-16bit-spl.bin')
|
||||
|
||||
x86 CPUs start up in 16-bit mode, even if they are 64-bit CPUs. This code
|
||||
must be placed at a particular address. This entry holds that code. It is
|
||||
typically placed at offset CONFIG_SYS_X86_START16. The code is responsible
|
||||
for changing to 32-bit mode and starting SPL, which in turn changes to
|
||||
64-bit mode and jumps to U-Boot (for 64-bit U-Boot).
|
||||
|
||||
For 32-bit U-Boot, the 'x86_start16' entry type is used instead.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry_blob.__init__(self, section, etype, node)
|
||||
|
||||
|
|
109
tools/binman/fmap_util.py
Normal file
109
tools/binman/fmap_util.py
Normal file
|
@ -0,0 +1,109 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2018 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# Support for flashrom's FMAP format. This supports a header followed by a
|
||||
# number of 'areas', describing regions of a firmware storage device,
|
||||
# generally SPI flash.
|
||||
|
||||
import collections
|
||||
import struct
|
||||
|
||||
# constants imported from lib/fmap.h
|
||||
FMAP_SIGNATURE = '__FMAP__'
|
||||
FMAP_VER_MAJOR = 1
|
||||
FMAP_VER_MINOR = 0
|
||||
FMAP_STRLEN = 32
|
||||
|
||||
FMAP_AREA_STATIC = 1 << 0
|
||||
FMAP_AREA_COMPRESSED = 1 << 1
|
||||
FMAP_AREA_RO = 1 << 2
|
||||
|
||||
FMAP_HEADER_LEN = 56
|
||||
FMAP_AREA_LEN = 42
|
||||
|
||||
FMAP_HEADER_FORMAT = '<8sBBQI%dsH'% (FMAP_STRLEN)
|
||||
FMAP_AREA_FORMAT = '<II%dsH' % (FMAP_STRLEN)
|
||||
|
||||
FMAP_HEADER_NAMES = (
|
||||
'signature',
|
||||
'ver_major',
|
||||
'ver_minor',
|
||||
'base',
|
||||
'image_size',
|
||||
'name',
|
||||
'nareas',
|
||||
)
|
||||
|
||||
FMAP_AREA_NAMES = (
|
||||
'offset',
|
||||
'size',
|
||||
'name',
|
||||
'flags',
|
||||
)
|
||||
|
||||
# These are the two data structures supported by flashrom, a header (which
|
||||
# appears once at the start) and an area (which is repeated until the end of
|
||||
# the list of areas)
|
||||
FmapHeader = collections.namedtuple('FmapHeader', FMAP_HEADER_NAMES)
|
||||
FmapArea = collections.namedtuple('FmapArea', FMAP_AREA_NAMES)
|
||||
|
||||
|
||||
def ConvertName(field_names, fields):
|
||||
"""Convert a name to something flashrom likes
|
||||
|
||||
Flashrom requires upper case, underscores instead of hyphens. We remove any
|
||||
null characters as well. This updates the 'name' value in fields.
|
||||
|
||||
Args:
|
||||
field_names: List of field names for this struct
|
||||
fields: Dict:
|
||||
key: Field name
|
||||
value: value of that field (string for the ones we support)
|
||||
"""
|
||||
name_index = field_names.index('name')
|
||||
fields[name_index] = fields[name_index].replace('\0', '').replace('-', '_').upper()
|
||||
|
||||
def DecodeFmap(data):
|
||||
"""Decode a flashmap into a header and list of areas
|
||||
|
||||
Args:
|
||||
data: Data block containing the FMAP
|
||||
|
||||
Returns:
|
||||
Tuple:
|
||||
header: FmapHeader object
|
||||
List of FmapArea objects
|
||||
"""
|
||||
fields = list(struct.unpack(FMAP_HEADER_FORMAT, data[:FMAP_HEADER_LEN]))
|
||||
ConvertName(FMAP_HEADER_NAMES, fields)
|
||||
header = FmapHeader(*fields)
|
||||
areas = []
|
||||
data = data[FMAP_HEADER_LEN:]
|
||||
for area in range(header.nareas):
|
||||
fields = list(struct.unpack(FMAP_AREA_FORMAT, data[:FMAP_AREA_LEN]))
|
||||
ConvertName(FMAP_AREA_NAMES, fields)
|
||||
areas.append(FmapArea(*fields))
|
||||
data = data[FMAP_AREA_LEN:]
|
||||
return header, areas
|
||||
|
||||
def EncodeFmap(image_size, name, areas):
|
||||
"""Create a new FMAP from a list of areas
|
||||
|
||||
Args:
|
||||
image_size: Size of image, to put in the header
|
||||
name: Name of image, to put in the header
|
||||
areas: List of FmapArea objects
|
||||
|
||||
Returns:
|
||||
String containing the FMAP created
|
||||
"""
|
||||
def _FormatBlob(fmt, names, obj):
|
||||
params = [getattr(obj, name) for name in names]
|
||||
return struct.pack(fmt, *params)
|
||||
|
||||
values = FmapHeader(FMAP_SIGNATURE, 1, 0, 0, image_size, name, len(areas))
|
||||
blob = _FormatBlob(FMAP_HEADER_FORMAT, FMAP_HEADER_NAMES, values)
|
||||
for area in areas:
|
||||
blob += _FormatBlob(FMAP_AREA_FORMAT, FMAP_AREA_NAMES, area)
|
||||
return blob
|
|
@ -21,6 +21,8 @@ import control
|
|||
import elf
|
||||
import fdt
|
||||
import fdt_util
|
||||
import fmap_util
|
||||
import test_util
|
||||
import tools
|
||||
import tout
|
||||
|
||||
|
@ -28,11 +30,13 @@ import tout
|
|||
U_BOOT_DATA = '1234'
|
||||
U_BOOT_IMG_DATA = 'img'
|
||||
U_BOOT_SPL_DATA = '56780123456789abcde'
|
||||
U_BOOT_TPL_DATA = 'tpl'
|
||||
BLOB_DATA = '89'
|
||||
ME_DATA = '0abcd'
|
||||
VGA_DATA = 'vga'
|
||||
U_BOOT_DTB_DATA = 'udtb'
|
||||
U_BOOT_SPL_DTB_DATA = 'spldtb'
|
||||
U_BOOT_TPL_DTB_DATA = 'tpldtb'
|
||||
X86_START16_DATA = 'start16'
|
||||
X86_START16_SPL_DATA = 'start16spl'
|
||||
U_BOOT_NODTB_DATA = 'nodtb with microcode pointer somewhere in here'
|
||||
|
@ -41,6 +45,14 @@ FSP_DATA = 'fsp'
|
|||
CMC_DATA = 'cmc'
|
||||
VBT_DATA = 'vbt'
|
||||
MRC_DATA = 'mrc'
|
||||
TEXT_DATA = 'text'
|
||||
TEXT_DATA2 = 'text2'
|
||||
TEXT_DATA3 = 'text3'
|
||||
CROS_EC_RW_DATA = 'ecrw'
|
||||
GBB_DATA = 'gbbd'
|
||||
BMPBLK_DATA = 'bmp'
|
||||
VBLOCK_DATA = 'vblk'
|
||||
|
||||
|
||||
class TestFunctional(unittest.TestCase):
|
||||
"""Functional tests for binman
|
||||
|
@ -72,11 +84,11 @@ class TestFunctional(unittest.TestCase):
|
|||
TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
|
||||
TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
|
||||
TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
|
||||
TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
|
||||
TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
|
||||
TestFunctional._MakeInputFile('me.bin', ME_DATA)
|
||||
TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
|
||||
TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
|
||||
TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
|
||||
self._ResetDtbs()
|
||||
TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
|
||||
TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
|
||||
X86_START16_SPL_DATA)
|
||||
|
@ -87,6 +99,9 @@ class TestFunctional(unittest.TestCase):
|
|||
TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
|
||||
TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
|
||||
TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
|
||||
TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
|
||||
TestFunctional._MakeInputDir('devkeys')
|
||||
TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
|
||||
self._output_setup = False
|
||||
|
||||
# ELF file with a '_dt_ucode_base_size' symbol
|
||||
|
@ -113,6 +128,12 @@ class TestFunctional(unittest.TestCase):
|
|||
"""Remove the temporary output directory"""
|
||||
tools._FinaliseForTest()
|
||||
|
||||
@classmethod
|
||||
def _ResetDtbs(self):
|
||||
TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
|
||||
TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
|
||||
TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
|
||||
|
||||
def _RunBinman(self, *args, **kwargs):
|
||||
"""Run binman using the command line
|
||||
|
||||
|
@ -146,14 +167,15 @@ class TestFunctional(unittest.TestCase):
|
|||
# options.verbosity = tout.DEBUG
|
||||
return control.Binman(options, args)
|
||||
|
||||
def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False):
|
||||
def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
|
||||
entry_args=None):
|
||||
"""Run binman with a given test file
|
||||
|
||||
Args:
|
||||
fname: Device-tree source filename to use (e.g. 05_simple.dts)
|
||||
debug: True to enable debugging output
|
||||
map: True to output map files for the images
|
||||
update_dtb: Update the position and size of each entry in the device
|
||||
update_dtb: Update the offset and size of each entry in the device
|
||||
tree before packing it into the image
|
||||
"""
|
||||
args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
|
||||
|
@ -163,6 +185,9 @@ class TestFunctional(unittest.TestCase):
|
|||
args.append('-m')
|
||||
if update_dtb:
|
||||
args.append('-up')
|
||||
if entry_args:
|
||||
for arg, value in entry_args.iteritems():
|
||||
args.append('-a%s=%s' % (arg, value))
|
||||
return self._DoBinman(*args)
|
||||
|
||||
def _SetupDtb(self, fname, outfile='u-boot.dtb'):
|
||||
|
@ -188,7 +213,7 @@ class TestFunctional(unittest.TestCase):
|
|||
return data
|
||||
|
||||
def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
|
||||
update_dtb=False):
|
||||
update_dtb=False, entry_args=None):
|
||||
"""Run binman and return the resulting image
|
||||
|
||||
This runs binman with a given test file and then reads the resulting
|
||||
|
@ -204,7 +229,7 @@ class TestFunctional(unittest.TestCase):
|
|||
test contents (the U_BOOT_DTB_DATA string) can be used.
|
||||
But in some test we need the real contents.
|
||||
map: True to output map files for the images
|
||||
update_dtb: Update the position and size of each entry in the device
|
||||
update_dtb: Update the offset and size of each entry in the device
|
||||
tree before packing it into the image
|
||||
|
||||
Returns:
|
||||
|
@ -212,6 +237,7 @@ class TestFunctional(unittest.TestCase):
|
|||
Resulting image contents
|
||||
Device tree contents
|
||||
Map data showing contents of image (or None if none)
|
||||
Output device tree binary filename ('u-boot.dtb' path)
|
||||
"""
|
||||
dtb_data = None
|
||||
# Use the compiled test file as the u-boot-dtb input
|
||||
|
@ -219,7 +245,8 @@ class TestFunctional(unittest.TestCase):
|
|||
dtb_data = self._SetupDtb(fname)
|
||||
|
||||
try:
|
||||
retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb)
|
||||
retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
|
||||
entry_args=entry_args)
|
||||
self.assertEqual(0, retcode)
|
||||
out_dtb_fname = control.GetFdtPath('u-boot.dtb')
|
||||
|
||||
|
@ -238,7 +265,7 @@ class TestFunctional(unittest.TestCase):
|
|||
finally:
|
||||
# Put the test file back
|
||||
if use_real_dtb:
|
||||
TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
|
||||
self._ResetDtbs()
|
||||
|
||||
def _DoReadFile(self, fname, use_real_dtb=False):
|
||||
"""Helper function which discards the device-tree binary
|
||||
|
@ -249,6 +276,9 @@ class TestFunctional(unittest.TestCase):
|
|||
the u-boot-dtb entry. Normally this is not needed and the
|
||||
test contents (the U_BOOT_DTB_DATA string) can be used.
|
||||
But in some test we need the real contents.
|
||||
|
||||
Returns:
|
||||
Resulting image contents
|
||||
"""
|
||||
return self._DoReadFileDtb(fname, use_real_dtb)[0]
|
||||
|
||||
|
@ -257,7 +287,7 @@ class TestFunctional(unittest.TestCase):
|
|||
"""Create a new test input file, creating directories as needed
|
||||
|
||||
Args:
|
||||
fname: Filenaem to create
|
||||
fname: Filename to create
|
||||
contents: File contents to write in to the file
|
||||
Returns:
|
||||
Full pathname of file created
|
||||
|
@ -270,6 +300,21 @@ class TestFunctional(unittest.TestCase):
|
|||
fd.write(contents)
|
||||
return pathname
|
||||
|
||||
@classmethod
|
||||
def _MakeInputDir(self, dirname):
|
||||
"""Create a new test input directory, creating directories as needed
|
||||
|
||||
Args:
|
||||
dirname: Directory name to create
|
||||
|
||||
Returns:
|
||||
Full pathname of directory created
|
||||
"""
|
||||
pathname = os.path.join(self._indir, dirname)
|
||||
if not os.path.exists(pathname):
|
||||
os.makedirs(pathname)
|
||||
return pathname
|
||||
|
||||
@classmethod
|
||||
def TestFile(self, fname):
|
||||
return os.path.join(self._binman_dir, 'test', fname)
|
||||
|
@ -292,10 +337,10 @@ class TestFunctional(unittest.TestCase):
|
|||
Args:
|
||||
entries: List of entries to check
|
||||
"""
|
||||
pos = 0
|
||||
offset = 0
|
||||
for entry in entries.values():
|
||||
self.assertEqual(pos, entry.pos)
|
||||
pos += entry.size
|
||||
self.assertEqual(offset, entry.offset)
|
||||
offset += entry.size
|
||||
|
||||
def GetFdtLen(self, dtb):
|
||||
"""Get the totalsize field from a device-tree binary
|
||||
|
@ -308,23 +353,19 @@ class TestFunctional(unittest.TestCase):
|
|||
"""
|
||||
return struct.unpack('>L', dtb[4:8])[0]
|
||||
|
||||
def _GetPropTree(self, dtb_data, node_names):
|
||||
def _GetPropTree(self, dtb, prop_names):
|
||||
def AddNode(node, path):
|
||||
if node.name != '/':
|
||||
path += '/' + node.name
|
||||
#print 'path', path
|
||||
for subnode in node.subnodes:
|
||||
for prop in subnode.props.values():
|
||||
if prop.name in node_names:
|
||||
if prop.name in prop_names:
|
||||
prop_path = path + '/' + subnode.name + ':' + prop.name
|
||||
tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
|
||||
prop.value)
|
||||
#print ' ', prop.name
|
||||
AddNode(subnode, path)
|
||||
|
||||
tree = {}
|
||||
dtb = fdt.Fdt(dtb_data)
|
||||
dtb.Scan()
|
||||
AddNode(dtb.GetRoot(), '')
|
||||
return tree
|
||||
|
||||
|
@ -409,7 +450,6 @@ class TestFunctional(unittest.TestCase):
|
|||
with self.assertRaises(Exception) as e:
|
||||
result = self._RunBinman('-d',
|
||||
self.TestFile('04_invalid_entry.dts'))
|
||||
#print e.exception
|
||||
self.assertIn("Unknown entry type 'not-a-valid-type' in node "
|
||||
"'/binman/not-a-valid-type'", str(e.exception))
|
||||
|
||||
|
@ -467,32 +507,32 @@ class TestFunctional(unittest.TestCase):
|
|||
# First u-boot
|
||||
self.assertIn('u-boot', entries)
|
||||
entry = entries['u-boot']
|
||||
self.assertEqual(0, entry.pos)
|
||||
self.assertEqual(0, entry.offset)
|
||||
self.assertEqual(len(U_BOOT_DATA), entry.size)
|
||||
|
||||
# Second u-boot, aligned to 16-byte boundary
|
||||
self.assertIn('u-boot-align', entries)
|
||||
entry = entries['u-boot-align']
|
||||
self.assertEqual(16, entry.pos)
|
||||
self.assertEqual(16, entry.offset)
|
||||
self.assertEqual(len(U_BOOT_DATA), entry.size)
|
||||
|
||||
# Third u-boot, size 23 bytes
|
||||
self.assertIn('u-boot-size', entries)
|
||||
entry = entries['u-boot-size']
|
||||
self.assertEqual(20, entry.pos)
|
||||
self.assertEqual(20, entry.offset)
|
||||
self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
|
||||
self.assertEqual(23, entry.size)
|
||||
|
||||
# Fourth u-boot, placed immediate after the above
|
||||
self.assertIn('u-boot-next', entries)
|
||||
entry = entries['u-boot-next']
|
||||
self.assertEqual(43, entry.pos)
|
||||
self.assertEqual(43, entry.offset)
|
||||
self.assertEqual(len(U_BOOT_DATA), entry.size)
|
||||
|
||||
# Fifth u-boot, placed at a fixed position
|
||||
# Fifth u-boot, placed at a fixed offset
|
||||
self.assertIn('u-boot-fixed', entries)
|
||||
entry = entries['u-boot-fixed']
|
||||
self.assertEqual(61, entry.pos)
|
||||
self.assertEqual(61, entry.offset)
|
||||
self.assertEqual(len(U_BOOT_DATA), entry.size)
|
||||
|
||||
self.assertEqual(65, image._size)
|
||||
|
@ -510,32 +550,32 @@ class TestFunctional(unittest.TestCase):
|
|||
# First u-boot with padding before and after
|
||||
self.assertIn('u-boot', entries)
|
||||
entry = entries['u-boot']
|
||||
self.assertEqual(0, entry.pos)
|
||||
self.assertEqual(0, entry.offset)
|
||||
self.assertEqual(3, entry.pad_before)
|
||||
self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
|
||||
|
||||
# Second u-boot has an aligned size, but it has no effect
|
||||
self.assertIn('u-boot-align-size-nop', entries)
|
||||
entry = entries['u-boot-align-size-nop']
|
||||
self.assertEqual(12, entry.pos)
|
||||
self.assertEqual(12, entry.offset)
|
||||
self.assertEqual(4, entry.size)
|
||||
|
||||
# Third u-boot has an aligned size too
|
||||
self.assertIn('u-boot-align-size', entries)
|
||||
entry = entries['u-boot-align-size']
|
||||
self.assertEqual(16, entry.pos)
|
||||
self.assertEqual(16, entry.offset)
|
||||
self.assertEqual(32, entry.size)
|
||||
|
||||
# Fourth u-boot has an aligned end
|
||||
self.assertIn('u-boot-align-end', entries)
|
||||
entry = entries['u-boot-align-end']
|
||||
self.assertEqual(48, entry.pos)
|
||||
self.assertEqual(48, entry.offset)
|
||||
self.assertEqual(16, entry.size)
|
||||
|
||||
# Fifth u-boot immediately afterwards
|
||||
self.assertIn('u-boot-align-both', entries)
|
||||
entry = entries['u-boot-align-both']
|
||||
self.assertEqual(64, entry.pos)
|
||||
self.assertEqual(64, entry.offset)
|
||||
self.assertEqual(64, entry.size)
|
||||
|
||||
self.CheckNoGaps(entries)
|
||||
|
@ -556,10 +596,10 @@ class TestFunctional(unittest.TestCase):
|
|||
"power of two", str(e.exception))
|
||||
|
||||
def testPackInvalidAlign(self):
|
||||
"""Test detection of an position that does not match its alignment"""
|
||||
"""Test detection of an offset that does not match its alignment"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('12_pack_inv_align.dts')
|
||||
self.assertIn("Node '/binman/u-boot': Position 0x5 (5) does not match "
|
||||
self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
|
||||
"align 0x4 (4)", str(e.exception))
|
||||
|
||||
def testPackInvalidSizeAlign(self):
|
||||
|
@ -573,7 +613,7 @@ class TestFunctional(unittest.TestCase):
|
|||
"""Test that overlapping regions are detected"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('14_pack_overlap.dts')
|
||||
self.assertIn("Node '/binman/u-boot-align': Position 0x3 (3) overlaps "
|
||||
self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
|
||||
"with previous entry '/binman/u-boot' ending at 0x4 (4)",
|
||||
str(e.exception))
|
||||
|
||||
|
@ -651,11 +691,11 @@ class TestFunctional(unittest.TestCase):
|
|||
self.assertEqual(chr(0) * 1 + U_BOOT_SPL_DATA + chr(0) * 2 +
|
||||
U_BOOT_DATA, data)
|
||||
|
||||
def testPackZeroPosition(self):
|
||||
"""Test that an entry at position 0 is not given a new position"""
|
||||
def testPackZeroOffset(self):
|
||||
"""Test that an entry at offset 0 is not given a new offset"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('25_pack_zero_size.dts')
|
||||
self.assertIn("Node '/binman/u-boot-spl': Position 0x0 (0) overlaps "
|
||||
self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
|
||||
"with previous entry '/binman/u-boot' ending at 0x4 (4)",
|
||||
str(e.exception))
|
||||
|
||||
|
@ -672,10 +712,10 @@ class TestFunctional(unittest.TestCase):
|
|||
"using end-at-4gb", str(e.exception))
|
||||
|
||||
def testPackX86RomOutside(self):
|
||||
"""Test that the end-at-4gb property checks for position boundaries"""
|
||||
"""Test that the end-at-4gb property checks for offset boundaries"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('28_pack_4gb_outside.dts')
|
||||
self.assertIn("Node '/binman/u-boot': Position 0x0 (0) is outside "
|
||||
self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
|
||||
"the section starting at 0xffffffe0 (4294967264)",
|
||||
str(e.exception))
|
||||
|
||||
|
@ -697,9 +737,9 @@ class TestFunctional(unittest.TestCase):
|
|||
"""Test that the Intel requires a descriptor entry"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('30_x86-rom-me-no-desc.dts')
|
||||
self.assertIn("Node '/binman/intel-me': No position set with "
|
||||
"pos-unset: should another entry provide this correct "
|
||||
"position?", str(e.exception))
|
||||
self.assertIn("Node '/binman/intel-me': No offset set with "
|
||||
"offset-unset: should another entry provide this correct "
|
||||
"offset?", str(e.exception))
|
||||
|
||||
def testPackX86RomMe(self):
|
||||
"""Test that an x86 ROM with an ME region can be created"""
|
||||
|
@ -728,7 +768,7 @@ class TestFunctional(unittest.TestCase):
|
|||
Returns:
|
||||
Tuple:
|
||||
Contents of first region (U-Boot or SPL)
|
||||
Position and size components of microcode pointer, as inserted
|
||||
Offset and size components of microcode pointer, as inserted
|
||||
in the above (two 4-byte words)
|
||||
"""
|
||||
data = self._DoReadFile(dts_fname, True)
|
||||
|
@ -761,7 +801,7 @@ class TestFunctional(unittest.TestCase):
|
|||
self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
|
||||
|
||||
# Check that the microcode pointer was inserted. It should match the
|
||||
# expected position and size
|
||||
# expected offset and size
|
||||
pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
|
||||
len(ucode_data))
|
||||
u_boot = data[:len(nodtb_data)]
|
||||
|
@ -806,7 +846,7 @@ class TestFunctional(unittest.TestCase):
|
|||
ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
|
||||
|
||||
# Check that the microcode pointer was inserted. It should match the
|
||||
# expected position and size
|
||||
# expected offset and size
|
||||
pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
|
||||
len(ucode_data))
|
||||
first = data[:len(U_BOOT_NODTB_DATA)]
|
||||
|
@ -890,7 +930,7 @@ class TestFunctional(unittest.TestCase):
|
|||
"""Test that microcode must be placed within the image"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFile('41_unknown_pos_size.dts', True)
|
||||
self.assertIn("Section '/binman': Unable to set pos/size for unknown "
|
||||
self.assertIn("Section '/binman': Unable to set offset/size for unknown "
|
||||
"entry 'invalid-entry'", str(e.exception))
|
||||
|
||||
def testPackFsp(self):
|
||||
|
@ -984,7 +1024,7 @@ class TestFunctional(unittest.TestCase):
|
|||
elf_fname = self.TestFile('u_boot_binman_syms')
|
||||
syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
|
||||
addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
|
||||
self.assertEqual(syms['_binman_u_boot_spl_prop_pos'].address, addr)
|
||||
self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
|
||||
|
||||
with open(self.TestFile('u_boot_binman_syms')) as fd:
|
||||
TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
|
||||
|
@ -1003,27 +1043,32 @@ class TestFunctional(unittest.TestCase):
|
|||
def testSections(self):
|
||||
"""Basic test of sections"""
|
||||
data = self._DoReadFile('55_sections.dts')
|
||||
expected = U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12 + '&' * 8
|
||||
expected = (U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12 +
|
||||
U_BOOT_DATA + '&' * 4)
|
||||
self.assertEqual(expected, data)
|
||||
|
||||
def testMap(self):
|
||||
"""Tests outputting a map of the images"""
|
||||
_, _, map_data, _ = self._DoReadFileDtb('55_sections.dts', map=True)
|
||||
self.assertEqual('''Position Size Name
|
||||
00000000 00000010 section@0
|
||||
00000000 00000004 u-boot
|
||||
00000010 00000010 section@1
|
||||
00000000 00000004 u-boot
|
||||
self.assertEqual('''ImagePos Offset Size Name
|
||||
00000000 00000000 00000028 main-section
|
||||
00000000 00000000 00000010 section@0
|
||||
00000000 00000000 00000004 u-boot
|
||||
00000010 00000010 00000010 section@1
|
||||
00000010 00000000 00000004 u-boot
|
||||
00000020 00000020 00000004 section@2
|
||||
00000020 00000000 00000004 u-boot
|
||||
''', map_data)
|
||||
|
||||
def testNamePrefix(self):
|
||||
"""Tests that name prefixes are used"""
|
||||
_, _, map_data, _ = self._DoReadFileDtb('56_name_prefix.dts', map=True)
|
||||
self.assertEqual('''Position Size Name
|
||||
00000000 00000010 section@0
|
||||
00000000 00000004 ro-u-boot
|
||||
00000010 00000010 section@1
|
||||
00000000 00000004 rw-u-boot
|
||||
self.assertEqual('''ImagePos Offset Size Name
|
||||
00000000 00000000 00000028 main-section
|
||||
00000000 00000000 00000010 section@0
|
||||
00000000 00000000 00000004 ro-u-boot
|
||||
00000010 00000010 00000010 section@1
|
||||
00000010 00000000 00000004 rw-u-boot
|
||||
''', map_data)
|
||||
|
||||
def testUnknownContents(self):
|
||||
|
@ -1042,25 +1087,31 @@ class TestFunctional(unittest.TestCase):
|
|||
'2 to 1', str(e.exception))
|
||||
|
||||
def testUpdateFdt(self):
|
||||
"""Test that we can update the device tree with pos/size info"""
|
||||
"""Test that we can update the device tree with offset/size info"""
|
||||
_, _, _, out_dtb_fname = self._DoReadFileDtb('60_fdt_update.dts',
|
||||
update_dtb=True)
|
||||
props = self._GetPropTree(out_dtb_fname, ['pos', 'size'])
|
||||
with open('/tmp/x.dtb', 'wb') as outf:
|
||||
with open(out_dtb_fname) as inf:
|
||||
outf.write(inf.read())
|
||||
dtb = fdt.Fdt(out_dtb_fname)
|
||||
dtb.Scan()
|
||||
props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
|
||||
self.assertEqual({
|
||||
'_testing:pos': 32,
|
||||
'image-pos': 0,
|
||||
'offset': 0,
|
||||
'_testing:offset': 32,
|
||||
'_testing:size': 1,
|
||||
'section@0/u-boot:pos': 0,
|
||||
'_testing:image-pos': 32,
|
||||
'section@0/u-boot:offset': 0,
|
||||
'section@0/u-boot:size': len(U_BOOT_DATA),
|
||||
'section@0:pos': 0,
|
||||
'section@0/u-boot:image-pos': 0,
|
||||
'section@0:offset': 0,
|
||||
'section@0:size': 16,
|
||||
'section@0:image-pos': 0,
|
||||
|
||||
'section@1/u-boot:pos': 0,
|
||||
'section@1/u-boot:offset': 0,
|
||||
'section@1/u-boot:size': len(U_BOOT_DATA),
|
||||
'section@1:pos': 16,
|
||||
'section@1/u-boot:image-pos': 16,
|
||||
'section@1:offset': 16,
|
||||
'section@1:size': 16,
|
||||
'section@1:image-pos': 16,
|
||||
'size': 40
|
||||
}, props)
|
||||
|
||||
|
@ -1071,5 +1122,248 @@ class TestFunctional(unittest.TestCase):
|
|||
self.assertIn('Could not complete processing of Fdt: remaining '
|
||||
'[<_testing.Entry__testing', str(e.exception))
|
||||
|
||||
def testEntryArgs(self):
|
||||
"""Test passing arguments to entries from the command line"""
|
||||
entry_args = {
|
||||
'test-str-arg': 'test1',
|
||||
'test-int-arg': '456',
|
||||
}
|
||||
self._DoReadFileDtb('62_entry_args.dts', entry_args=entry_args)
|
||||
self.assertIn('image', control.images)
|
||||
entry = control.images['image'].GetEntries()['_testing']
|
||||
self.assertEqual('test0', entry.test_str_fdt)
|
||||
self.assertEqual('test1', entry.test_str_arg)
|
||||
self.assertEqual(123, entry.test_int_fdt)
|
||||
self.assertEqual(456, entry.test_int_arg)
|
||||
|
||||
def testEntryArgsMissing(self):
|
||||
"""Test missing arguments and properties"""
|
||||
entry_args = {
|
||||
'test-int-arg': '456',
|
||||
}
|
||||
self._DoReadFileDtb('63_entry_args_missing.dts', entry_args=entry_args)
|
||||
entry = control.images['image'].GetEntries()['_testing']
|
||||
self.assertEqual('test0', entry.test_str_fdt)
|
||||
self.assertEqual(None, entry.test_str_arg)
|
||||
self.assertEqual(None, entry.test_int_fdt)
|
||||
self.assertEqual(456, entry.test_int_arg)
|
||||
|
||||
def testEntryArgsRequired(self):
|
||||
"""Test missing arguments and properties"""
|
||||
entry_args = {
|
||||
'test-int-arg': '456',
|
||||
}
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFileDtb('64_entry_args_required.dts')
|
||||
self.assertIn("Node '/binman/_testing': Missing required "
|
||||
'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
|
||||
str(e.exception))
|
||||
|
||||
def testEntryArgsInvalidFormat(self):
|
||||
"""Test that an invalid entry-argument format is detected"""
|
||||
args = ['-d', self.TestFile('64_entry_args_required.dts'), '-ano-value']
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoBinman(*args)
|
||||
self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
|
||||
|
||||
def testEntryArgsInvalidInteger(self):
|
||||
"""Test that an invalid entry-argument integer is detected"""
|
||||
entry_args = {
|
||||
'test-int-arg': 'abc',
|
||||
}
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFileDtb('62_entry_args.dts', entry_args=entry_args)
|
||||
self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
|
||||
"'test-int-arg' (value 'abc') to integer",
|
||||
str(e.exception))
|
||||
|
||||
def testEntryArgsInvalidDatatype(self):
|
||||
"""Test that an invalid entry-argument datatype is detected
|
||||
|
||||
This test could be written in entry_test.py except that it needs
|
||||
access to control.entry_args, which seems more than that module should
|
||||
be able to see.
|
||||
"""
|
||||
entry_args = {
|
||||
'test-bad-datatype-arg': '12',
|
||||
}
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFileDtb('65_entry_args_unknown_datatype.dts',
|
||||
entry_args=entry_args)
|
||||
self.assertIn('GetArg() internal error: Unknown data type ',
|
||||
str(e.exception))
|
||||
|
||||
def testText(self):
|
||||
"""Test for a text entry type"""
|
||||
entry_args = {
|
||||
'test-id': TEXT_DATA,
|
||||
'test-id2': TEXT_DATA2,
|
||||
'test-id3': TEXT_DATA3,
|
||||
}
|
||||
data, _, _, _ = self._DoReadFileDtb('66_text.dts',
|
||||
entry_args=entry_args)
|
||||
expected = (TEXT_DATA + chr(0) * (8 - len(TEXT_DATA)) + TEXT_DATA2 +
|
||||
TEXT_DATA3 + 'some text')
|
||||
self.assertEqual(expected, data)
|
||||
|
||||
def testEntryDocs(self):
|
||||
"""Test for creation of entry documentation"""
|
||||
with test_util.capture_sys_output() as (stdout, stderr):
|
||||
control.WriteEntryDocs(binman.GetEntryModules())
|
||||
self.assertTrue(len(stdout.getvalue()) > 0)
|
||||
|
||||
def testEntryDocsMissing(self):
|
||||
"""Test handling of missing entry documentation"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
with test_util.capture_sys_output() as (stdout, stderr):
|
||||
control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
|
||||
self.assertIn('Documentation is missing for modules: u_boot',
|
||||
str(e.exception))
|
||||
|
||||
def testFmap(self):
|
||||
"""Basic test of generation of a flashrom fmap"""
|
||||
data = self._DoReadFile('67_fmap.dts')
|
||||
fhdr, fentries = fmap_util.DecodeFmap(data[32:])
|
||||
expected = U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12
|
||||
self.assertEqual(expected, data[:32])
|
||||
self.assertEqual('__FMAP__', fhdr.signature)
|
||||
self.assertEqual(1, fhdr.ver_major)
|
||||
self.assertEqual(0, fhdr.ver_minor)
|
||||
self.assertEqual(0, fhdr.base)
|
||||
self.assertEqual(16 + 16 +
|
||||
fmap_util.FMAP_HEADER_LEN +
|
||||
fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
|
||||
self.assertEqual('FMAP', fhdr.name)
|
||||
self.assertEqual(3, fhdr.nareas)
|
||||
for fentry in fentries:
|
||||
self.assertEqual(0, fentry.flags)
|
||||
|
||||
self.assertEqual(0, fentries[0].offset)
|
||||
self.assertEqual(4, fentries[0].size)
|
||||
self.assertEqual('RO_U_BOOT', fentries[0].name)
|
||||
|
||||
self.assertEqual(16, fentries[1].offset)
|
||||
self.assertEqual(4, fentries[1].size)
|
||||
self.assertEqual('RW_U_BOOT', fentries[1].name)
|
||||
|
||||
self.assertEqual(32, fentries[2].offset)
|
||||
self.assertEqual(fmap_util.FMAP_HEADER_LEN +
|
||||
fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
|
||||
self.assertEqual('FMAP', fentries[2].name)
|
||||
|
||||
def testBlobNamedByArg(self):
|
||||
"""Test we can add a blob with the filename coming from an entry arg"""
|
||||
entry_args = {
|
||||
'cros-ec-rw-path': 'ecrw.bin',
|
||||
}
|
||||
data, _, _, _ = self._DoReadFileDtb('68_blob_named_by_arg.dts',
|
||||
entry_args=entry_args)
|
||||
|
||||
def testFill(self):
|
||||
"""Test for an fill entry type"""
|
||||
data = self._DoReadFile('69_fill.dts')
|
||||
expected = 8 * chr(0xff) + 8 * chr(0)
|
||||
self.assertEqual(expected, data)
|
||||
|
||||
def testFillNoSize(self):
|
||||
"""Test for an fill entry type with no size"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFile('70_fill_no_size.dts')
|
||||
self.assertIn("'fill' entry must have a size property",
|
||||
str(e.exception))
|
||||
|
||||
def _HandleGbbCommand(self, pipe_list):
|
||||
"""Fake calls to the futility utility"""
|
||||
if pipe_list[0][0] == 'futility':
|
||||
fname = pipe_list[0][-1]
|
||||
# Append our GBB data to the file, which will happen every time the
|
||||
# futility command is called.
|
||||
with open(fname, 'a') as fd:
|
||||
fd.write(GBB_DATA)
|
||||
return command.CommandResult()
|
||||
|
||||
def testGbb(self):
|
||||
"""Test for the Chromium OS Google Binary Block"""
|
||||
command.test_result = self._HandleGbbCommand
|
||||
entry_args = {
|
||||
'keydir': 'devkeys',
|
||||
'bmpblk': 'bmpblk.bin',
|
||||
}
|
||||
data, _, _, _ = self._DoReadFileDtb('71_gbb.dts', entry_args=entry_args)
|
||||
|
||||
# Since futility
|
||||
expected = GBB_DATA + GBB_DATA + 8 * chr(0) + (0x2180 - 16) * chr(0)
|
||||
self.assertEqual(expected, data)
|
||||
|
||||
def testGbbTooSmall(self):
|
||||
"""Test for the Chromium OS Google Binary Block being large enough"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFileDtb('72_gbb_too_small.dts')
|
||||
self.assertIn("Node '/binman/gbb': GBB is too small",
|
||||
str(e.exception))
|
||||
|
||||
def testGbbNoSize(self):
|
||||
"""Test for the Chromium OS Google Binary Block having a size"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFileDtb('73_gbb_no_size.dts')
|
||||
self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
|
||||
str(e.exception))
|
||||
|
||||
def _HandleVblockCommand(self, pipe_list):
|
||||
"""Fake calls to the futility utility"""
|
||||
if pipe_list[0][0] == 'futility':
|
||||
fname = pipe_list[0][3]
|
||||
with open(fname, 'w') as fd:
|
||||
fd.write(VBLOCK_DATA)
|
||||
return command.CommandResult()
|
||||
|
||||
def testVblock(self):
|
||||
"""Test for the Chromium OS Verified Boot Block"""
|
||||
command.test_result = self._HandleVblockCommand
|
||||
entry_args = {
|
||||
'keydir': 'devkeys',
|
||||
}
|
||||
data, _, _, _ = self._DoReadFileDtb('74_vblock.dts',
|
||||
entry_args=entry_args)
|
||||
expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
|
||||
self.assertEqual(expected, data)
|
||||
|
||||
def testVblockNoContent(self):
|
||||
"""Test we detect a vblock which has no content to sign"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFile('75_vblock_no_content.dts')
|
||||
self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
|
||||
'property', str(e.exception))
|
||||
|
||||
def testVblockBadPhandle(self):
|
||||
"""Test that we detect a vblock with an invalid phandle in contents"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFile('76_vblock_bad_phandle.dts')
|
||||
self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
|
||||
'1000', str(e.exception))
|
||||
|
||||
def testVblockBadEntry(self):
|
||||
"""Test that we detect an entry that points to a non-entry"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFile('77_vblock_bad_entry.dts')
|
||||
self.assertIn("Node '/binman/vblock': Cannot find entry for node "
|
||||
"'other'", str(e.exception))
|
||||
|
||||
def testTpl(self):
|
||||
"""Test that an image with TPL and ots device tree can be created"""
|
||||
# ELF file with a '__bss_size' symbol
|
||||
with open(self.TestFile('bss_data')) as fd:
|
||||
TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
|
||||
data = self._DoReadFile('78_u_boot_tpl.dts')
|
||||
self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
|
||||
|
||||
def testUsesPos(self):
|
||||
"""Test that the 'pos' property cannot be used anymore"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
data = self._DoReadFile('79_uses_pos.dts')
|
||||
self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
|
||||
"'pos'", str(e.exception))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -57,7 +57,7 @@ class Image:
|
|||
def AddMissingProperties(self):
|
||||
"""Add properties that are not present in the device tree
|
||||
|
||||
When binman has completed packing the entries the position and size of
|
||||
When binman has completed packing the entries the offset and size of
|
||||
each entry are known. But before this the device tree may not specify
|
||||
these. Add any missing properties, with a dummy value, so that the
|
||||
size of the entry is correct. That way we can insert the correct values
|
||||
|
@ -73,13 +73,13 @@ class Image:
|
|||
"""
|
||||
self._section.GetEntryContents()
|
||||
|
||||
def GetEntryPositions(self):
|
||||
"""Handle entries that want to set the position/size of other entries
|
||||
def GetEntryOffsets(self):
|
||||
"""Handle entries that want to set the offset/size of other entries
|
||||
|
||||
This calls each entry's GetPositions() method. If it returns a list
|
||||
This calls each entry's GetOffsets() method. If it returns a list
|
||||
of entries to update, it updates them.
|
||||
"""
|
||||
self._section.GetEntryPositions()
|
||||
self._section.GetEntryOffsets()
|
||||
|
||||
def PackEntries(self):
|
||||
"""Pack all entries into the image"""
|
||||
|
@ -96,6 +96,9 @@ class Image:
|
|||
def SetCalculatedProperties(self):
|
||||
self._section.SetCalculatedProperties()
|
||||
|
||||
def SetImagePos(self):
|
||||
self._section.SetImagePos(0)
|
||||
|
||||
def ProcessEntryContents(self):
|
||||
"""Call the ProcessContents() method for each entry
|
||||
|
||||
|
@ -121,5 +124,6 @@ class Image:
|
|||
filename = '%s.map' % self._name
|
||||
fname = tools.GetOutputFilename(filename)
|
||||
with open(fname, 'w') as fd:
|
||||
print('%8s %8s %s' % ('Position', 'Size', 'Name'), file=fd)
|
||||
print('%8s %8s %8s %s' % ('ImagePos', 'Offset', 'Size', 'Name'),
|
||||
file=fd)
|
||||
self._section.WriteMap(fd, 0)
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
u-boot-fixed {
|
||||
type = "u-boot";
|
||||
pos = <61>;
|
||||
offset = <61>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
binman {
|
||||
u-boot {
|
||||
pos = <5>;
|
||||
offset = <5>;
|
||||
align = <4>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
u-boot-align {
|
||||
type = "u-boot";
|
||||
pos = <3>;
|
||||
offset = <3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
};
|
||||
|
||||
u-boot {
|
||||
pos = <20>;
|
||||
offset = <20>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
sort-by-offset;
|
||||
u-boot {
|
||||
pos = <22>;
|
||||
offset = <22>;
|
||||
};
|
||||
|
||||
u-boot-spl {
|
||||
pos = <1>;
|
||||
offset = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
};
|
||||
|
||||
u-boot-spl {
|
||||
pos = <0>;
|
||||
offset = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
sort-by-offset;
|
||||
end-at-4gb;
|
||||
u-boot {
|
||||
pos = <0xfffffff0>;
|
||||
offset = <0xfffffff0>;
|
||||
};
|
||||
|
||||
u-boot-spl {
|
||||
pos = <0xfffffff7>;
|
||||
offset = <0xfffffff7>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -5,15 +5,15 @@
|
|||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
sort-by-offset;
|
||||
end-at-4gb;
|
||||
size = <32>;
|
||||
u-boot {
|
||||
pos = <0>;
|
||||
offset = <0>;
|
||||
};
|
||||
|
||||
u-boot-spl {
|
||||
pos = <0xffffffeb>;
|
||||
offset = <0xffffffeb>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -5,15 +5,15 @@
|
|||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
sort-by-offset;
|
||||
end-at-4gb;
|
||||
size = <32>;
|
||||
u-boot {
|
||||
pos = <0xffffffe0>;
|
||||
offset = <0xffffffe0>;
|
||||
};
|
||||
|
||||
u-boot-spl {
|
||||
pos = <0xffffffeb>;
|
||||
offset = <0xffffffeb>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
sort-by-offset;
|
||||
end-at-4gb;
|
||||
size = <16>;
|
||||
intel-me {
|
||||
filename = "me.bin";
|
||||
pos-unset;
|
||||
offset-unset;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
sort-by-offset;
|
||||
end-at-4gb;
|
||||
size = <0x800000>;
|
||||
intel-descriptor {
|
||||
|
@ -14,7 +14,7 @@
|
|||
|
||||
intel-me {
|
||||
filename = "me.bin";
|
||||
pos-unset;
|
||||
offset-unset;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
sort-by-offset;
|
||||
end-at-4gb;
|
||||
size = <0x200>;
|
||||
u-boot-with-ucode-ptr {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
sort-by-offset;
|
||||
end-at-4gb;
|
||||
size = <0x200>;
|
||||
u-boot-with-ucode-ptr {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
sort-by-offset;
|
||||
end-at-4gb;
|
||||
size = <0x200>;
|
||||
u-boot-with-ucode-ptr {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
sort-by-offset;
|
||||
end-at-4gb;
|
||||
size = <0x200>;
|
||||
u-boot-with-ucode-ptr {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
sort-by-offset;
|
||||
end-at-4gb;
|
||||
size = <0x200>;
|
||||
u-boot-with-ucode-ptr {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
sort-by-offset;
|
||||
size = <0x200>;
|
||||
u-boot-with-ucode-ptr {
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
sort-by-offset;
|
||||
end-at-4gb;
|
||||
size = <0x200>;
|
||||
u-boot-with-ucode-ptr {
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
sort-by-offset;
|
||||
end-at-4gb;
|
||||
size = <16>;
|
||||
intel-me {
|
||||
filename = "me.bin";
|
||||
pos-unset;
|
||||
offset-unset;
|
||||
intval = <3>;
|
||||
intarray = <5 6>;
|
||||
byteval = [08];
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
sort-by-offset;
|
||||
end-at-4gb;
|
||||
size = <0x200>;
|
||||
u-boot-spl-with-ucode-ptr {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
};
|
||||
|
||||
u-boot {
|
||||
pos = <20>;
|
||||
offset = <20>;
|
||||
};
|
||||
|
||||
u-boot-spl2 {
|
||||
|
|
|
@ -24,5 +24,9 @@
|
|||
u-boot {
|
||||
};
|
||||
};
|
||||
section@2 {
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
sort-by-offset;
|
||||
end-at-4gb;
|
||||
size = <0x200>;
|
||||
u-boot-spl-with-ucode-ptr {
|
||||
|
|
14
tools/binman/test/62_entry_args.dts
Normal file
14
tools/binman/test/62_entry_args.dts
Normal file
|
@ -0,0 +1,14 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
_testing {
|
||||
test-str-fdt = "test0";
|
||||
test-int-fdt = <123>;
|
||||
};
|
||||
};
|
||||
};
|
13
tools/binman/test/63_entry_args_missing.dts
Normal file
13
tools/binman/test/63_entry_args_missing.dts
Normal file
|
@ -0,0 +1,13 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
_testing {
|
||||
test-str-fdt = "test0";
|
||||
};
|
||||
};
|
||||
};
|
14
tools/binman/test/64_entry_args_required.dts
Normal file
14
tools/binman/test/64_entry_args_required.dts
Normal file
|
@ -0,0 +1,14 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
_testing {
|
||||
require-args;
|
||||
test-str-fdt = "test0";
|
||||
};
|
||||
};
|
||||
};
|
15
tools/binman/test/65_entry_args_unknown_datatype.dts
Normal file
15
tools/binman/test/65_entry_args_unknown_datatype.dts
Normal file
|
@ -0,0 +1,15 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
_testing {
|
||||
test-str-fdt = "test0";
|
||||
test-int-fdt = <123>;
|
||||
force-bad-datatype;
|
||||
};
|
||||
};
|
||||
};
|
28
tools/binman/test/66_text.dts
Normal file
28
tools/binman/test/66_text.dts
Normal file
|
@ -0,0 +1,28 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
text {
|
||||
size = <8>;
|
||||
text-label = "test-id";
|
||||
};
|
||||
text2 {
|
||||
type = "text";
|
||||
text-label = "test-id2";
|
||||
};
|
||||
text3 {
|
||||
type = "text";
|
||||
text-label = "test-id3";
|
||||
};
|
||||
/* This one does not use command-line args */
|
||||
text4 {
|
||||
type = "text";
|
||||
text-label = "test-id4";
|
||||
test-id4 = "some text";
|
||||
};
|
||||
};
|
||||
};
|
29
tools/binman/test/67_fmap.dts
Normal file
29
tools/binman/test/67_fmap.dts
Normal file
|
@ -0,0 +1,29 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
section@0 {
|
||||
read-only;
|
||||
name-prefix = "ro-";
|
||||
size = <0x10>;
|
||||
pad-byte = <0x21>;
|
||||
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
section@1 {
|
||||
name-prefix = "rw-";
|
||||
size = <0x10>;
|
||||
pad-byte = <0x61>;
|
||||
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
fmap {
|
||||
};
|
||||
};
|
||||
};
|
12
tools/binman/test/68_blob_named_by_arg.dts
Normal file
12
tools/binman/test/68_blob_named_by_arg.dts
Normal file
|
@ -0,0 +1,12 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
cros-ec-rw {
|
||||
};
|
||||
};
|
||||
};
|
15
tools/binman/test/69_fill.dts
Normal file
15
tools/binman/test/69_fill.dts
Normal file
|
@ -0,0 +1,15 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
size = <16>;
|
||||
fill {
|
||||
size = <8>;
|
||||
fill-byte = [ff];
|
||||
};
|
||||
};
|
||||
};
|
14
tools/binman/test/70_fill_no_size.dts
Normal file
14
tools/binman/test/70_fill_no_size.dts
Normal file
|
@ -0,0 +1,14 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
size = <16>;
|
||||
fill {
|
||||
fill-byte = [ff];
|
||||
};
|
||||
};
|
||||
};
|
31
tools/binman/test/71_gbb.dts
Normal file
31
tools/binman/test/71_gbb.dts
Normal file
|
@ -0,0 +1,31 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
gbb {
|
||||
size = <0x2180>;
|
||||
flags {
|
||||
dev-screen-short-delay;
|
||||
load-option-roms;
|
||||
enable-alternate-os;
|
||||
force-dev-switch-on;
|
||||
force-dev-boot-usb;
|
||||
disable-fw-rollback-check;
|
||||
enter-triggers-tonorm;
|
||||
force-dev-boot-legacy;
|
||||
faft-key-override;
|
||||
disable-ec-software-sync;
|
||||
default-dev-boot-legacy;
|
||||
disable-pd-software-sync;
|
||||
disable-lid-shutdown;
|
||||
force-dev-boot-fastboot-full-cap;
|
||||
enable-serial;
|
||||
disable-dwmp;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
10
tools/binman/test/72_gbb_too_small.dts
Normal file
10
tools/binman/test/72_gbb_too_small.dts
Normal file
|
@ -0,0 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
binman {
|
||||
gbb {
|
||||
size = <0x200>;
|
||||
};
|
||||
};
|
||||
};
|
9
tools/binman/test/73_gbb_no_size.dts
Normal file
9
tools/binman/test/73_gbb_no_size.dts
Normal file
|
@ -0,0 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
binman {
|
||||
gbb {
|
||||
};
|
||||
};
|
||||
};
|
28
tools/binman/test/74_vblock.dts
Normal file
28
tools/binman/test/74_vblock.dts
Normal file
|
@ -0,0 +1,28 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u_boot: u-boot {
|
||||
};
|
||||
|
||||
vblock {
|
||||
content = <&u_boot &dtb>;
|
||||
keyblock = "firmware.keyblock";
|
||||
signprivate = "firmware_data_key.vbprivk";
|
||||
version = <1>;
|
||||
kernelkey = "kernel_subkey.vbpubk";
|
||||
preamble-flags = <1>;
|
||||
};
|
||||
|
||||
/*
|
||||
* Put this after the vblock so that its contents are not
|
||||
* available when the vblock first tries to obtain its contents
|
||||
*/
|
||||
dtb: u-boot-dtb {
|
||||
};
|
||||
};
|
||||
};
|
23
tools/binman/test/75_vblock_no_content.dts
Normal file
23
tools/binman/test/75_vblock_no_content.dts
Normal file
|
@ -0,0 +1,23 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u_boot: u-boot {
|
||||
};
|
||||
|
||||
vblock {
|
||||
keyblock = "firmware.keyblock";
|
||||
signprivate = "firmware_data_key.vbprivk";
|
||||
version = <1>;
|
||||
kernelkey = "kernel_subkey.vbpubk";
|
||||
preamble-flags = <1>;
|
||||
};
|
||||
|
||||
dtb: u-boot-dtb {
|
||||
};
|
||||
};
|
||||
};
|
24
tools/binman/test/76_vblock_bad_phandle.dts
Normal file
24
tools/binman/test/76_vblock_bad_phandle.dts
Normal file
|
@ -0,0 +1,24 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u_boot: u-boot {
|
||||
};
|
||||
|
||||
vblock {
|
||||
content = <1000>;
|
||||
keyblock = "firmware.keyblock";
|
||||
signprivate = "firmware_data_key.vbprivk";
|
||||
version = <1>;
|
||||
kernelkey = "kernel_subkey.vbpubk";
|
||||
preamble-flags = <1>;
|
||||
};
|
||||
|
||||
dtb: u-boot-dtb {
|
||||
};
|
||||
};
|
||||
};
|
27
tools/binman/test/77_vblock_bad_entry.dts
Normal file
27
tools/binman/test/77_vblock_bad_entry.dts
Normal file
|
@ -0,0 +1,27 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u_boot: u-boot {
|
||||
};
|
||||
|
||||
vblock {
|
||||
content = <&u_boot &other>;
|
||||
keyblock = "firmware.keyblock";
|
||||
signprivate = "firmware_data_key.vbprivk";
|
||||
version = <1>;
|
||||
kernelkey = "kernel_subkey.vbpubk";
|
||||
preamble-flags = <1>;
|
||||
};
|
||||
|
||||
dtb: u-boot-dtb {
|
||||
};
|
||||
};
|
||||
|
||||
other: other {
|
||||
};
|
||||
};
|
11
tools/binman/test/78_u_boot_tpl.dts
Normal file
11
tools/binman/test/78_u_boot_tpl.dts
Normal file
|
@ -0,0 +1,11 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
binman {
|
||||
u-boot-tpl {
|
||||
};
|
||||
u-boot-tpl-dtb {
|
||||
};
|
||||
};
|
||||
};
|
10
tools/binman/test/79_uses_pos.dts
Normal file
10
tools/binman/test/79_uses_pos.dts
Normal file
|
@ -0,0 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
binman {
|
||||
u-boot {
|
||||
pos = <10>;
|
||||
};
|
||||
};
|
||||
};
|
Binary file not shown.
|
@ -8,6 +8,6 @@
|
|||
#define CONFIG_BINMAN
|
||||
#include <binman_sym.h>
|
||||
|
||||
binman_sym_declare(unsigned long, u_boot_spl, pos);
|
||||
binman_sym_declare(unsigned long long, u_boot_spl2, pos);
|
||||
binman_sym_declare(unsigned long, u_boot_any, pos);
|
||||
binman_sym_declare(unsigned long, u_boot_spl, offset);
|
||||
binman_sym_declare(unsigned long long, u_boot_spl2, offset);
|
||||
binman_sym_declare(unsigned long, u_boot_any, image_pos);
|
||||
|
|
|
@ -181,7 +181,15 @@ class Node:
|
|||
self.subnodes = []
|
||||
self.props = {}
|
||||
|
||||
def _FindNode(self, name):
|
||||
def GetFdt(self):
|
||||
"""Get the Fdt object for this node
|
||||
|
||||
Returns:
|
||||
Fdt object
|
||||
"""
|
||||
return self._fdt
|
||||
|
||||
def FindNode(self, name):
|
||||
"""Find a node given its name
|
||||
|
||||
Args:
|
||||
|
@ -314,6 +322,17 @@ class Fdt:
|
|||
with open(self._fname) as fd:
|
||||
self._fdt_obj = libfdt.Fdt(fd.read())
|
||||
|
||||
def LookupPhandle(self, phandle):
|
||||
"""Look up a phandle
|
||||
|
||||
Args:
|
||||
phandle: Phandle to look up (int)
|
||||
|
||||
Returns:
|
||||
Node object the phandle points to
|
||||
"""
|
||||
return self.phandle_to_node.get(phandle)
|
||||
|
||||
def Scan(self, root='/'):
|
||||
"""Scan a device tree, building up a tree of Node objects
|
||||
|
||||
|
@ -349,7 +368,7 @@ class Fdt:
|
|||
if len(parts) < 2:
|
||||
return None
|
||||
for part in parts[1:]:
|
||||
node = node._FindNode(part)
|
||||
node = node.FindNode(part)
|
||||
if not node:
|
||||
return None
|
||||
return node
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
|
||||
# Utility functions for reading from a device tree. Once the upstream pylibfdt
|
||||
# implementation advances far enough, we should be able to drop these.
|
||||
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
|
@ -90,6 +93,16 @@ def EnsureCompiled(fname, capture_stderr=False):
|
|||
return dtb_output
|
||||
|
||||
def GetInt(node, propname, default=None):
|
||||
"""Get an integer from a property
|
||||
|
||||
Args:
|
||||
node: Node object to read from
|
||||
propname: property name to read
|
||||
default: Default value to use if the node/property do not exist
|
||||
|
||||
Returns:
|
||||
Integer value read, or default if none
|
||||
"""
|
||||
prop = node.props.get(propname)
|
||||
if not prop:
|
||||
return default
|
||||
|
@ -100,6 +113,16 @@ def GetInt(node, propname, default=None):
|
|||
return value
|
||||
|
||||
def GetString(node, propname, default=None):
|
||||
"""Get a string from a property
|
||||
|
||||
Args:
|
||||
node: Node object to read from
|
||||
propname: property name to read
|
||||
default: Default value to use if the node/property do not exist
|
||||
|
||||
Returns:
|
||||
String value read, or default if none
|
||||
"""
|
||||
prop = node.props.get(propname)
|
||||
if not prop:
|
||||
return default
|
||||
|
@ -110,6 +133,79 @@ def GetString(node, propname, default=None):
|
|||
return value
|
||||
|
||||
def GetBool(node, propname, default=False):
|
||||
"""Get an boolean from a property
|
||||
|
||||
Args:
|
||||
node: Node object to read from
|
||||
propname: property name to read
|
||||
default: Default value to use if the node/property do not exist
|
||||
|
||||
Returns:
|
||||
Boolean value read, or default if none (if you set this to True the
|
||||
function will always return True)
|
||||
"""
|
||||
if propname in node.props:
|
||||
return True
|
||||
return default
|
||||
|
||||
def GetByte(node, propname, default=None):
|
||||
"""Get an byte from a property
|
||||
|
||||
Args:
|
||||
node: Node object to read from
|
||||
propname: property name to read
|
||||
default: Default value to use if the node/property do not exist
|
||||
|
||||
Returns:
|
||||
Byte value read, or default if none
|
||||
"""
|
||||
prop = node.props.get(propname)
|
||||
if not prop:
|
||||
return default
|
||||
value = prop.value
|
||||
if isinstance(value, list):
|
||||
raise ValueError("Node '%s' property '%s' has list value: expecting "
|
||||
"a single byte" % (node.name, propname))
|
||||
if len(value) != 1:
|
||||
raise ValueError("Node '%s' property '%s' has length %d, expecting %d" %
|
||||
(node.name, propname, len(value), 1))
|
||||
return ord(value[0])
|
||||
|
||||
def GetPhandleList(node, propname):
|
||||
"""Get a list of phandles from a property
|
||||
|
||||
Args:
|
||||
node: Node object to read from
|
||||
propname: property name to read
|
||||
|
||||
Returns:
|
||||
List of phandles read, each an integer
|
||||
"""
|
||||
prop = node.props.get(propname)
|
||||
if not prop:
|
||||
return None
|
||||
value = prop.value
|
||||
if not isinstance(value, list):
|
||||
value = [value]
|
||||
return [fdt32_to_cpu(v) for v in value]
|
||||
|
||||
def GetDatatype(node, propname, datatype):
|
||||
"""Get a value of a given type from a property
|
||||
|
||||
Args:
|
||||
node: Node object to read from
|
||||
propname: property name to read
|
||||
datatype: Type to read (str or int)
|
||||
|
||||
Returns:
|
||||
value read, or None if none
|
||||
|
||||
Raises:
|
||||
ValueError if datatype is not str or int
|
||||
"""
|
||||
if datatype == str:
|
||||
return GetString(node, propname)
|
||||
elif datatype == int:
|
||||
return GetInt(node, propname)
|
||||
raise ValueError("fdt_util internal error: Unknown data type '%s'" %
|
||||
datatype)
|
||||
|
|
|
@ -115,6 +115,9 @@ class TestFdt(unittest.TestCase):
|
|||
fdt.CheckErr(-libfdt.NOTFOUND, 'hello')
|
||||
self.assertIn('FDT_ERR_NOTFOUND: hello', str(e.exception))
|
||||
|
||||
def testGetFdt(self):
|
||||
node = self.dtb.GetNode('/spl-test')
|
||||
self.assertEqual(self.dtb, node.GetFdt())
|
||||
|
||||
class TestNode(unittest.TestCase):
|
||||
"""Test operation of the Node class"""
|
||||
|
@ -155,12 +158,12 @@ class TestNode(unittest.TestCase):
|
|||
self.assertEqual(prop.value, value)
|
||||
|
||||
def testFindNode(self):
|
||||
"""Tests that we can find a node using the _FindNode() functoin"""
|
||||
node = self.dtb.GetRoot()._FindNode('i2c@0')
|
||||
"""Tests that we can find a node using the FindNode() functoin"""
|
||||
node = self.dtb.GetRoot().FindNode('i2c@0')
|
||||
self.assertEqual('i2c@0', node.name)
|
||||
subnode = node._FindNode('pmic@9')
|
||||
subnode = node.FindNode('pmic@9')
|
||||
self.assertEqual('pmic@9', subnode.name)
|
||||
self.assertEqual(None, node._FindNode('missing'))
|
||||
self.assertEqual(None, node.FindNode('missing'))
|
||||
|
||||
def testRefreshMissingNode(self):
|
||||
"""Test refreshing offsets when an extra node is present in dtb"""
|
||||
|
@ -188,6 +191,14 @@ class TestNode(unittest.TestCase):
|
|||
self.assertIn("Internal error, property 'notstring' missing, offset ",
|
||||
str(e.exception))
|
||||
|
||||
def testLookupPhandle(self):
|
||||
"""Test looking up a single phandle"""
|
||||
dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
|
||||
node = dtb.GetNode('/phandle-source2')
|
||||
prop = node.props['clocks']
|
||||
target = dtb.GetNode('/phandle-target')
|
||||
self.assertEqual(target, dtb.LookupPhandle(fdt32_to_cpu(prop.value)))
|
||||
|
||||
|
||||
class TestProp(unittest.TestCase):
|
||||
"""Test operation of the Prop class"""
|
||||
|
@ -380,6 +391,36 @@ class TestFdtUtil(unittest.TestCase):
|
|||
self.assertEqual(True, fdt_util.GetBool(self.node, 'missing', True))
|
||||
self.assertEqual(False, fdt_util.GetBool(self.node, 'missing', False))
|
||||
|
||||
def testGetByte(self):
|
||||
self.assertEqual(5, fdt_util.GetByte(self.node, 'byteval'))
|
||||
self.assertEqual(3, fdt_util.GetByte(self.node, 'missing', 3))
|
||||
|
||||
with self.assertRaises(ValueError) as e:
|
||||
fdt_util.GetByte(self.node, 'longbytearray')
|
||||
self.assertIn("property 'longbytearray' has list value: expecting a "
|
||||
'single byte', str(e.exception))
|
||||
|
||||
with self.assertRaises(ValueError) as e:
|
||||
fdt_util.GetByte(self.node, 'intval')
|
||||
self.assertIn("property 'intval' has length 4, expecting 1",
|
||||
str(e.exception))
|
||||
|
||||
def testGetPhandleList(self):
|
||||
dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
|
||||
node = dtb.GetNode('/phandle-source2')
|
||||
self.assertEqual([1], fdt_util.GetPhandleList(node, 'clocks'))
|
||||
node = dtb.GetNode('/phandle-source')
|
||||
self.assertEqual([1, 2, 11, 3, 12, 13, 1],
|
||||
fdt_util.GetPhandleList(node, 'clocks'))
|
||||
self.assertEqual(None, fdt_util.GetPhandleList(node, 'missing'))
|
||||
|
||||
def testGetDataType(self):
|
||||
self.assertEqual(1, fdt_util.GetDatatype(self.node, 'intval', int))
|
||||
self.assertEqual('message', fdt_util.GetDatatype(self.node, 'stringval',
|
||||
str))
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self.assertEqual(3, fdt_util.GetDatatype(self.node, 'boolval',
|
||||
bool))
|
||||
def testFdtCellsToCpu(self):
|
||||
val = self.node.props['intarray'].value
|
||||
self.assertEqual(0, fdt_util.fdt_cells_to_cpu(val, 0))
|
||||
|
|
|
@ -61,8 +61,12 @@ def RunPipe(pipe_list, infile=None, outfile=None,
|
|||
"""
|
||||
if test_result:
|
||||
if hasattr(test_result, '__call__'):
|
||||
return test_result(pipe_list=pipe_list)
|
||||
return test_result
|
||||
result = test_result(pipe_list=pipe_list)
|
||||
if result:
|
||||
return result
|
||||
else:
|
||||
return test_result
|
||||
# No result: fall through to normal processing
|
||||
result = CommandResult()
|
||||
last_pipe = None
|
||||
pipeline = list(pipe_list)
|
||||
|
|
|
@ -3,16 +3,26 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
#
|
||||
|
||||
import command
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
import tout
|
||||
|
||||
# Output directly (generally this is temporary)
|
||||
outdir = None
|
||||
indirs = None
|
||||
|
||||
# True to keep the output directory around after exiting
|
||||
preserve_outdir = False
|
||||
|
||||
# Path to the Chrome OS chroot, if we know it
|
||||
chroot_path = None
|
||||
|
||||
# Search paths to use for Filename(), used to find files
|
||||
search_paths = []
|
||||
|
||||
|
||||
def PrepareOutputDir(dirname, preserve=False):
|
||||
"""Select an output directory, ensuring it exists.
|
||||
|
||||
|
@ -106,8 +116,8 @@ def GetInputFilename(fname):
|
|||
if os.path.exists(pathname):
|
||||
return pathname
|
||||
|
||||
raise ValueError("Filename '%s' not found in input path (%s)" %
|
||||
(fname, ','.join(indir)))
|
||||
raise ValueError("Filename '%s' not found in input path (%s) (cwd='%s')" %
|
||||
(fname, ','.join(indir), os.getcwd()))
|
||||
|
||||
def Align(pos, align):
|
||||
if align:
|
||||
|
@ -117,3 +127,67 @@ def Align(pos, align):
|
|||
|
||||
def NotPowerOfTwo(num):
|
||||
return num and (num & (num - 1))
|
||||
|
||||
def Run(name, *args):
|
||||
command.Run(name, *args, cwd=outdir)
|
||||
|
||||
def Filename(fname):
|
||||
"""Resolve a file path to an absolute path.
|
||||
|
||||
If fname starts with ##/ and chroot is available, ##/ gets replaced with
|
||||
the chroot path. If chroot is not available, this file name can not be
|
||||
resolved, `None' is returned.
|
||||
|
||||
If fname is not prepended with the above prefix, and is not an existing
|
||||
file, the actual file name is retrieved from the passed in string and the
|
||||
search_paths directories (if any) are searched to for the file. If found -
|
||||
the path to the found file is returned, `None' is returned otherwise.
|
||||
|
||||
Args:
|
||||
fname: a string, the path to resolve.
|
||||
|
||||
Returns:
|
||||
Absolute path to the file or None if not found.
|
||||
"""
|
||||
if fname.startswith('##/'):
|
||||
if chroot_path:
|
||||
fname = os.path.join(chroot_path, fname[3:])
|
||||
else:
|
||||
return None
|
||||
|
||||
# Search for a pathname that exists, and return it if found
|
||||
if fname and not os.path.exists(fname):
|
||||
for path in search_paths:
|
||||
pathname = os.path.join(path, os.path.basename(fname))
|
||||
if os.path.exists(pathname):
|
||||
return pathname
|
||||
|
||||
# If not found, just return the standard, unchanged path
|
||||
return fname
|
||||
|
||||
def ReadFile(fname):
|
||||
"""Read and return the contents of a file.
|
||||
|
||||
Args:
|
||||
fname: path to filename to read, where ## signifiies the chroot.
|
||||
|
||||
Returns:
|
||||
data read from file, as a string.
|
||||
"""
|
||||
with open(Filename(fname), 'rb') as fd:
|
||||
data = fd.read()
|
||||
#self._out.Info("Read file '%s' size %d (%#0x)" %
|
||||
#(fname, len(data), len(data)))
|
||||
return data
|
||||
|
||||
def WriteFile(fname, data):
|
||||
"""Write data into a file.
|
||||
|
||||
Args:
|
||||
fname: path to filename to write
|
||||
data: data to write to file, as a string
|
||||
"""
|
||||
#self._out.Info("Write file '%s' size %d (%#0x)" %
|
||||
#(fname, len(data), len(data)))
|
||||
with open(Filename(fname), 'wb') as fd:
|
||||
fd.write(data)
|
||||
|
|
Loading…
Add table
Reference in a new issue