mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-21 22:51:37 +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";
|
filename = "spl/sunxi-spl.bin";
|
||||||
};
|
};
|
||||||
u-boot-img {
|
u-boot-img {
|
||||||
pos = <CONFIG_SPL_PAD_TO>;
|
offset = <CONFIG_SPL_PAD_TO>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
u-boot-spl {
|
u-boot-spl {
|
||||||
};
|
};
|
||||||
u-boot {
|
u-boot {
|
||||||
pos = <(U_BOOT_OFFSET)>;
|
offset = <(U_BOOT_OFFSET)>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
u-boot-spl {
|
u-boot-spl {
|
||||||
};
|
};
|
||||||
u-boot {
|
u-boot {
|
||||||
pos = <(U_BOOT_OFFSET)>;
|
offset = <(U_BOOT_OFFSET)>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
u-boot-spl {
|
u-boot-spl {
|
||||||
};
|
};
|
||||||
u-boot-nodtb {
|
u-boot-nodtb {
|
||||||
pos = <(U_BOOT_OFFSET)>;
|
offset = <(U_BOOT_OFFSET)>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
binman {
|
binman {
|
||||||
filename = "u-boot.rom";
|
filename = "u-boot.rom";
|
||||||
end-at-4gb;
|
end-at-4gb;
|
||||||
sort-by-pos;
|
sort-by-offset;
|
||||||
pad-byte = <0xff>;
|
pad-byte = <0xff>;
|
||||||
size = <CONFIG_ROM_SIZE>;
|
size = <CONFIG_ROM_SIZE>;
|
||||||
#ifdef CONFIG_HAVE_INTEL_ME
|
#ifdef CONFIG_HAVE_INTEL_ME
|
||||||
|
@ -24,18 +24,18 @@
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_SPL
|
#ifdef CONFIG_SPL
|
||||||
u-boot-spl-with-ucode-ptr {
|
u-boot-spl-with-ucode-ptr {
|
||||||
pos = <CONFIG_SPL_TEXT_BASE>;
|
offset = <CONFIG_SPL_TEXT_BASE>;
|
||||||
};
|
};
|
||||||
|
|
||||||
u-boot-dtb-with-ucode2 {
|
u-boot-dtb-with-ucode2 {
|
||||||
type = "u-boot-dtb-with-ucode";
|
type = "u-boot-dtb-with-ucode";
|
||||||
};
|
};
|
||||||
u-boot {
|
u-boot {
|
||||||
pos = <0xfff00000>;
|
offset = <0xfff00000>;
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
u-boot-with-ucode-ptr {
|
u-boot-with-ucode-ptr {
|
||||||
pos = <CONFIG_SYS_TEXT_BASE>;
|
offset = <CONFIG_SYS_TEXT_BASE>;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
u-boot-dtb-with-ucode {
|
u-boot-dtb-with-ucode {
|
||||||
|
@ -45,45 +45,45 @@
|
||||||
};
|
};
|
||||||
#ifdef CONFIG_HAVE_MRC
|
#ifdef CONFIG_HAVE_MRC
|
||||||
intel-mrc {
|
intel-mrc {
|
||||||
pos = <CONFIG_X86_MRC_ADDR>;
|
offset = <CONFIG_X86_MRC_ADDR>;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_HAVE_FSP
|
#ifdef CONFIG_HAVE_FSP
|
||||||
intel-fsp {
|
intel-fsp {
|
||||||
filename = CONFIG_FSP_FILE;
|
filename = CONFIG_FSP_FILE;
|
||||||
pos = <CONFIG_FSP_ADDR>;
|
offset = <CONFIG_FSP_ADDR>;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_HAVE_CMC
|
#ifdef CONFIG_HAVE_CMC
|
||||||
intel-cmc {
|
intel-cmc {
|
||||||
filename = CONFIG_CMC_FILE;
|
filename = CONFIG_CMC_FILE;
|
||||||
pos = <CONFIG_CMC_ADDR>;
|
offset = <CONFIG_CMC_ADDR>;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_HAVE_VGA_BIOS
|
#ifdef CONFIG_HAVE_VGA_BIOS
|
||||||
intel-vga {
|
intel-vga {
|
||||||
filename = CONFIG_VGA_BIOS_FILE;
|
filename = CONFIG_VGA_BIOS_FILE;
|
||||||
pos = <CONFIG_VGA_BIOS_ADDR>;
|
offset = <CONFIG_VGA_BIOS_ADDR>;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_HAVE_VBT
|
#ifdef CONFIG_HAVE_VBT
|
||||||
intel-vbt {
|
intel-vbt {
|
||||||
filename = CONFIG_VBT_FILE;
|
filename = CONFIG_VBT_FILE;
|
||||||
pos = <CONFIG_VBT_ADDR>;
|
offset = <CONFIG_VBT_ADDR>;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_HAVE_REFCODE
|
#ifdef CONFIG_HAVE_REFCODE
|
||||||
intel-refcode {
|
intel-refcode {
|
||||||
pos = <CONFIG_X86_REFCODE_ADDR>;
|
offset = <CONFIG_X86_REFCODE_ADDR>;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_SPL
|
#ifdef CONFIG_SPL
|
||||||
x86-start16-spl {
|
x86-start16-spl {
|
||||||
pos = <CONFIG_SYS_X86_START16>;
|
offset = <CONFIG_SYS_X86_START16>;
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
x86-start16 {
|
x86-start16 {
|
||||||
pos = <CONFIG_SYS_X86_START16>;
|
offset = <CONFIG_SYS_X86_START16>;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,7 +34,7 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||||
u32 *boot_params_ptr = NULL;
|
u32 *boot_params_ptr = NULL;
|
||||||
|
|
||||||
/* See spl.h for information about this */
|
/* 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 */
|
/* Define board data structure */
|
||||||
static bd_t bdata __attribute__ ((section(".data")));
|
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)
|
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;
|
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;
|
load.read = spl_ram_load_read;
|
||||||
spl_load_simple_fit(spl_image, &load, 0, header);
|
spl_load_simple_fit(spl_image, &load, 0, header);
|
||||||
} else {
|
} 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");
|
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
|
* 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.
|
* 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.
|
* spl_load_simple_fit() - Loads a fit image from a device.
|
||||||
|
|
|
@ -238,7 +238,7 @@ below:
|
||||||
filename = "spl/sunxi-spl.bin";
|
filename = "spl/sunxi-spl.bin";
|
||||||
};
|
};
|
||||||
u-boot {
|
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.
|
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
|
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
|
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
|
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.
|
The attributes supported for entries are described below.
|
||||||
|
|
||||||
pos:
|
offset:
|
||||||
This sets the position of an entry within the image. The first byte
|
This sets the offset of an entry within the image or section containing
|
||||||
of the image is normally at position 0. If 'pos' is not provided,
|
it. The first byte of the image is normally at offset 0. If 'offset' is
|
||||||
binman sets it to the end of the previous region, or the start of
|
not provided, binman sets it to the end of the previous region, or the
|
||||||
the image's entry area (normally 0) if there is no previous region.
|
start of the image's entry area (normally 0) if there is no previous
|
||||||
|
region.
|
||||||
|
|
||||||
align:
|
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
|
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
|
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
|
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"'
|
possible to use any name, and then add (for example) 'type = "u-boot"'
|
||||||
to specify the type.
|
to specify the type.
|
||||||
|
|
||||||
pos-unset:
|
offset-unset:
|
||||||
Indicates that the position of this entry should not be set by placing
|
Indicates that the offset of this entry should not be set by placing
|
||||||
it immediately after the entry before. Instead, is set by another
|
it immediately after the entry before. Instead, is set by another
|
||||||
entry which knows where this entry should go. When this boolean
|
entry which knows where this entry should go. When this boolean
|
||||||
property is present, binman will give an error if another entry does
|
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
|
The attributes supported for images are described below. Several are similar
|
||||||
|
@ -338,7 +345,7 @@ align-size:
|
||||||
|
|
||||||
pad-before:
|
pad-before:
|
||||||
This sets the padding before the image entries. The first entry will
|
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:
|
pad-after:
|
||||||
This sets the padding after the image entries. The padding will be
|
This sets the padding after the image entries. The padding will be
|
||||||
|
@ -351,15 +358,15 @@ pad-byte:
|
||||||
filename:
|
filename:
|
||||||
This specifies the image filename. It defaults to 'image.bin'.
|
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
|
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
|
are in increasing positional order. This can be used when your entry
|
||||||
order may not match the positional order. A common situation is where
|
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.
|
not known a priori.
|
||||||
|
|
||||||
This is a boolean property so needs no value. To enable it, add a
|
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:
|
multiple-images:
|
||||||
Normally only a single image is generated. To create more than one
|
Normally only a single image is generated. To create more than one
|
||||||
|
@ -383,11 +390,11 @@ multiple-images:
|
||||||
};
|
};
|
||||||
|
|
||||||
end-at-4gb:
|
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
|
up so that the image finished at the 4GB boundary. This boolean
|
||||||
option can be enabled to support this. The image size must be
|
option can be enabled to support this. The image size must be
|
||||||
provided so that binman knows when the image should start. For an
|
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.
|
this option, instead of 0 without this option.
|
||||||
|
|
||||||
|
|
||||||
|
@ -446,6 +453,15 @@ name-prefix:
|
||||||
distinguish binaries with otherwise identical names.
|
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
|
Special properties
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
@ -463,7 +479,7 @@ Order of image creation
|
||||||
Image creation proceeds in the following order, for each entry in the image.
|
Image creation proceeds in the following order, for each entry in the image.
|
||||||
|
|
||||||
1. AddMissingProperties() - binman can add calculated values to the device
|
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
|
entry. This method adds any properties associated with this, expanding the
|
||||||
device tree as needed. These properties can have placeholder values which are
|
device tree as needed. These properties can have placeholder values which are
|
||||||
set later by SetCalculatedProperties(). By that stage the size of sections
|
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
|
retry calling the functions a few times if False is returned, allowing
|
||||||
dependencies between the contents of different entries.
|
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
|
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
|
entry name and the value is a tuple (offset, size). This allows an entry to
|
||||||
provide the position and size for other entries. The default implementation
|
provide the offset and size for other entries. The default implementation
|
||||||
of GetEntryPositions() returns {}.
|
of GetEntryOffsets() returns {}.
|
||||||
|
|
||||||
5. PackEntries() - calls Entry.Pack() which figures out the position and
|
5. PackEntries() - calls Entry.Pack() which figures out the offset and
|
||||||
size of an entry. The 'current' image position is passed in, and the function
|
size of an entry. The 'current' image offset is passed in, and the function
|
||||||
returns the position immediately after the entry being packed. The default
|
returns the offset immediately after the entry being packed. The default
|
||||||
implementation of Pack() is usually sufficient.
|
implementation of Pack() is usually sufficient.
|
||||||
|
|
||||||
6. CheckSize() - checks that the contents of all the entries fits within
|
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.
|
outside the image.
|
||||||
|
|
||||||
8. SetCalculatedProperties() - update any calculated properties in the device
|
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.
|
9. ProcessEntryContents() - this calls Entry.ProcessContents() on each entry.
|
||||||
The default implementatoin does nothing. This can be overriden to adjust the
|
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
|
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
|
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.
|
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.
|
what happens in this stage.
|
||||||
|
|
||||||
11. BuildImage() - builds the image and writes it to a file. This is the final
|
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)
|
# 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.
|
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
|
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
|
Binman allows you to declare symbols in the SPL image which are filled in
|
||||||
with their correct values during the build. For example:
|
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.
|
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:
|
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
|
the whole image has been loaded, or is available in flash. You can then jump to
|
||||||
that address to start U-Boot.
|
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.
|
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
|
Map files
|
||||||
---------
|
---------
|
||||||
|
|
||||||
The -m option causes binman to output a .map file for each image that it
|
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
|
Offset Size Name
|
||||||
|
00000000 00000028 main-section
|
||||||
00000000 00000010 section@0
|
00000000 00000010 section@0
|
||||||
00000000 00000004 u-boot
|
00000000 00000004 u-boot
|
||||||
00000010 00000010 section@1
|
00000010 00000010 section@1
|
||||||
00000000 00000004 u-boot
|
00000000 00000004 u-boot
|
||||||
|
|
||||||
This shows a hierarchical image with two sections, each with a single entry. The
|
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
|
offsets 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 entries are relative to their respective sections. The size of
|
||||||
each entry is also shown, in bytes (hex). The indentation shows the entries
|
each entry is also shown, in bytes (hex). The indentation shows the entries
|
||||||
nested inside their sections.
|
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
|
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,
|
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.
|
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
|
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
|
so they don't need to be set in the binman decription. It can also adjust
|
||||||
entry contents.
|
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 1
|
||||||
return 0
|
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():
|
def RunTestCoverage():
|
||||||
"""Run the tests and check that we get 100% coverage"""
|
"""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]
|
all_set = set([os.path.splitext(os.path.basename(item))[0]
|
||||||
for item in glob_list if '_testing' not in item])
|
for item in glob_list if '_testing' not in item])
|
||||||
test_util.RunTestCoverage('tools/binman/binman.py', None,
|
test_util.RunTestCoverage('tools/binman/binman.py', None,
|
||||||
|
@ -107,13 +118,8 @@ def RunBinman(options, args):
|
||||||
elif options.test_coverage:
|
elif options.test_coverage:
|
||||||
RunTestCoverage()
|
RunTestCoverage()
|
||||||
|
|
||||||
elif options.full_help:
|
elif options.entry_docs:
|
||||||
pager = os.getenv('PAGER')
|
control.WriteEntryDocs(GetEntryModules())
|
||||||
if not pager:
|
|
||||||
pager = 'more'
|
|
||||||
fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
|
|
||||||
'README')
|
|
||||||
command.Run(pager, fname)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -25,22 +25,21 @@ class Section(object):
|
||||||
_size: Section size in bytes, or None if not known yet
|
_size: Section size in bytes, or None if not known yet
|
||||||
_align_size: Section size alignment, or None
|
_align_size: Section size alignment, or None
|
||||||
_pad_before: Number of bytes before the first entry starts. This
|
_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
|
_pad_after: Number of bytes after the last entry ends. The last
|
||||||
entry will finish on or before this boundary
|
entry will finish on or before this boundary
|
||||||
_pad_byte: Byte to use to pad the section where there is no entry
|
_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
|
must be in-order in the device tree description
|
||||||
_skip_at_start: Number of bytes before the first entry starts. These
|
_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.
|
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.
|
in the image file.
|
||||||
_end_4gb: Indicates that the section ends at the 4GB boundary. This is
|
_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
|
used for x86 images, which want to use offsets such that a memory
|
||||||
memory address (like 0xff800000) is the first entry position.
|
address (like 0xff800000) is the first entry offset. This causes
|
||||||
This causes _skip_at_start to be set to the starting memory
|
_skip_at_start to be set to the starting memory address.
|
||||||
address.
|
|
||||||
_name_prefix: Prefix to add to the name of all entries within this
|
_name_prefix: Prefix to add to the name of all entries within this
|
||||||
section
|
section
|
||||||
_entries: OrderedDict() of entries
|
_entries: OrderedDict() of entries
|
||||||
|
@ -51,7 +50,9 @@ class Section(object):
|
||||||
import entry
|
import entry
|
||||||
from entry import Entry
|
from entry import Entry
|
||||||
|
|
||||||
|
self._name = name
|
||||||
self._node = node
|
self._node = node
|
||||||
|
self._offset = 0
|
||||||
self._size = None
|
self._size = None
|
||||||
self._align_size = None
|
self._align_size = None
|
||||||
self._pad_before = 0
|
self._pad_before = 0
|
||||||
|
@ -76,7 +77,7 @@ class Section(object):
|
||||||
self._pad_before = fdt_util.GetInt(self._node, 'pad-before', 0)
|
self._pad_before = fdt_util.GetInt(self._node, 'pad-before', 0)
|
||||||
self._pad_after = fdt_util.GetInt(self._node, 'pad-after', 0)
|
self._pad_after = fdt_util.GetInt(self._node, 'pad-after', 0)
|
||||||
self._pad_byte = fdt_util.GetInt(self._node, 'pad-byte', 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')
|
self._end_4gb = fdt_util.GetBool(self._node, 'end-at-4gb')
|
||||||
if self._end_4gb and not self._size:
|
if self._end_4gb and not self._size:
|
||||||
self._Raise("Section size must be provided when using end-at-4gb")
|
self._Raise("Section size must be provided when using end-at-4gb")
|
||||||
|
@ -90,11 +91,21 @@ class Section(object):
|
||||||
entry.SetPrefix(self._name_prefix)
|
entry.SetPrefix(self._name_prefix)
|
||||||
self._entries[node.name] = entry
|
self._entries[node.name] = entry
|
||||||
|
|
||||||
|
def SetOffset(self, offset):
|
||||||
|
self._offset = offset
|
||||||
|
|
||||||
def AddMissingProperties(self):
|
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():
|
for entry in self._entries.values():
|
||||||
entry.AddMissingProperties()
|
entry.AddMissingProperties()
|
||||||
|
|
||||||
def SetCalculatedProperties(self):
|
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():
|
for entry in self._entries.values():
|
||||||
entry.SetCalculatedProperties()
|
entry.SetCalculatedProperties()
|
||||||
|
|
||||||
|
@ -117,7 +128,7 @@ class Section(object):
|
||||||
"""Check that the section contents does not exceed its size, etc."""
|
"""Check that the section contents does not exceed its size, etc."""
|
||||||
contents_size = 0
|
contents_size = 0
|
||||||
for entry in self._entries.values():
|
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
|
contents_size -= self._skip_at_start
|
||||||
|
|
||||||
|
@ -190,39 +201,41 @@ class Section(object):
|
||||||
'contents: remaining %s' % todo)
|
'contents: remaining %s' % todo)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _SetEntryPosSize(self, name, pos, size):
|
def _SetEntryOffsetSize(self, name, offset, size):
|
||||||
"""Set the position and size of an entry
|
"""Set the offset and size of an entry
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name: Entry name to update
|
name: Entry name to update
|
||||||
pos: New position
|
offset: New offset
|
||||||
size: New size
|
size: New size
|
||||||
"""
|
"""
|
||||||
entry = self._entries.get(name)
|
entry = self._entries.get(name)
|
||||||
if not entry:
|
if not entry:
|
||||||
self._Raise("Unable to set pos/size for unknown entry '%s'" % name)
|
self._Raise("Unable to set offset/size for unknown entry '%s'" %
|
||||||
entry.SetPositionSize(self._skip_at_start + pos, size)
|
name)
|
||||||
|
entry.SetOffsetSize(self._skip_at_start + offset, size)
|
||||||
|
|
||||||
def GetEntryPositions(self):
|
def GetEntryOffsets(self):
|
||||||
"""Handle entries that want to set the position/size of other entries
|
"""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.
|
of entries to update, it updates them.
|
||||||
"""
|
"""
|
||||||
for entry in self._entries.values():
|
for entry in self._entries.values():
|
||||||
pos_dict = entry.GetPositions()
|
offset_dict = entry.GetOffsets()
|
||||||
for name, info in pos_dict.iteritems():
|
for name, info in offset_dict.iteritems():
|
||||||
self._SetEntryPosSize(name, *info)
|
self._SetEntryOffsetSize(name, *info)
|
||||||
|
|
||||||
def PackEntries(self):
|
def PackEntries(self):
|
||||||
"""Pack all entries into the section"""
|
"""Pack all entries into the section"""
|
||||||
pos = self._skip_at_start
|
offset = self._skip_at_start
|
||||||
for entry in self._entries.values():
|
for entry in self._entries.values():
|
||||||
pos = entry.Pack(pos)
|
offset = entry.Pack(offset)
|
||||||
|
self._size = self.CheckSize()
|
||||||
|
|
||||||
def _SortEntries(self):
|
def _SortEntries(self):
|
||||||
"""Sort entries by position"""
|
"""Sort entries by offset"""
|
||||||
entries = sorted(self._entries.values(), key=lambda entry: entry.pos)
|
entries = sorted(self._entries.values(), key=lambda entry: entry.offset)
|
||||||
self._entries.clear()
|
self._entries.clear()
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
self._entries[entry._node.name] = entry
|
self._entries[entry._node.name] = entry
|
||||||
|
@ -231,23 +244,28 @@ class Section(object):
|
||||||
"""Check that entries do not overlap or extend outside the section"""
|
"""Check that entries do not overlap or extend outside the section"""
|
||||||
if self._sort:
|
if self._sort:
|
||||||
self._SortEntries()
|
self._SortEntries()
|
||||||
pos = 0
|
offset = 0
|
||||||
prev_name = 'None'
|
prev_name = 'None'
|
||||||
for entry in self._entries.values():
|
for entry in self._entries.values():
|
||||||
entry.CheckPosition()
|
entry.CheckOffset()
|
||||||
if (entry.pos < self._skip_at_start or
|
if (entry.offset < self._skip_at_start or
|
||||||
entry.pos >= self._skip_at_start + self._size):
|
entry.offset >= self._skip_at_start + self._size):
|
||||||
entry.Raise("Position %#x (%d) is outside the section starting "
|
entry.Raise("Offset %#x (%d) is outside the section starting "
|
||||||
"at %#x (%d)" %
|
"at %#x (%d)" %
|
||||||
(entry.pos, entry.pos, self._skip_at_start,
|
(entry.offset, entry.offset, self._skip_at_start,
|
||||||
self._skip_at_start))
|
self._skip_at_start))
|
||||||
if entry.pos < pos:
|
if entry.offset < offset:
|
||||||
entry.Raise("Position %#x (%d) overlaps with previous entry '%s' "
|
entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' "
|
||||||
"ending at %#x (%d)" %
|
"ending at %#x (%d)" %
|
||||||
(entry.pos, entry.pos, prev_name, pos, pos))
|
(entry.offset, entry.offset, prev_name, offset, offset))
|
||||||
pos = entry.pos + entry.size
|
offset = entry.offset + entry.size
|
||||||
prev_name = entry.GetPath()
|
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):
|
def ProcessEntryContents(self):
|
||||||
"""Call the ProcessContents() method for each entry
|
"""Call the ProcessContents() method for each entry
|
||||||
|
|
||||||
|
@ -261,18 +279,18 @@ class Section(object):
|
||||||
for entry in self._entries.values():
|
for entry in self._entries.values():
|
||||||
entry.WriteSymbols(self)
|
entry.WriteSymbols(self)
|
||||||
|
|
||||||
def BuildSection(self, fd, base_pos):
|
def BuildSection(self, fd, base_offset):
|
||||||
"""Write the section to a file"""
|
"""Write the section to a file"""
|
||||||
fd.seek(base_pos)
|
fd.seek(base_offset)
|
||||||
fd.write(self.GetData())
|
fd.write(self.GetData())
|
||||||
|
|
||||||
def GetData(self):
|
def GetData(self):
|
||||||
"""Write the section to a file"""
|
"""Get the contents of the section"""
|
||||||
section_data = chr(self._pad_byte) * self._size
|
section_data = chr(self._pad_byte) * self._size
|
||||||
|
|
||||||
for entry in self._entries.values():
|
for entry in self._entries.values():
|
||||||
data = entry.GetData()
|
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 = (section_data[:base] + data +
|
||||||
section_data[base + len(data):])
|
section_data[base + len(data):])
|
||||||
return section_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
|
Looks up a symbol in an ELF file. Only entry types which come from an
|
||||||
ELF image can be used by this function.
|
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:
|
Args:
|
||||||
sym_name: Symbol name in the ELF file to look up in the format
|
sym_name: Symbol name in the ELF file to look up in the format
|
||||||
_binman_<entry>_prop_<property> where <entry> is the name of
|
_binman_<entry>_prop_<property> where <entry> is the name of
|
||||||
the entry and <property> is the property to find (e.g.
|
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.
|
_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)
|
u-boot-img and u-boot-nodtb)
|
||||||
optional: True if the symbol is optional. If False this function
|
optional: True if the symbol is optional. If False this function
|
||||||
will raise if the symbol is not found
|
will raise if the symbol is not found
|
||||||
|
@ -327,19 +345,64 @@ class Section(object):
|
||||||
print('Warning: %s' % err, file=sys.stderr)
|
print('Warning: %s' % err, file=sys.stderr)
|
||||||
return None
|
return None
|
||||||
raise ValueError(err)
|
raise ValueError(err)
|
||||||
if prop_name == 'pos':
|
if prop_name == 'offset':
|
||||||
return entry.pos
|
return entry.offset
|
||||||
|
elif prop_name == 'image_pos':
|
||||||
|
return entry.image_pos
|
||||||
else:
|
else:
|
||||||
raise ValueError("%s: No such property '%s'" % (msg, prop_name))
|
raise ValueError("%s: No such property '%s'" % (msg, prop_name))
|
||||||
|
|
||||||
def GetEntries(self):
|
def GetEntries(self):
|
||||||
|
"""Get the number of entries in a section
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Number of entries in a section
|
||||||
|
"""
|
||||||
return self._entries
|
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):
|
def WriteMap(self, fd, indent):
|
||||||
"""Write a map of the section to a .map file
|
"""Write a map of the section to a .map file
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
fd: File to write the map to
|
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():
|
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
|
args is a list of string arguments
|
||||||
"""
|
"""
|
||||||
parser = OptionParser()
|
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',
|
parser.add_option('-b', '--board', type='string',
|
||||||
help='Board name to build')
|
help='Board name to build')
|
||||||
parser.add_option('-B', '--build-dir', type='string', default='b',
|
parser.add_option('-B', '--build-dir', type='string', default='b',
|
||||||
|
@ -26,6 +28,8 @@ def ParseArgs(argv):
|
||||||
help='Configuration file (.dtb) to use')
|
help='Configuration file (.dtb) to use')
|
||||||
parser.add_option('-D', '--debug', action='store_true',
|
parser.add_option('-D', '--debug', action='store_true',
|
||||||
help='Enabling debugging (provides a full traceback on error)')
|
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',
|
parser.add_option('-I', '--indir', action='append',
|
||||||
help='Add a path to a directory to use for input files')
|
help='Add a path to a directory to use for input files')
|
||||||
parser.add_option('-H', '--full-help', action='store_true',
|
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',
|
parser.add_option('-T', '--test-coverage', action='store_true',
|
||||||
default=False, help='run tests and check for 100% coverage')
|
default=False, help='run tests and check for 100% coverage')
|
||||||
parser.add_option('-u', '--update-fdt', action='store_true',
|
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,
|
parser.add_option('-v', '--verbosity', default=1,
|
||||||
type='int', help='Control verbosity: 0=silent, 1=progress, 3=full, '
|
type='int', help='Control verbosity: 0=silent, 1=progress, 3=full, '
|
||||||
'4=debug')
|
'4=debug')
|
||||||
|
|
|
@ -7,13 +7,12 @@
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import tools
|
import tools
|
||||||
|
|
||||||
import command
|
import command
|
||||||
import elf
|
import elf
|
||||||
import fdt
|
|
||||||
import fdt_util
|
|
||||||
from image import Image
|
from image import Image
|
||||||
import tout
|
import tout
|
||||||
|
|
||||||
|
@ -25,6 +24,9 @@ images = OrderedDict()
|
||||||
# 'u-boot-spl.dtb')
|
# 'u-boot-spl.dtb')
|
||||||
fdt_files = {}
|
fdt_files = {}
|
||||||
|
|
||||||
|
# Arguments passed to binman to provide arguments to entries
|
||||||
|
entry_args = {}
|
||||||
|
|
||||||
|
|
||||||
def _ReadImageDesc(binman_node):
|
def _ReadImageDesc(binman_node):
|
||||||
"""Read the image descriptions from the /binman node
|
"""Read the image descriptions from the /binman node
|
||||||
|
@ -76,6 +78,24 @@ def GetFdt(fname):
|
||||||
def GetFdtPath(fname):
|
def GetFdtPath(fname):
|
||||||
return fdt_files[fname]._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):
|
def Binman(options, args):
|
||||||
"""The main control code for binman
|
"""The main control code for binman
|
||||||
|
|
||||||
|
@ -111,11 +131,17 @@ def Binman(options, args):
|
||||||
options.indir.append(board_pathname)
|
options.indir.append(board_pathname)
|
||||||
|
|
||||||
try:
|
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)
|
tout.Init(options.verbosity)
|
||||||
elf.debug = options.debug
|
elf.debug = options.debug
|
||||||
try:
|
try:
|
||||||
tools.SetInputDirs(options.indir)
|
tools.SetInputDirs(options.indir)
|
||||||
tools.PrepareOutputDir(options.outdir, options.preserve)
|
tools.PrepareOutputDir(options.outdir, options.preserve)
|
||||||
|
SetEntryArgs(options.entry_arg)
|
||||||
|
|
||||||
# Get the device tree ready by compiling it and copying the compiled
|
# 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
|
# 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
|
# size of the device tree is correct. Later, in
|
||||||
# SetCalculatedProperties() we will insert the correct values
|
# SetCalculatedProperties() we will insert the correct values
|
||||||
# without changing the device-tree size, thus ensuring that our
|
# 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():
|
for image in images.values():
|
||||||
if options.update_fdt:
|
if options.update_fdt:
|
||||||
image.AddMissingProperties()
|
image.AddMissingProperties()
|
||||||
|
@ -157,10 +183,11 @@ def Binman(options, args):
|
||||||
# image will be reported after earlier images are already
|
# image will be reported after earlier images are already
|
||||||
# completed and written, but that does not seem important.
|
# completed and written, but that does not seem important.
|
||||||
image.GetEntryContents()
|
image.GetEntryContents()
|
||||||
image.GetEntryPositions()
|
image.GetEntryOffsets()
|
||||||
image.PackEntries()
|
image.PackEntries()
|
||||||
image.CheckSize()
|
image.CheckSize()
|
||||||
image.CheckEntries()
|
image.CheckEntries()
|
||||||
|
image.SetImagePos()
|
||||||
if options.update_fdt:
|
if options.update_fdt:
|
||||||
image.SetCalculatedProperties()
|
image.SetCalculatedProperties()
|
||||||
image.ProcessEntryContents()
|
image.ProcessEntryContents()
|
||||||
|
|
|
@ -57,7 +57,9 @@ def GetSymbols(fname, patterns):
|
||||||
name = parts[2]
|
name = parts[2]
|
||||||
syms[name] = Symbol(section, int(value, 16), int(size,16),
|
syms[name] = Symbol(section, int(value, 16), int(size,16),
|
||||||
flags[1] == 'w')
|
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):
|
def GetSymbolAddress(fname, sym_name):
|
||||||
"""Get a value of a symbol from an ELF file
|
"""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
|
"""Replace all symbols in an entry with their correct values
|
||||||
|
|
||||||
The entry contents is updated so that values for referenced symbols will be
|
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
|
visible at run time. This is done by finding out the symbols offsets in the
|
||||||
the entry (using the ELF file) and replacing them with values from binman's
|
entry (using the ELF file) and replacing them with values from binman's data
|
||||||
data structures.
|
structures.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
elf_fname: Filename of ELF image containing the symbol information for
|
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:
|
class FakeEntry:
|
||||||
|
"""A fake Entry object, usedfor testing
|
||||||
|
|
||||||
|
This supports an entry with a given size.
|
||||||
|
"""
|
||||||
def __init__(self, contents_size):
|
def __init__(self, contents_size):
|
||||||
self.contents_size = contents_size
|
self.contents_size = contents_size
|
||||||
self.data = 'a' * contents_size
|
self.data = 'a' * contents_size
|
||||||
|
@ -22,7 +26,14 @@ class FakeEntry:
|
||||||
def GetPath(self):
|
def GetPath(self):
|
||||||
return 'entry_path'
|
return 'entry_path'
|
||||||
|
|
||||||
|
|
||||||
class FakeSection:
|
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):
|
def __init__(self, sym_value=1):
|
||||||
self.sym_value = sym_value
|
self.sym_value = sym_value
|
||||||
|
|
||||||
|
@ -30,15 +41,19 @@ class FakeSection:
|
||||||
return 'section_path'
|
return 'section_path'
|
||||||
|
|
||||||
def LookupSymbol(self, name, weak, msg):
|
def LookupSymbol(self, name, weak, msg):
|
||||||
|
"""Fake implementation which returns the same value for all symbols"""
|
||||||
return self.sym_value
|
return self.sym_value
|
||||||
|
|
||||||
|
|
||||||
class TestElf(unittest.TestCase):
|
class TestElf(unittest.TestCase):
|
||||||
def testAllSymbols(self):
|
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')
|
fname = os.path.join(binman_dir, 'test', 'u_boot_ucode_ptr')
|
||||||
syms = elf.GetSymbols(fname, [])
|
syms = elf.GetSymbols(fname, [])
|
||||||
self.assertIn('.ucode', syms)
|
self.assertIn('.ucode', syms)
|
||||||
|
|
||||||
def testRegexSymbols(self):
|
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')
|
fname = os.path.join(binman_dir, 'test', 'u_boot_ucode_ptr')
|
||||||
syms = elf.GetSymbols(fname, ['ucode'])
|
syms = elf.GetSymbols(fname, ['ucode'])
|
||||||
self.assertIn('.ucode', syms)
|
self.assertIn('.ucode', syms)
|
||||||
|
@ -48,6 +63,7 @@ class TestElf(unittest.TestCase):
|
||||||
self.assertIn('.ucode', syms)
|
self.assertIn('.ucode', syms)
|
||||||
|
|
||||||
def testMissingFile(self):
|
def testMissingFile(self):
|
||||||
|
"""Test that a missing file is detected"""
|
||||||
entry = FakeEntry(10)
|
entry = FakeEntry(10)
|
||||||
section = FakeSection()
|
section = FakeSection()
|
||||||
with self.assertRaises(ValueError) as e:
|
with self.assertRaises(ValueError) as e:
|
||||||
|
@ -56,6 +72,7 @@ class TestElf(unittest.TestCase):
|
||||||
str(e.exception))
|
str(e.exception))
|
||||||
|
|
||||||
def testOutsideFile(self):
|
def testOutsideFile(self):
|
||||||
|
"""Test a symbol which extends outside the entry area is detected"""
|
||||||
entry = FakeEntry(10)
|
entry = FakeEntry(10)
|
||||||
section = FakeSection()
|
section = FakeSection()
|
||||||
elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms')
|
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))
|
'is a', str(e.exception))
|
||||||
|
|
||||||
def testMissingImageStart(self):
|
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)
|
entry = FakeEntry(10)
|
||||||
section = FakeSection()
|
section = FakeSection()
|
||||||
elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms_bad')
|
elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms_bad')
|
||||||
|
@ -72,6 +94,11 @@ class TestElf(unittest.TestCase):
|
||||||
None)
|
None)
|
||||||
|
|
||||||
def testBadSymbolSize(self):
|
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)
|
entry = FakeEntry(10)
|
||||||
section = FakeSection()
|
section = FakeSection()
|
||||||
elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms_size')
|
elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms_size')
|
||||||
|
@ -81,6 +108,11 @@ class TestElf(unittest.TestCase):
|
||||||
str(e.exception))
|
str(e.exception))
|
||||||
|
|
||||||
def testNoValue(self):
|
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)
|
entry = FakeEntry(20)
|
||||||
section = FakeSection(sym_value=None)
|
section = FakeSection(sym_value=None)
|
||||||
elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms')
|
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)
|
self.assertEqual(chr(255) * 16 + 'a' * 4, entry.data)
|
||||||
|
|
||||||
def testDebug(self):
|
def testDebug(self):
|
||||||
|
"""Check that enabling debug in the elf module produced debug output"""
|
||||||
elf.debug = True
|
elf.debug = True
|
||||||
entry = FakeEntry(20)
|
entry = FakeEntry(20)
|
||||||
section = FakeSection()
|
section = FakeSection()
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
# importlib was introduced in Python 2.7 but there was a report of it not
|
# 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:
|
# working in 2.7.12, so we work around this:
|
||||||
# http://lists.denx.de/pipermail/u-boot/2016-October/269729.html
|
# http://lists.denx.de/pipermail/u-boot/2016-October/269729.html
|
||||||
|
@ -16,6 +18,7 @@ except:
|
||||||
have_importlib = False
|
have_importlib = False
|
||||||
|
|
||||||
import fdt_util
|
import fdt_util
|
||||||
|
import control
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import tools
|
import tools
|
||||||
|
@ -24,6 +27,12 @@ modules = {}
|
||||||
|
|
||||||
our_path = os.path.dirname(os.path.realpath(__file__))
|
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):
|
class Entry(object):
|
||||||
"""An Entry in the section
|
"""An Entry in the section
|
||||||
|
|
||||||
|
@ -36,14 +45,15 @@ class Entry(object):
|
||||||
Entry.
|
Entry.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
section: The section containing this entry
|
section: Section object containing this entry
|
||||||
node: The node that created 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
|
size: Entry size in bytes, None if not known
|
||||||
contents_size: Size of contents in bytes, 0 by default
|
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_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_before: Number of pad bytes before the contents, 0 if none
|
||||||
pad_after: Number of pad bytes after the contents, 0 if none
|
pad_after: Number of pad bytes after the contents, 0 if none
|
||||||
data: Contents of entry (string of bytes)
|
data: Contents of entry (string of bytes)
|
||||||
|
@ -53,34 +63,33 @@ class Entry(object):
|
||||||
self.etype = etype
|
self.etype = etype
|
||||||
self._node = node
|
self._node = node
|
||||||
self.name = node and (name_prefix + node.name) or 'none'
|
self.name = node and (name_prefix + node.name) or 'none'
|
||||||
self.pos = None
|
self.offset = None
|
||||||
self.size = None
|
self.size = None
|
||||||
self.data = ''
|
self.data = None
|
||||||
self.contents_size = 0
|
self.contents_size = 0
|
||||||
self.align = None
|
self.align = None
|
||||||
self.align_size = None
|
self.align_size = None
|
||||||
self.align_end = None
|
self.align_end = None
|
||||||
self.pad_before = 0
|
self.pad_before = 0
|
||||||
self.pad_after = 0
|
self.pad_after = 0
|
||||||
self.pos_unset = False
|
self.offset_unset = False
|
||||||
|
self.image_pos = None
|
||||||
if read_node:
|
if read_node:
|
||||||
self.ReadNode()
|
self.ReadNode()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def Create(section, node, etype=None):
|
def Lookup(section, node_path, etype):
|
||||||
"""Create a new entry for a node.
|
"""Look up the entry class for a node.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
section: Image object containing this node
|
section: Section object containing this node
|
||||||
node: Node object containing information about the entry to create
|
node_node: Path name of Node object containing information about
|
||||||
etype: Entry type to use, or None to work it out (used for tests)
|
the entry to create (used for errors)
|
||||||
|
etype: Entry type to use
|
||||||
|
|
||||||
Returns:
|
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
|
# Convert something like 'u-boot@0' to 'u_boot' since we are only
|
||||||
# interested in the type.
|
# interested in the type.
|
||||||
module_name = etype.replace('-', '_')
|
module_name = etype.replace('-', '_')
|
||||||
|
@ -99,15 +108,34 @@ class Entry(object):
|
||||||
module = importlib.import_module(module_name)
|
module = importlib.import_module(module_name)
|
||||||
else:
|
else:
|
||||||
module = __import__(module_name)
|
module = __import__(module_name)
|
||||||
except ImportError:
|
except ImportError as e:
|
||||||
raise ValueError("Unknown entry type '%s' in node '%s'" %
|
raise ValueError("Unknown entry type '%s' in node '%s' (expected etype/%s.py, error '%s'" %
|
||||||
(etype, node.path))
|
(etype, node_path, module_name, e))
|
||||||
finally:
|
finally:
|
||||||
sys.path = old_path
|
sys.path = old_path
|
||||||
modules[module_name] = module
|
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.
|
# Call its constructor to get the object we want.
|
||||||
obj = getattr(module, 'Entry_%s' % module_name)
|
|
||||||
return obj(section, etype, node)
|
return obj(section, etype, node)
|
||||||
|
|
||||||
def ReadNode(self):
|
def ReadNode(self):
|
||||||
|
@ -115,7 +143,9 @@ class Entry(object):
|
||||||
|
|
||||||
This reads all the fields we recognise from the node, ready for use.
|
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.size = fdt_util.GetInt(self._node, 'size')
|
||||||
self.align = fdt_util.GetInt(self._node, 'align')
|
self.align = fdt_util.GetInt(self._node, 'align')
|
||||||
if tools.NotPowerOfTwo(self.align):
|
if tools.NotPowerOfTwo(self.align):
|
||||||
|
@ -128,18 +158,19 @@ class Entry(object):
|
||||||
raise ValueError("Node '%s': Alignment size %s must be a power "
|
raise ValueError("Node '%s': Alignment size %s must be a power "
|
||||||
"of two" % (self._node.path, self.align_size))
|
"of two" % (self._node.path, self.align_size))
|
||||||
self.align_end = fdt_util.GetInt(self._node, 'align-end')
|
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):
|
def AddMissingProperties(self):
|
||||||
"""Add new properties to the device tree as needed for this entry"""
|
"""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:
|
if not prop in self._node.props:
|
||||||
self._node.AddZeroProp(prop)
|
self._node.AddZeroProp(prop)
|
||||||
|
|
||||||
def SetCalculatedProperties(self):
|
def SetCalculatedProperties(self):
|
||||||
"""Set the value of device-tree properties calculated by binman"""
|
"""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('size', self.size)
|
||||||
|
self._node.SetInt('image-pos', self.image_pos)
|
||||||
|
|
||||||
def ProcessFdt(self, fdt):
|
def ProcessFdt(self, fdt):
|
||||||
return True
|
return True
|
||||||
|
@ -190,39 +221,39 @@ class Entry(object):
|
||||||
# No contents by default: subclasses can implement this
|
# No contents by default: subclasses can implement this
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def Pack(self, pos):
|
def Pack(self, offset):
|
||||||
"""Figure out how to pack the entry into the section
|
"""Figure out how to pack the entry into the section
|
||||||
|
|
||||||
Most of the time the entries are not fully specified. There may be
|
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
|
an alignment but no size. In that case we take the size from the
|
||||||
contents of the entry.
|
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.
|
entry will be know.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
Current section position pointer
|
Current section offset pointer
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
New section position pointer (after this entry)
|
New section offset pointer (after this entry)
|
||||||
"""
|
"""
|
||||||
if self.pos is None:
|
if self.offset is None:
|
||||||
if self.pos_unset:
|
if self.offset_unset:
|
||||||
self.Raise('No position set with pos-unset: should another '
|
self.Raise('No offset set with offset-unset: should another '
|
||||||
'entry provide this correct position?')
|
'entry provide this correct offset?')
|
||||||
self.pos = tools.Align(pos, self.align)
|
self.offset = tools.Align(offset, self.align)
|
||||||
needed = self.pad_before + self.contents_size + self.pad_after
|
needed = self.pad_before + self.contents_size + self.pad_after
|
||||||
needed = tools.Align(needed, self.align_size)
|
needed = tools.Align(needed, self.align_size)
|
||||||
size = self.size
|
size = self.size
|
||||||
if not size:
|
if not size:
|
||||||
size = needed
|
size = needed
|
||||||
new_pos = self.pos + size
|
new_offset = self.offset + size
|
||||||
aligned_pos = tools.Align(new_pos, self.align_end)
|
aligned_offset = tools.Align(new_offset, self.align_end)
|
||||||
if aligned_pos != new_pos:
|
if aligned_offset != new_offset:
|
||||||
size = aligned_pos - self.pos
|
size = aligned_offset - self.offset
|
||||||
new_pos = aligned_pos
|
new_offset = aligned_offset
|
||||||
|
|
||||||
if not self.size:
|
if not self.size:
|
||||||
self.size = size
|
self.size = size
|
||||||
|
@ -231,21 +262,48 @@ class Entry(object):
|
||||||
self.Raise("Entry contents size is %#x (%d) but entry size is "
|
self.Raise("Entry contents size is %#x (%d) but entry size is "
|
||||||
"%#x (%d)" % (needed, needed, self.size, self.size))
|
"%#x (%d)" % (needed, needed, self.size, self.size))
|
||||||
# Check that the alignment is correct. It could be wrong if the
|
# 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
|
# conflict with the provided alignment values
|
||||||
if self.size != tools.Align(self.size, self.align_size):
|
if self.size != tools.Align(self.size, self.align_size):
|
||||||
self.Raise("Size %#x (%d) does not match align-size %#x (%d)" %
|
self.Raise("Size %#x (%d) does not match align-size %#x (%d)" %
|
||||||
(self.size, self.size, self.align_size, self.align_size))
|
(self.size, self.size, self.align_size, self.align_size))
|
||||||
if self.pos != tools.Align(self.pos, self.align):
|
if self.offset != tools.Align(self.offset, self.align):
|
||||||
self.Raise("Position %#x (%d) does not match align %#x (%d)" %
|
self.Raise("Offset %#x (%d) does not match align %#x (%d)" %
|
||||||
(self.pos, self.pos, self.align, self.align))
|
(self.offset, self.offset, self.align, self.align))
|
||||||
|
|
||||||
return new_pos
|
return new_offset
|
||||||
|
|
||||||
def Raise(self, msg):
|
def Raise(self, msg):
|
||||||
"""Convenience function to raise an error referencing a node"""
|
"""Convenience function to raise an error referencing a node"""
|
||||||
raise ValueError("Node '%s': %s" % (self._node.path, msg))
|
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):
|
def GetPath(self):
|
||||||
"""Get the path of a node
|
"""Get the path of a node
|
||||||
|
|
||||||
|
@ -257,13 +315,21 @@ class Entry(object):
|
||||||
def GetData(self):
|
def GetData(self):
|
||||||
return self.data
|
return self.data
|
||||||
|
|
||||||
def GetPositions(self):
|
def GetOffsets(self):
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def SetPositionSize(self, pos, size):
|
def SetOffsetSize(self, pos, size):
|
||||||
self.pos = pos
|
self.offset = pos
|
||||||
self.size = size
|
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):
|
def ProcessContents(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -275,15 +341,20 @@ class Entry(object):
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def CheckPosition(self):
|
def CheckOffset(self):
|
||||||
"""Check that the entry positions are correct
|
"""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
|
than having to be fully inside their section). Sub-classes can implement
|
||||||
this function and raise if there is a problem.
|
this function and raise if there is a problem.
|
||||||
"""
|
"""
|
||||||
pass
|
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):
|
def WriteMap(self, fd, indent):
|
||||||
"""Write a map of the entry to a .map file
|
"""Write a map of the entry to a .map file
|
||||||
|
|
||||||
|
@ -291,5 +362,97 @@ class Entry(object):
|
||||||
fd: File to write the map to
|
fd: File to write the map to
|
||||||
indent: Curent indent level of map (0=none, 1=one level, etc.)
|
indent: Curent indent level of map (0=none, 1=one level, etc.)
|
||||||
"""
|
"""
|
||||||
print('%s%08x %08x %s' % (' ' * indent, self.pos, self.size,
|
self.WriteMapLine(fd, indent, self.name, self.offset, self.size,
|
||||||
self.name), file=fd)
|
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.
|
# 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 fdt_util
|
||||||
import tools
|
import tools
|
||||||
|
|
||||||
|
@ -13,8 +15,30 @@ import tools
|
||||||
class Entry__testing(Entry):
|
class Entry__testing(Entry):
|
||||||
"""A fake entry used for testing
|
"""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:
|
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):
|
def __init__(self, section, etype, node):
|
||||||
Entry.__init__(self, section, etype, node)
|
Entry.__init__(self, section, etype, node)
|
||||||
|
@ -24,9 +48,26 @@ class Entry__testing(Entry):
|
||||||
'return-unknown-contents')
|
'return-unknown-contents')
|
||||||
self.bad_update_contents = fdt_util.GetBool(self._node,
|
self.bad_update_contents = fdt_util.GetBool(self._node,
|
||||||
'bad-update-contents')
|
'bad-update-contents')
|
||||||
|
|
||||||
|
# Set to True when the entry is ready to process the FDT.
|
||||||
self.process_fdt_ready = False
|
self.process_fdt_ready = False
|
||||||
self.never_complete_process_fdt = fdt_util.GetBool(self._node,
|
self.never_complete_process_fdt = fdt_util.GetBool(self._node,
|
||||||
'never-complete-process-fdt')
|
'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):
|
def ObtainContents(self):
|
||||||
if self.return_unknown_contents:
|
if self.return_unknown_contents:
|
||||||
|
@ -35,7 +76,7 @@ class Entry__testing(Entry):
|
||||||
self.contents_size = len(self.data)
|
self.contents_size = len(self.data)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def GetPositions(self):
|
def GetOffsets(self):
|
||||||
if self.return_invalid_entry :
|
if self.return_invalid_entry :
|
||||||
return {'invalid-entry': [1, 2]}
|
return {'invalid-entry': [1, 2]}
|
||||||
return {}
|
return {}
|
||||||
|
|
|
@ -10,6 +10,18 @@ import fdt_util
|
||||||
import tools
|
import tools
|
||||||
|
|
||||||
class Entry_blob(Entry):
|
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):
|
def __init__(self, section, etype, node):
|
||||||
Entry.__init__(self, section, etype, node)
|
Entry.__init__(self, section, etype, node)
|
||||||
self._filename = fdt_util.GetString(self._node, "filename", self.etype)
|
self._filename = fdt_util.GetString(self._node, "filename", self.etype)
|
||||||
|
@ -17,10 +29,10 @@ class Entry_blob(Entry):
|
||||||
def ObtainContents(self):
|
def ObtainContents(self):
|
||||||
self._filename = self.GetDefaultFilename()
|
self._filename = self.GetDefaultFilename()
|
||||||
self._pathname = tools.GetInputFilename(self._filename)
|
self._pathname = tools.GetInputFilename(self._filename)
|
||||||
self.ReadContents()
|
self.ReadBlobContents()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def ReadContents(self):
|
def ReadBlobContents(self):
|
||||||
with open(self._pathname) as fd:
|
with open(self._pathname) as fd:
|
||||||
# We assume the data is small enough to fit into memory. If this
|
# We assume the data is small enough to fit into memory. If this
|
||||||
# is used for large filesystem image that might not be true.
|
# 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
|
from blob import Entry_blob
|
||||||
|
|
||||||
class Entry_intel_cmc(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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__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)
|
FD_SIGNATURE = struct.pack('<L', 0x0ff0a55a)
|
||||||
MAX_REGIONS = 5
|
MAX_REGIONS = 5
|
||||||
|
|
||||||
|
# Region numbers supported by the Intel firmware format
|
||||||
(REGION_DESCRIPTOR, REGION_BIOS, REGION_ME, REGION_GBE,
|
(REGION_DESCRIPTOR, REGION_BIOS, REGION_ME, REGION_GBE,
|
||||||
REGION_PDATA) = range(5)
|
REGION_PDATA) = range(5)
|
||||||
|
|
||||||
|
@ -27,21 +28,32 @@ class Region:
|
||||||
class Entry_intel_descriptor(Entry_blob):
|
class Entry_intel_descriptor(Entry_blob):
|
||||||
"""Intel flash descriptor block (4KB)
|
"""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
|
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
|
size of the ME (Management Engine) region, allowing us to place the ME
|
||||||
place.
|
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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__init__(self, section, etype, node)
|
Entry_blob.__init__(self, section, etype, node)
|
||||||
self._regions = []
|
self._regions = []
|
||||||
|
|
||||||
def GetPositions(self):
|
def GetOffsets(self):
|
||||||
pos = self.data.find(FD_SIGNATURE)
|
offset = self.data.find(FD_SIGNATURE)
|
||||||
if pos == -1:
|
if offset == -1:
|
||||||
self.Raise('Cannot find FD signature')
|
self.Raise('Cannot find FD signature')
|
||||||
flvalsig, flmap0, flmap1, flmap2 = struct.unpack('<LLLL',
|
flvalsig, flmap0, flmap1, flmap2 = struct.unpack('<LLLL',
|
||||||
self.data[pos:pos + 16])
|
self.data[offset:offset + 16])
|
||||||
frba = ((flmap0 >> 16) & 0xff) << 4
|
frba = ((flmap0 >> 16) & 0xff) << 4
|
||||||
for i in range(MAX_REGIONS):
|
for i in range(MAX_REGIONS):
|
||||||
self._regions.append(Region(self.data, frba, i))
|
self._regions.append(Region(self.data, frba, i))
|
||||||
|
|
|
@ -9,5 +9,19 @@ from entry import Entry
|
||||||
from blob import Entry_blob
|
from blob import Entry_blob
|
||||||
|
|
||||||
class Entry_intel_fsp(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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__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
|
from blob import Entry_blob
|
||||||
|
|
||||||
class Entry_intel_me(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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__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
|
from blob import Entry_blob
|
||||||
|
|
||||||
class Entry_intel_mrc(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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__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
|
from blob import Entry_blob
|
||||||
|
|
||||||
class Entry_intel_vbt(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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__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
|
from blob import Entry_blob
|
||||||
|
|
||||||
class Entry_intel_vga(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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__init__(self, section, etype, node)
|
Entry_blob.__init__(self, section, etype, node)
|
||||||
|
|
|
@ -13,8 +13,25 @@ import tools
|
||||||
import bsection
|
import bsection
|
||||||
|
|
||||||
class Entry_section(Entry):
|
class Entry_section(Entry):
|
||||||
def __init__(self, image, etype, node):
|
"""Entry that contains other entries
|
||||||
Entry.__init__(self, image, etype, node)
|
|
||||||
|
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)
|
self._section = bsection.Section(node.name, node)
|
||||||
|
|
||||||
def ProcessFdt(self, fdt):
|
def ProcessFdt(self, fdt):
|
||||||
|
@ -30,20 +47,25 @@ class Entry_section(Entry):
|
||||||
def GetData(self):
|
def GetData(self):
|
||||||
return self._section.GetData()
|
return self._section.GetData()
|
||||||
|
|
||||||
def GetPositions(self):
|
def GetOffsets(self):
|
||||||
"""Handle entries that want to set the position/size of other entries
|
"""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.
|
of entries to update, it updates them.
|
||||||
"""
|
"""
|
||||||
self._section.GetEntryPositions()
|
self._section.GetEntryOffsets()
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def Pack(self, pos):
|
def Pack(self, offset):
|
||||||
"""Pack all entries into the section"""
|
"""Pack all entries into the section"""
|
||||||
self._section.PackEntries()
|
self._section.PackEntries()
|
||||||
self.size = self._section.CheckSize()
|
self._section.SetOffset(offset)
|
||||||
return super(Entry_section, self).Pack(pos)
|
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):
|
def WriteSymbols(self, section):
|
||||||
"""Write symbol values into binary files for access at run time"""
|
"""Write symbol values into binary files for access at run time"""
|
||||||
|
@ -57,7 +79,7 @@ class Entry_section(Entry):
|
||||||
self._section.ProcessEntryContents()
|
self._section.ProcessEntryContents()
|
||||||
super(Entry_section, self).ProcessContents()
|
super(Entry_section, self).ProcessContents()
|
||||||
|
|
||||||
def CheckPosition(self):
|
def CheckOffset(self):
|
||||||
self._section.CheckEntries()
|
self._section.CheckEntries()
|
||||||
|
|
||||||
def WriteMap(self, fd, indent):
|
def WriteMap(self, fd, indent):
|
||||||
|
@ -66,5 +88,7 @@ class Entry_section(Entry):
|
||||||
Args:
|
Args:
|
||||||
fd: File to write the map to
|
fd: File to write the map to
|
||||||
"""
|
"""
|
||||||
super(Entry_section, self).WriteMap(fd, indent)
|
self._section.WriteMap(fd, indent)
|
||||||
self._section.WriteMap(fd, indent + 1)
|
|
||||||
|
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
|
from blob import Entry_blob
|
||||||
|
|
||||||
class Entry_u_boot(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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__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
|
from blob import Entry_blob
|
||||||
|
|
||||||
class Entry_u_boot_dtb(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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__init__(self, section, etype, node)
|
Entry_blob.__init__(self, section, etype, node)
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import control
|
import control
|
||||||
import fdt
|
|
||||||
from entry import Entry
|
from entry import Entry
|
||||||
from blob import Entry_blob
|
from blob import Entry_blob
|
||||||
import tools
|
import tools
|
||||||
|
@ -14,8 +13,16 @@ import tools
|
||||||
class Entry_u_boot_dtb_with_ucode(Entry_blob):
|
class Entry_u_boot_dtb_with_ucode(Entry_blob):
|
||||||
"""A U-Boot device tree file, with the microcode removed
|
"""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
|
Properties / Entry arguments:
|
||||||
process.
|
- 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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__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'
|
return 'u-boot.dtb'
|
||||||
|
|
||||||
def ProcessFdt(self, fdt):
|
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
|
# If the section does not need microcode, there is nothing to do
|
||||||
ucode_dest_entry = self.section.FindEntryType(
|
ucode_dest_entry = self.section.FindEntryType(
|
||||||
'u-boot-spl-with-ucode-ptr')
|
'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(
|
ucode_dest_entry = self.section.FindEntryType(
|
||||||
'u-boot-with-ucode-ptr')
|
'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
|
return True
|
||||||
|
|
||||||
# Remove the microcode
|
# 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.
|
# Call the base class just in case it does something important.
|
||||||
Entry_blob.ObtainContents(self)
|
Entry_blob.ObtainContents(self)
|
||||||
self._pathname = control.GetFdtPath(self._filename)
|
self._pathname = control.GetFdtPath(self._filename)
|
||||||
self.ReadContents()
|
self.ReadBlobContents()
|
||||||
if self.ucode:
|
if self.ucode:
|
||||||
for node in self.ucode.subnodes:
|
for node in self.ucode.subnodes:
|
||||||
data_prop = node.props.get('data')
|
data_prop = node.props.get('data')
|
||||||
|
|
|
@ -9,6 +9,17 @@ from entry import Entry
|
||||||
from blob import Entry_blob
|
from blob import Entry_blob
|
||||||
|
|
||||||
class Entry_u_boot_img(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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__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
|
from blob import Entry_blob
|
||||||
|
|
||||||
class Entry_u_boot_nodtb(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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__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
|
from blob import Entry_blob
|
||||||
|
|
||||||
class Entry_u_boot_spl(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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__init__(self, section, etype, node)
|
Entry_blob.__init__(self, section, etype, node)
|
||||||
self.elf_fname = 'spl/u-boot-spl'
|
self.elf_fname = 'spl/u-boot-spl'
|
||||||
|
|
|
@ -14,6 +14,22 @@ from blob import Entry_blob
|
||||||
import tools
|
import tools
|
||||||
|
|
||||||
class Entry_u_boot_spl_bss_pad(Entry_blob):
|
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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__init__(self, section, etype, node)
|
Entry_blob.__init__(self, section, etype, node)
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,22 @@
|
||||||
# Copyright (c) 2016 Google, Inc
|
# Copyright (c) 2016 Google, Inc
|
||||||
# Written by Simon Glass <sjg@chromium.org>
|
# 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 entry import Entry
|
||||||
from blob import Entry_blob
|
from blob import Entry_blob
|
||||||
|
|
||||||
class Entry_u_boot_spl_dtb(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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__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
|
from blob import Entry_blob
|
||||||
|
|
||||||
class Entry_u_boot_spl_nodtb(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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__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):
|
class Entry_u_boot_ucode(Entry_blob):
|
||||||
"""U-Boot microcode block
|
"""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
|
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
|
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
|
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 = self.section.FindEntryType('u-boot-with-ucode-ptr')
|
||||||
ucode_dest_entry_spl = self.section.FindEntryType(
|
ucode_dest_entry_spl = self.section.FindEntryType(
|
||||||
'u-boot-spl-with-ucode-ptr')
|
'u-boot-spl-with-ucode-ptr')
|
||||||
if ((not ucode_dest_entry or not ucode_dest_entry.target_pos) and
|
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_pos)):
|
(not ucode_dest_entry_spl or not ucode_dest_entry_spl.target_offset)):
|
||||||
self.data = ''
|
self.data = ''
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -86,6 +92,6 @@ class Entry_u_boot_ucode(Entry_blob):
|
||||||
fd.write(fdt_entry.ucode_data)
|
fd.write(fdt_entry.ucode_data)
|
||||||
|
|
||||||
self._pathname = fname
|
self._pathname = fname
|
||||||
self.ReadContents()
|
self.ReadBlobContents()
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -17,13 +17,18 @@ import tools
|
||||||
class Entry_u_boot_with_ucode_ptr(Entry_blob):
|
class Entry_u_boot_with_ucode_ptr(Entry_blob):
|
||||||
"""U-Boot with embedded microcode pointer
|
"""U-Boot with embedded microcode pointer
|
||||||
|
|
||||||
See Entry_u_boot_ucode for full details of the 3 entries involved in this
|
Properties / Entry arguments:
|
||||||
process.
|
- 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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__init__(self, section, etype, node)
|
Entry_blob.__init__(self, section, etype, node)
|
||||||
self.elf_fname = 'u-boot'
|
self.elf_fname = 'u-boot'
|
||||||
self.target_pos = None
|
self.target_offset = None
|
||||||
|
|
||||||
def GetDefaultFilename(self):
|
def GetDefaultFilename(self):
|
||||||
return 'u-boot-nodtb.bin'
|
return 'u-boot-nodtb.bin'
|
||||||
|
@ -33,52 +38,53 @@ class Entry_u_boot_with_ucode_ptr(Entry_blob):
|
||||||
fname = tools.GetInputFilename(self.elf_fname)
|
fname = tools.GetInputFilename(self.elf_fname)
|
||||||
sym = elf.GetSymbolAddress(fname, '_dt_ucode_base_size')
|
sym = elf.GetSymbolAddress(fname, '_dt_ucode_base_size')
|
||||||
if sym:
|
if sym:
|
||||||
self.target_pos = sym
|
self.target_offset = sym
|
||||||
elif not fdt_util.GetBool(self._node, 'optional-ucode'):
|
elif not fdt_util.GetBool(self._node, 'optional-ucode'):
|
||||||
self.Raise('Cannot locate _dt_ucode_base_size symbol in u-boot')
|
self.Raise('Cannot locate _dt_ucode_base_size symbol in u-boot')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def ProcessContents(self):
|
def ProcessContents(self):
|
||||||
# If the image does not need microcode, there is nothing to do
|
# If the image does not need microcode, there is nothing to do
|
||||||
if not self.target_pos:
|
if not self.target_offset:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Get the position of the microcode
|
# Get the offset of the microcode
|
||||||
ucode_entry = self.section.FindEntryType('u-boot-ucode')
|
ucode_entry = self.section.FindEntryType('u-boot-ucode')
|
||||||
if not ucode_entry:
|
if not ucode_entry:
|
||||||
self.Raise('Cannot find microcode region u-boot-ucode')
|
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
|
# 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.
|
# in the section.
|
||||||
#
|
#
|
||||||
# The section must be set up so that U-Boot is placed at the
|
# The section must be set up so that U-Boot is placed at the
|
||||||
# flash address to which it is linked. For example, if
|
# flash address to which it is linked. For example, if
|
||||||
# CONFIG_SYS_TEXT_BASE is 0xfff00000, and the ROM is 8MB, then
|
# 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
|
# the U-Boot region must start at offset 7MB in the section. In this
|
||||||
# case the ROM starts at 0xff800000, so the position of the first
|
# case the ROM starts at 0xff800000, so the offset of the first
|
||||||
# entry in the section corresponds to that.
|
# entry in the section corresponds to that.
|
||||||
if (self.target_pos < self.pos or
|
if (self.target_offset < self.offset or
|
||||||
self.target_pos >= self.pos + self.size):
|
self.target_offset >= self.offset + self.size):
|
||||||
self.Raise('Microcode pointer _dt_ucode_base_size at %08x is '
|
self.Raise('Microcode pointer _dt_ucode_base_size at %08x is '
|
||||||
'outside the section ranging from %08x to %08x' %
|
'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.
|
# 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
|
# 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
|
# in the former. If we extracted the microcode from the device tree
|
||||||
# and collated it in one place, it will be in the latter.
|
# and collated it in one place, it will be in the latter.
|
||||||
if ucode_entry.size:
|
if ucode_entry.size:
|
||||||
pos, size = ucode_entry.pos, ucode_entry.size
|
offset, size = ucode_entry.offset, ucode_entry.size
|
||||||
else:
|
else:
|
||||||
dtb_entry = self.section.FindEntryType('u-boot-dtb-with-ucode')
|
dtb_entry = self.section.FindEntryType('u-boot-dtb-with-ucode')
|
||||||
if not dtb_entry or not dtb_entry.ready:
|
if not dtb_entry or not dtb_entry.ready:
|
||||||
self.Raise('Cannot find microcode region u-boot-dtb-with-ucode')
|
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
|
size = dtb_entry.ucode_size
|
||||||
|
|
||||||
# Write the microcode position and size into the entry
|
# Write the microcode offset and size into the entry
|
||||||
pos_and_size = struct.pack('<2L', pos, size)
|
offset_and_size = struct.pack('<2L', offset, size)
|
||||||
self.target_pos -= self.pos
|
self.target_offset -= self.offset
|
||||||
self.ProcessContentsUpdate(self.data[:self.target_pos] + pos_and_size +
|
self.ProcessContentsUpdate(self.data[:self.target_offset] +
|
||||||
self.data[self.target_pos + 8:])
|
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
|
from blob import Entry_blob
|
||||||
|
|
||||||
class Entry_x86_start16(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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__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
|
from blob import Entry_blob
|
||||||
|
|
||||||
class Entry_x86_start16_spl(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):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__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 elf
|
||||||
import fdt
|
import fdt
|
||||||
import fdt_util
|
import fdt_util
|
||||||
|
import fmap_util
|
||||||
|
import test_util
|
||||||
import tools
|
import tools
|
||||||
import tout
|
import tout
|
||||||
|
|
||||||
|
@ -28,11 +30,13 @@ import tout
|
||||||
U_BOOT_DATA = '1234'
|
U_BOOT_DATA = '1234'
|
||||||
U_BOOT_IMG_DATA = 'img'
|
U_BOOT_IMG_DATA = 'img'
|
||||||
U_BOOT_SPL_DATA = '56780123456789abcde'
|
U_BOOT_SPL_DATA = '56780123456789abcde'
|
||||||
|
U_BOOT_TPL_DATA = 'tpl'
|
||||||
BLOB_DATA = '89'
|
BLOB_DATA = '89'
|
||||||
ME_DATA = '0abcd'
|
ME_DATA = '0abcd'
|
||||||
VGA_DATA = 'vga'
|
VGA_DATA = 'vga'
|
||||||
U_BOOT_DTB_DATA = 'udtb'
|
U_BOOT_DTB_DATA = 'udtb'
|
||||||
U_BOOT_SPL_DTB_DATA = 'spldtb'
|
U_BOOT_SPL_DTB_DATA = 'spldtb'
|
||||||
|
U_BOOT_TPL_DTB_DATA = 'tpldtb'
|
||||||
X86_START16_DATA = 'start16'
|
X86_START16_DATA = 'start16'
|
||||||
X86_START16_SPL_DATA = 'start16spl'
|
X86_START16_SPL_DATA = 'start16spl'
|
||||||
U_BOOT_NODTB_DATA = 'nodtb with microcode pointer somewhere in here'
|
U_BOOT_NODTB_DATA = 'nodtb with microcode pointer somewhere in here'
|
||||||
|
@ -41,6 +45,14 @@ FSP_DATA = 'fsp'
|
||||||
CMC_DATA = 'cmc'
|
CMC_DATA = 'cmc'
|
||||||
VBT_DATA = 'vbt'
|
VBT_DATA = 'vbt'
|
||||||
MRC_DATA = 'mrc'
|
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):
|
class TestFunctional(unittest.TestCase):
|
||||||
"""Functional tests for binman
|
"""Functional tests for binman
|
||||||
|
@ -72,11 +84,11 @@ class TestFunctional(unittest.TestCase):
|
||||||
TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
|
TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
|
||||||
TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
|
TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
|
||||||
TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_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('blobfile', BLOB_DATA)
|
||||||
TestFunctional._MakeInputFile('me.bin', ME_DATA)
|
TestFunctional._MakeInputFile('me.bin', ME_DATA)
|
||||||
TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
|
TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
|
||||||
TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
|
self._ResetDtbs()
|
||||||
TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
|
|
||||||
TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
|
TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
|
||||||
TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
|
TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
|
||||||
X86_START16_SPL_DATA)
|
X86_START16_SPL_DATA)
|
||||||
|
@ -87,6 +99,9 @@ class TestFunctional(unittest.TestCase):
|
||||||
TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
|
TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
|
||||||
TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
|
TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
|
||||||
TestFunctional._MakeInputFile('mrc.bin', MRC_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
|
self._output_setup = False
|
||||||
|
|
||||||
# ELF file with a '_dt_ucode_base_size' symbol
|
# ELF file with a '_dt_ucode_base_size' symbol
|
||||||
|
@ -113,6 +128,12 @@ class TestFunctional(unittest.TestCase):
|
||||||
"""Remove the temporary output directory"""
|
"""Remove the temporary output directory"""
|
||||||
tools._FinaliseForTest()
|
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):
|
def _RunBinman(self, *args, **kwargs):
|
||||||
"""Run binman using the command line
|
"""Run binman using the command line
|
||||||
|
|
||||||
|
@ -146,14 +167,15 @@ class TestFunctional(unittest.TestCase):
|
||||||
# options.verbosity = tout.DEBUG
|
# options.verbosity = tout.DEBUG
|
||||||
return control.Binman(options, args)
|
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
|
"""Run binman with a given test file
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
fname: Device-tree source filename to use (e.g. 05_simple.dts)
|
fname: Device-tree source filename to use (e.g. 05_simple.dts)
|
||||||
debug: True to enable debugging output
|
debug: True to enable debugging output
|
||||||
map: True to output map files for the images
|
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
|
tree before packing it into the image
|
||||||
"""
|
"""
|
||||||
args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
|
args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
|
||||||
|
@ -163,6 +185,9 @@ class TestFunctional(unittest.TestCase):
|
||||||
args.append('-m')
|
args.append('-m')
|
||||||
if update_dtb:
|
if update_dtb:
|
||||||
args.append('-up')
|
args.append('-up')
|
||||||
|
if entry_args:
|
||||||
|
for arg, value in entry_args.iteritems():
|
||||||
|
args.append('-a%s=%s' % (arg, value))
|
||||||
return self._DoBinman(*args)
|
return self._DoBinman(*args)
|
||||||
|
|
||||||
def _SetupDtb(self, fname, outfile='u-boot.dtb'):
|
def _SetupDtb(self, fname, outfile='u-boot.dtb'):
|
||||||
|
@ -188,7 +213,7 @@ class TestFunctional(unittest.TestCase):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
|
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
|
"""Run binman and return the resulting image
|
||||||
|
|
||||||
This runs binman with a given test file and then reads the resulting
|
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.
|
test contents (the U_BOOT_DTB_DATA string) can be used.
|
||||||
But in some test we need the real contents.
|
But in some test we need the real contents.
|
||||||
map: True to output map files for the images
|
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
|
tree before packing it into the image
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
@ -212,6 +237,7 @@ class TestFunctional(unittest.TestCase):
|
||||||
Resulting image contents
|
Resulting image contents
|
||||||
Device tree contents
|
Device tree contents
|
||||||
Map data showing contents of image (or None if none)
|
Map data showing contents of image (or None if none)
|
||||||
|
Output device tree binary filename ('u-boot.dtb' path)
|
||||||
"""
|
"""
|
||||||
dtb_data = None
|
dtb_data = None
|
||||||
# Use the compiled test file as the u-boot-dtb input
|
# Use the compiled test file as the u-boot-dtb input
|
||||||
|
@ -219,7 +245,8 @@ class TestFunctional(unittest.TestCase):
|
||||||
dtb_data = self._SetupDtb(fname)
|
dtb_data = self._SetupDtb(fname)
|
||||||
|
|
||||||
try:
|
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)
|
self.assertEqual(0, retcode)
|
||||||
out_dtb_fname = control.GetFdtPath('u-boot.dtb')
|
out_dtb_fname = control.GetFdtPath('u-boot.dtb')
|
||||||
|
|
||||||
|
@ -238,7 +265,7 @@ class TestFunctional(unittest.TestCase):
|
||||||
finally:
|
finally:
|
||||||
# Put the test file back
|
# Put the test file back
|
||||||
if use_real_dtb:
|
if use_real_dtb:
|
||||||
TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
|
self._ResetDtbs()
|
||||||
|
|
||||||
def _DoReadFile(self, fname, use_real_dtb=False):
|
def _DoReadFile(self, fname, use_real_dtb=False):
|
||||||
"""Helper function which discards the device-tree binary
|
"""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
|
the u-boot-dtb entry. Normally this is not needed and the
|
||||||
test contents (the U_BOOT_DTB_DATA string) can be used.
|
test contents (the U_BOOT_DTB_DATA string) can be used.
|
||||||
But in some test we need the real contents.
|
But in some test we need the real contents.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Resulting image contents
|
||||||
"""
|
"""
|
||||||
return self._DoReadFileDtb(fname, use_real_dtb)[0]
|
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
|
"""Create a new test input file, creating directories as needed
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
fname: Filenaem to create
|
fname: Filename to create
|
||||||
contents: File contents to write in to the file
|
contents: File contents to write in to the file
|
||||||
Returns:
|
Returns:
|
||||||
Full pathname of file created
|
Full pathname of file created
|
||||||
|
@ -270,6 +300,21 @@ class TestFunctional(unittest.TestCase):
|
||||||
fd.write(contents)
|
fd.write(contents)
|
||||||
return pathname
|
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
|
@classmethod
|
||||||
def TestFile(self, fname):
|
def TestFile(self, fname):
|
||||||
return os.path.join(self._binman_dir, 'test', fname)
|
return os.path.join(self._binman_dir, 'test', fname)
|
||||||
|
@ -292,10 +337,10 @@ class TestFunctional(unittest.TestCase):
|
||||||
Args:
|
Args:
|
||||||
entries: List of entries to check
|
entries: List of entries to check
|
||||||
"""
|
"""
|
||||||
pos = 0
|
offset = 0
|
||||||
for entry in entries.values():
|
for entry in entries.values():
|
||||||
self.assertEqual(pos, entry.pos)
|
self.assertEqual(offset, entry.offset)
|
||||||
pos += entry.size
|
offset += entry.size
|
||||||
|
|
||||||
def GetFdtLen(self, dtb):
|
def GetFdtLen(self, dtb):
|
||||||
"""Get the totalsize field from a device-tree binary
|
"""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]
|
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):
|
def AddNode(node, path):
|
||||||
if node.name != '/':
|
if node.name != '/':
|
||||||
path += '/' + node.name
|
path += '/' + node.name
|
||||||
#print 'path', path
|
|
||||||
for subnode in node.subnodes:
|
for subnode in node.subnodes:
|
||||||
for prop in subnode.props.values():
|
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
|
prop_path = path + '/' + subnode.name + ':' + prop.name
|
||||||
tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
|
tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
|
||||||
prop.value)
|
prop.value)
|
||||||
#print ' ', prop.name
|
|
||||||
AddNode(subnode, path)
|
AddNode(subnode, path)
|
||||||
|
|
||||||
tree = {}
|
tree = {}
|
||||||
dtb = fdt.Fdt(dtb_data)
|
|
||||||
dtb.Scan()
|
|
||||||
AddNode(dtb.GetRoot(), '')
|
AddNode(dtb.GetRoot(), '')
|
||||||
return tree
|
return tree
|
||||||
|
|
||||||
|
@ -409,7 +450,6 @@ class TestFunctional(unittest.TestCase):
|
||||||
with self.assertRaises(Exception) as e:
|
with self.assertRaises(Exception) as e:
|
||||||
result = self._RunBinman('-d',
|
result = self._RunBinman('-d',
|
||||||
self.TestFile('04_invalid_entry.dts'))
|
self.TestFile('04_invalid_entry.dts'))
|
||||||
#print e.exception
|
|
||||||
self.assertIn("Unknown entry type 'not-a-valid-type' in node "
|
self.assertIn("Unknown entry type 'not-a-valid-type' in node "
|
||||||
"'/binman/not-a-valid-type'", str(e.exception))
|
"'/binman/not-a-valid-type'", str(e.exception))
|
||||||
|
|
||||||
|
@ -467,32 +507,32 @@ class TestFunctional(unittest.TestCase):
|
||||||
# First u-boot
|
# First u-boot
|
||||||
self.assertIn('u-boot', entries)
|
self.assertIn('u-boot', entries)
|
||||||
entry = entries['u-boot']
|
entry = entries['u-boot']
|
||||||
self.assertEqual(0, entry.pos)
|
self.assertEqual(0, entry.offset)
|
||||||
self.assertEqual(len(U_BOOT_DATA), entry.size)
|
self.assertEqual(len(U_BOOT_DATA), entry.size)
|
||||||
|
|
||||||
# Second u-boot, aligned to 16-byte boundary
|
# Second u-boot, aligned to 16-byte boundary
|
||||||
self.assertIn('u-boot-align', entries)
|
self.assertIn('u-boot-align', entries)
|
||||||
entry = entries['u-boot-align']
|
entry = entries['u-boot-align']
|
||||||
self.assertEqual(16, entry.pos)
|
self.assertEqual(16, entry.offset)
|
||||||
self.assertEqual(len(U_BOOT_DATA), entry.size)
|
self.assertEqual(len(U_BOOT_DATA), entry.size)
|
||||||
|
|
||||||
# Third u-boot, size 23 bytes
|
# Third u-boot, size 23 bytes
|
||||||
self.assertIn('u-boot-size', entries)
|
self.assertIn('u-boot-size', entries)
|
||||||
entry = entries['u-boot-size']
|
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(len(U_BOOT_DATA), entry.contents_size)
|
||||||
self.assertEqual(23, entry.size)
|
self.assertEqual(23, entry.size)
|
||||||
|
|
||||||
# Fourth u-boot, placed immediate after the above
|
# Fourth u-boot, placed immediate after the above
|
||||||
self.assertIn('u-boot-next', entries)
|
self.assertIn('u-boot-next', entries)
|
||||||
entry = entries['u-boot-next']
|
entry = entries['u-boot-next']
|
||||||
self.assertEqual(43, entry.pos)
|
self.assertEqual(43, entry.offset)
|
||||||
self.assertEqual(len(U_BOOT_DATA), entry.size)
|
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)
|
self.assertIn('u-boot-fixed', entries)
|
||||||
entry = entries['u-boot-fixed']
|
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(len(U_BOOT_DATA), entry.size)
|
||||||
|
|
||||||
self.assertEqual(65, image._size)
|
self.assertEqual(65, image._size)
|
||||||
|
@ -510,32 +550,32 @@ class TestFunctional(unittest.TestCase):
|
||||||
# First u-boot with padding before and after
|
# First u-boot with padding before and after
|
||||||
self.assertIn('u-boot', entries)
|
self.assertIn('u-boot', entries)
|
||||||
entry = entries['u-boot']
|
entry = entries['u-boot']
|
||||||
self.assertEqual(0, entry.pos)
|
self.assertEqual(0, entry.offset)
|
||||||
self.assertEqual(3, entry.pad_before)
|
self.assertEqual(3, entry.pad_before)
|
||||||
self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
|
self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
|
||||||
|
|
||||||
# Second u-boot has an aligned size, but it has no effect
|
# Second u-boot has an aligned size, but it has no effect
|
||||||
self.assertIn('u-boot-align-size-nop', entries)
|
self.assertIn('u-boot-align-size-nop', entries)
|
||||||
entry = entries['u-boot-align-size-nop']
|
entry = entries['u-boot-align-size-nop']
|
||||||
self.assertEqual(12, entry.pos)
|
self.assertEqual(12, entry.offset)
|
||||||
self.assertEqual(4, entry.size)
|
self.assertEqual(4, entry.size)
|
||||||
|
|
||||||
# Third u-boot has an aligned size too
|
# Third u-boot has an aligned size too
|
||||||
self.assertIn('u-boot-align-size', entries)
|
self.assertIn('u-boot-align-size', entries)
|
||||||
entry = entries['u-boot-align-size']
|
entry = entries['u-boot-align-size']
|
||||||
self.assertEqual(16, entry.pos)
|
self.assertEqual(16, entry.offset)
|
||||||
self.assertEqual(32, entry.size)
|
self.assertEqual(32, entry.size)
|
||||||
|
|
||||||
# Fourth u-boot has an aligned end
|
# Fourth u-boot has an aligned end
|
||||||
self.assertIn('u-boot-align-end', entries)
|
self.assertIn('u-boot-align-end', entries)
|
||||||
entry = entries['u-boot-align-end']
|
entry = entries['u-boot-align-end']
|
||||||
self.assertEqual(48, entry.pos)
|
self.assertEqual(48, entry.offset)
|
||||||
self.assertEqual(16, entry.size)
|
self.assertEqual(16, entry.size)
|
||||||
|
|
||||||
# Fifth u-boot immediately afterwards
|
# Fifth u-boot immediately afterwards
|
||||||
self.assertIn('u-boot-align-both', entries)
|
self.assertIn('u-boot-align-both', entries)
|
||||||
entry = entries['u-boot-align-both']
|
entry = entries['u-boot-align-both']
|
||||||
self.assertEqual(64, entry.pos)
|
self.assertEqual(64, entry.offset)
|
||||||
self.assertEqual(64, entry.size)
|
self.assertEqual(64, entry.size)
|
||||||
|
|
||||||
self.CheckNoGaps(entries)
|
self.CheckNoGaps(entries)
|
||||||
|
@ -556,10 +596,10 @@ class TestFunctional(unittest.TestCase):
|
||||||
"power of two", str(e.exception))
|
"power of two", str(e.exception))
|
||||||
|
|
||||||
def testPackInvalidAlign(self):
|
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:
|
with self.assertRaises(ValueError) as e:
|
||||||
self._DoTestFile('12_pack_inv_align.dts')
|
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))
|
"align 0x4 (4)", str(e.exception))
|
||||||
|
|
||||||
def testPackInvalidSizeAlign(self):
|
def testPackInvalidSizeAlign(self):
|
||||||
|
@ -573,7 +613,7 @@ class TestFunctional(unittest.TestCase):
|
||||||
"""Test that overlapping regions are detected"""
|
"""Test that overlapping regions are detected"""
|
||||||
with self.assertRaises(ValueError) as e:
|
with self.assertRaises(ValueError) as e:
|
||||||
self._DoTestFile('14_pack_overlap.dts')
|
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)",
|
"with previous entry '/binman/u-boot' ending at 0x4 (4)",
|
||||||
str(e.exception))
|
str(e.exception))
|
||||||
|
|
||||||
|
@ -651,11 +691,11 @@ class TestFunctional(unittest.TestCase):
|
||||||
self.assertEqual(chr(0) * 1 + U_BOOT_SPL_DATA + chr(0) * 2 +
|
self.assertEqual(chr(0) * 1 + U_BOOT_SPL_DATA + chr(0) * 2 +
|
||||||
U_BOOT_DATA, data)
|
U_BOOT_DATA, data)
|
||||||
|
|
||||||
def testPackZeroPosition(self):
|
def testPackZeroOffset(self):
|
||||||
"""Test that an entry at position 0 is not given a new position"""
|
"""Test that an entry at offset 0 is not given a new offset"""
|
||||||
with self.assertRaises(ValueError) as e:
|
with self.assertRaises(ValueError) as e:
|
||||||
self._DoTestFile('25_pack_zero_size.dts')
|
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)",
|
"with previous entry '/binman/u-boot' ending at 0x4 (4)",
|
||||||
str(e.exception))
|
str(e.exception))
|
||||||
|
|
||||||
|
@ -672,10 +712,10 @@ class TestFunctional(unittest.TestCase):
|
||||||
"using end-at-4gb", str(e.exception))
|
"using end-at-4gb", str(e.exception))
|
||||||
|
|
||||||
def testPackX86RomOutside(self):
|
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:
|
with self.assertRaises(ValueError) as e:
|
||||||
self._DoTestFile('28_pack_4gb_outside.dts')
|
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)",
|
"the section starting at 0xffffffe0 (4294967264)",
|
||||||
str(e.exception))
|
str(e.exception))
|
||||||
|
|
||||||
|
@ -697,9 +737,9 @@ class TestFunctional(unittest.TestCase):
|
||||||
"""Test that the Intel requires a descriptor entry"""
|
"""Test that the Intel requires a descriptor entry"""
|
||||||
with self.assertRaises(ValueError) as e:
|
with self.assertRaises(ValueError) as e:
|
||||||
self._DoTestFile('30_x86-rom-me-no-desc.dts')
|
self._DoTestFile('30_x86-rom-me-no-desc.dts')
|
||||||
self.assertIn("Node '/binman/intel-me': No position set with "
|
self.assertIn("Node '/binman/intel-me': No offset set with "
|
||||||
"pos-unset: should another entry provide this correct "
|
"offset-unset: should another entry provide this correct "
|
||||||
"position?", str(e.exception))
|
"offset?", str(e.exception))
|
||||||
|
|
||||||
def testPackX86RomMe(self):
|
def testPackX86RomMe(self):
|
||||||
"""Test that an x86 ROM with an ME region can be created"""
|
"""Test that an x86 ROM with an ME region can be created"""
|
||||||
|
@ -728,7 +768,7 @@ class TestFunctional(unittest.TestCase):
|
||||||
Returns:
|
Returns:
|
||||||
Tuple:
|
Tuple:
|
||||||
Contents of first region (U-Boot or SPL)
|
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)
|
in the above (two 4-byte words)
|
||||||
"""
|
"""
|
||||||
data = self._DoReadFile(dts_fname, True)
|
data = self._DoReadFile(dts_fname, True)
|
||||||
|
@ -761,7 +801,7 @@ class TestFunctional(unittest.TestCase):
|
||||||
self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
|
self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
|
||||||
|
|
||||||
# Check that the microcode pointer was inserted. It should match the
|
# 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,
|
pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
|
||||||
len(ucode_data))
|
len(ucode_data))
|
||||||
u_boot = data[:len(nodtb_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)
|
ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
|
||||||
|
|
||||||
# Check that the microcode pointer was inserted. It should match the
|
# 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,
|
pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
|
||||||
len(ucode_data))
|
len(ucode_data))
|
||||||
first = data[:len(U_BOOT_NODTB_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"""
|
"""Test that microcode must be placed within the image"""
|
||||||
with self.assertRaises(ValueError) as e:
|
with self.assertRaises(ValueError) as e:
|
||||||
self._DoReadFile('41_unknown_pos_size.dts', True)
|
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))
|
"entry 'invalid-entry'", str(e.exception))
|
||||||
|
|
||||||
def testPackFsp(self):
|
def testPackFsp(self):
|
||||||
|
@ -984,7 +1024,7 @@ class TestFunctional(unittest.TestCase):
|
||||||
elf_fname = self.TestFile('u_boot_binman_syms')
|
elf_fname = self.TestFile('u_boot_binman_syms')
|
||||||
syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
|
syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
|
||||||
addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
|
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:
|
with open(self.TestFile('u_boot_binman_syms')) as fd:
|
||||||
TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
|
TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
|
||||||
|
@ -1003,27 +1043,32 @@ class TestFunctional(unittest.TestCase):
|
||||||
def testSections(self):
|
def testSections(self):
|
||||||
"""Basic test of sections"""
|
"""Basic test of sections"""
|
||||||
data = self._DoReadFile('55_sections.dts')
|
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)
|
self.assertEqual(expected, data)
|
||||||
|
|
||||||
def testMap(self):
|
def testMap(self):
|
||||||
"""Tests outputting a map of the images"""
|
"""Tests outputting a map of the images"""
|
||||||
_, _, map_data, _ = self._DoReadFileDtb('55_sections.dts', map=True)
|
_, _, map_data, _ = self._DoReadFileDtb('55_sections.dts', map=True)
|
||||||
self.assertEqual('''Position Size Name
|
self.assertEqual('''ImagePos Offset Size Name
|
||||||
00000000 00000010 section@0
|
00000000 00000000 00000028 main-section
|
||||||
00000000 00000004 u-boot
|
00000000 00000000 00000010 section@0
|
||||||
00000010 00000010 section@1
|
00000000 00000000 00000004 u-boot
|
||||||
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)
|
''', map_data)
|
||||||
|
|
||||||
def testNamePrefix(self):
|
def testNamePrefix(self):
|
||||||
"""Tests that name prefixes are used"""
|
"""Tests that name prefixes are used"""
|
||||||
_, _, map_data, _ = self._DoReadFileDtb('56_name_prefix.dts', map=True)
|
_, _, map_data, _ = self._DoReadFileDtb('56_name_prefix.dts', map=True)
|
||||||
self.assertEqual('''Position Size Name
|
self.assertEqual('''ImagePos Offset Size Name
|
||||||
00000000 00000010 section@0
|
00000000 00000000 00000028 main-section
|
||||||
00000000 00000004 ro-u-boot
|
00000000 00000000 00000010 section@0
|
||||||
00000010 00000010 section@1
|
00000000 00000000 00000004 ro-u-boot
|
||||||
00000000 00000004 rw-u-boot
|
00000010 00000010 00000010 section@1
|
||||||
|
00000010 00000000 00000004 rw-u-boot
|
||||||
''', map_data)
|
''', map_data)
|
||||||
|
|
||||||
def testUnknownContents(self):
|
def testUnknownContents(self):
|
||||||
|
@ -1042,25 +1087,31 @@ class TestFunctional(unittest.TestCase):
|
||||||
'2 to 1', str(e.exception))
|
'2 to 1', str(e.exception))
|
||||||
|
|
||||||
def testUpdateFdt(self):
|
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',
|
_, _, _, out_dtb_fname = self._DoReadFileDtb('60_fdt_update.dts',
|
||||||
update_dtb=True)
|
update_dtb=True)
|
||||||
props = self._GetPropTree(out_dtb_fname, ['pos', 'size'])
|
dtb = fdt.Fdt(out_dtb_fname)
|
||||||
with open('/tmp/x.dtb', 'wb') as outf:
|
dtb.Scan()
|
||||||
with open(out_dtb_fname) as inf:
|
props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
|
||||||
outf.write(inf.read())
|
|
||||||
self.assertEqual({
|
self.assertEqual({
|
||||||
'_testing:pos': 32,
|
'image-pos': 0,
|
||||||
|
'offset': 0,
|
||||||
|
'_testing:offset': 32,
|
||||||
'_testing:size': 1,
|
'_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/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: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/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:size': 16,
|
||||||
|
'section@1:image-pos': 16,
|
||||||
'size': 40
|
'size': 40
|
||||||
}, props)
|
}, props)
|
||||||
|
|
||||||
|
@ -1071,5 +1122,248 @@ class TestFunctional(unittest.TestCase):
|
||||||
self.assertIn('Could not complete processing of Fdt: remaining '
|
self.assertIn('Could not complete processing of Fdt: remaining '
|
||||||
'[<_testing.Entry__testing', str(e.exception))
|
'[<_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__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -57,7 +57,7 @@ class Image:
|
||||||
def AddMissingProperties(self):
|
def AddMissingProperties(self):
|
||||||
"""Add properties that are not present in the device tree
|
"""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
|
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
|
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
|
size of the entry is correct. That way we can insert the correct values
|
||||||
|
@ -73,13 +73,13 @@ class Image:
|
||||||
"""
|
"""
|
||||||
self._section.GetEntryContents()
|
self._section.GetEntryContents()
|
||||||
|
|
||||||
def GetEntryPositions(self):
|
def GetEntryOffsets(self):
|
||||||
"""Handle entries that want to set the position/size of other entries
|
"""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.
|
of entries to update, it updates them.
|
||||||
"""
|
"""
|
||||||
self._section.GetEntryPositions()
|
self._section.GetEntryOffsets()
|
||||||
|
|
||||||
def PackEntries(self):
|
def PackEntries(self):
|
||||||
"""Pack all entries into the image"""
|
"""Pack all entries into the image"""
|
||||||
|
@ -96,6 +96,9 @@ class Image:
|
||||||
def SetCalculatedProperties(self):
|
def SetCalculatedProperties(self):
|
||||||
self._section.SetCalculatedProperties()
|
self._section.SetCalculatedProperties()
|
||||||
|
|
||||||
|
def SetImagePos(self):
|
||||||
|
self._section.SetImagePos(0)
|
||||||
|
|
||||||
def ProcessEntryContents(self):
|
def ProcessEntryContents(self):
|
||||||
"""Call the ProcessContents() method for each entry
|
"""Call the ProcessContents() method for each entry
|
||||||
|
|
||||||
|
@ -121,5 +124,6 @@ class Image:
|
||||||
filename = '%s.map' % self._name
|
filename = '%s.map' % self._name
|
||||||
fname = tools.GetOutputFilename(filename)
|
fname = tools.GetOutputFilename(filename)
|
||||||
with open(fname, 'w') as fd:
|
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)
|
self._section.WriteMap(fd, 0)
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
u-boot-fixed {
|
u-boot-fixed {
|
||||||
type = "u-boot";
|
type = "u-boot";
|
||||||
pos = <61>;
|
offset = <61>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
u-boot {
|
u-boot {
|
||||||
pos = <5>;
|
offset = <5>;
|
||||||
align = <4>;
|
align = <4>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
u-boot-align {
|
u-boot-align {
|
||||||
type = "u-boot";
|
type = "u-boot";
|
||||||
pos = <3>;
|
offset = <3>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
u-boot {
|
u-boot {
|
||||||
pos = <20>;
|
offset = <20>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,13 +5,13 @@
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
sort-by-pos;
|
sort-by-offset;
|
||||||
u-boot {
|
u-boot {
|
||||||
pos = <22>;
|
offset = <22>;
|
||||||
};
|
};
|
||||||
|
|
||||||
u-boot-spl {
|
u-boot-spl {
|
||||||
pos = <1>;
|
offset = <1>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
u-boot-spl {
|
u-boot-spl {
|
||||||
pos = <0>;
|
offset = <0>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,14 +5,14 @@
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
sort-by-pos;
|
sort-by-offset;
|
||||||
end-at-4gb;
|
end-at-4gb;
|
||||||
u-boot {
|
u-boot {
|
||||||
pos = <0xfffffff0>;
|
offset = <0xfffffff0>;
|
||||||
};
|
};
|
||||||
|
|
||||||
u-boot-spl {
|
u-boot-spl {
|
||||||
pos = <0xfffffff7>;
|
offset = <0xfffffff7>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,15 +5,15 @@
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
sort-by-pos;
|
sort-by-offset;
|
||||||
end-at-4gb;
|
end-at-4gb;
|
||||||
size = <32>;
|
size = <32>;
|
||||||
u-boot {
|
u-boot {
|
||||||
pos = <0>;
|
offset = <0>;
|
||||||
};
|
};
|
||||||
|
|
||||||
u-boot-spl {
|
u-boot-spl {
|
||||||
pos = <0xffffffeb>;
|
offset = <0xffffffeb>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,15 +5,15 @@
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
sort-by-pos;
|
sort-by-offset;
|
||||||
end-at-4gb;
|
end-at-4gb;
|
||||||
size = <32>;
|
size = <32>;
|
||||||
u-boot {
|
u-boot {
|
||||||
pos = <0xffffffe0>;
|
offset = <0xffffffe0>;
|
||||||
};
|
};
|
||||||
|
|
||||||
u-boot-spl {
|
u-boot-spl {
|
||||||
pos = <0xffffffeb>;
|
offset = <0xffffffeb>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
sort-by-pos;
|
sort-by-offset;
|
||||||
end-at-4gb;
|
end-at-4gb;
|
||||||
size = <16>;
|
size = <16>;
|
||||||
intel-me {
|
intel-me {
|
||||||
filename = "me.bin";
|
filename = "me.bin";
|
||||||
pos-unset;
|
offset-unset;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
sort-by-pos;
|
sort-by-offset;
|
||||||
end-at-4gb;
|
end-at-4gb;
|
||||||
size = <0x800000>;
|
size = <0x800000>;
|
||||||
intel-descriptor {
|
intel-descriptor {
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
intel-me {
|
intel-me {
|
||||||
filename = "me.bin";
|
filename = "me.bin";
|
||||||
pos-unset;
|
offset-unset;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
sort-by-pos;
|
sort-by-offset;
|
||||||
end-at-4gb;
|
end-at-4gb;
|
||||||
size = <0x200>;
|
size = <0x200>;
|
||||||
u-boot-with-ucode-ptr {
|
u-boot-with-ucode-ptr {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
sort-by-pos;
|
sort-by-offset;
|
||||||
end-at-4gb;
|
end-at-4gb;
|
||||||
size = <0x200>;
|
size = <0x200>;
|
||||||
u-boot-with-ucode-ptr {
|
u-boot-with-ucode-ptr {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
sort-by-pos;
|
sort-by-offset;
|
||||||
end-at-4gb;
|
end-at-4gb;
|
||||||
size = <0x200>;
|
size = <0x200>;
|
||||||
u-boot-with-ucode-ptr {
|
u-boot-with-ucode-ptr {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
sort-by-pos;
|
sort-by-offset;
|
||||||
end-at-4gb;
|
end-at-4gb;
|
||||||
size = <0x200>;
|
size = <0x200>;
|
||||||
u-boot-with-ucode-ptr {
|
u-boot-with-ucode-ptr {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
sort-by-pos;
|
sort-by-offset;
|
||||||
end-at-4gb;
|
end-at-4gb;
|
||||||
size = <0x200>;
|
size = <0x200>;
|
||||||
u-boot-with-ucode-ptr {
|
u-boot-with-ucode-ptr {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
sort-by-pos;
|
sort-by-offset;
|
||||||
size = <0x200>;
|
size = <0x200>;
|
||||||
u-boot-with-ucode-ptr {
|
u-boot-with-ucode-ptr {
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
sort-by-pos;
|
sort-by-offset;
|
||||||
end-at-4gb;
|
end-at-4gb;
|
||||||
size = <0x200>;
|
size = <0x200>;
|
||||||
u-boot-with-ucode-ptr {
|
u-boot-with-ucode-ptr {
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
sort-by-pos;
|
sort-by-offset;
|
||||||
end-at-4gb;
|
end-at-4gb;
|
||||||
size = <16>;
|
size = <16>;
|
||||||
intel-me {
|
intel-me {
|
||||||
filename = "me.bin";
|
filename = "me.bin";
|
||||||
pos-unset;
|
offset-unset;
|
||||||
intval = <3>;
|
intval = <3>;
|
||||||
intarray = <5 6>;
|
intarray = <5 6>;
|
||||||
byteval = [08];
|
byteval = [08];
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
sort-by-pos;
|
sort-by-offset;
|
||||||
end-at-4gb;
|
end-at-4gb;
|
||||||
size = <0x200>;
|
size = <0x200>;
|
||||||
u-boot-spl-with-ucode-ptr {
|
u-boot-spl-with-ucode-ptr {
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
u-boot {
|
u-boot {
|
||||||
pos = <20>;
|
offset = <20>;
|
||||||
};
|
};
|
||||||
|
|
||||||
u-boot-spl2 {
|
u-boot-spl2 {
|
||||||
|
|
|
@ -24,5 +24,9 @@
|
||||||
u-boot {
|
u-boot {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
section@2 {
|
||||||
|
u-boot {
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
|
||||||
binman {
|
binman {
|
||||||
sort-by-pos;
|
sort-by-offset;
|
||||||
end-at-4gb;
|
end-at-4gb;
|
||||||
size = <0x200>;
|
size = <0x200>;
|
||||||
u-boot-spl-with-ucode-ptr {
|
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
|
#define CONFIG_BINMAN
|
||||||
#include <binman_sym.h>
|
#include <binman_sym.h>
|
||||||
|
|
||||||
binman_sym_declare(unsigned long, u_boot_spl, pos);
|
binman_sym_declare(unsigned long, u_boot_spl, offset);
|
||||||
binman_sym_declare(unsigned long long, u_boot_spl2, pos);
|
binman_sym_declare(unsigned long long, u_boot_spl2, offset);
|
||||||
binman_sym_declare(unsigned long, u_boot_any, pos);
|
binman_sym_declare(unsigned long, u_boot_any, image_pos);
|
||||||
|
|
|
@ -181,7 +181,15 @@ class Node:
|
||||||
self.subnodes = []
|
self.subnodes = []
|
||||||
self.props = {}
|
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
|
"""Find a node given its name
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -314,6 +322,17 @@ class Fdt:
|
||||||
with open(self._fname) as fd:
|
with open(self._fname) as fd:
|
||||||
self._fdt_obj = libfdt.Fdt(fd.read())
|
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='/'):
|
def Scan(self, root='/'):
|
||||||
"""Scan a device tree, building up a tree of Node objects
|
"""Scan a device tree, building up a tree of Node objects
|
||||||
|
|
||||||
|
@ -349,7 +368,7 @@ class Fdt:
|
||||||
if len(parts) < 2:
|
if len(parts) < 2:
|
||||||
return None
|
return None
|
||||||
for part in parts[1:]:
|
for part in parts[1:]:
|
||||||
node = node._FindNode(part)
|
node = node.FindNode(part)
|
||||||
if not node:
|
if not node:
|
||||||
return None
|
return None
|
||||||
return node
|
return node
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
# Written by Simon Glass <sjg@chromium.org>
|
# 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 os
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
|
@ -90,6 +93,16 @@ def EnsureCompiled(fname, capture_stderr=False):
|
||||||
return dtb_output
|
return dtb_output
|
||||||
|
|
||||||
def GetInt(node, propname, default=None):
|
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)
|
prop = node.props.get(propname)
|
||||||
if not prop:
|
if not prop:
|
||||||
return default
|
return default
|
||||||
|
@ -100,6 +113,16 @@ def GetInt(node, propname, default=None):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def GetString(node, propname, default=None):
|
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)
|
prop = node.props.get(propname)
|
||||||
if not prop:
|
if not prop:
|
||||||
return default
|
return default
|
||||||
|
@ -110,6 +133,79 @@ def GetString(node, propname, default=None):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def GetBool(node, propname, default=False):
|
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:
|
if propname in node.props:
|
||||||
return True
|
return True
|
||||||
return default
|
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')
|
fdt.CheckErr(-libfdt.NOTFOUND, 'hello')
|
||||||
self.assertIn('FDT_ERR_NOTFOUND: hello', str(e.exception))
|
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):
|
class TestNode(unittest.TestCase):
|
||||||
"""Test operation of the Node class"""
|
"""Test operation of the Node class"""
|
||||||
|
@ -155,12 +158,12 @@ class TestNode(unittest.TestCase):
|
||||||
self.assertEqual(prop.value, value)
|
self.assertEqual(prop.value, value)
|
||||||
|
|
||||||
def testFindNode(self):
|
def testFindNode(self):
|
||||||
"""Tests that we can find a node using the _FindNode() functoin"""
|
"""Tests that we can find a node using the FindNode() functoin"""
|
||||||
node = self.dtb.GetRoot()._FindNode('i2c@0')
|
node = self.dtb.GetRoot().FindNode('i2c@0')
|
||||||
self.assertEqual('i2c@0', node.name)
|
self.assertEqual('i2c@0', node.name)
|
||||||
subnode = node._FindNode('pmic@9')
|
subnode = node.FindNode('pmic@9')
|
||||||
self.assertEqual('pmic@9', subnode.name)
|
self.assertEqual('pmic@9', subnode.name)
|
||||||
self.assertEqual(None, node._FindNode('missing'))
|
self.assertEqual(None, node.FindNode('missing'))
|
||||||
|
|
||||||
def testRefreshMissingNode(self):
|
def testRefreshMissingNode(self):
|
||||||
"""Test refreshing offsets when an extra node is present in dtb"""
|
"""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 ",
|
self.assertIn("Internal error, property 'notstring' missing, offset ",
|
||||||
str(e.exception))
|
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):
|
class TestProp(unittest.TestCase):
|
||||||
"""Test operation of the Prop class"""
|
"""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(True, fdt_util.GetBool(self.node, 'missing', True))
|
||||||
self.assertEqual(False, fdt_util.GetBool(self.node, 'missing', False))
|
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):
|
def testFdtCellsToCpu(self):
|
||||||
val = self.node.props['intarray'].value
|
val = self.node.props['intarray'].value
|
||||||
self.assertEqual(0, fdt_util.fdt_cells_to_cpu(val, 0))
|
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 test_result:
|
||||||
if hasattr(test_result, '__call__'):
|
if hasattr(test_result, '__call__'):
|
||||||
return test_result(pipe_list=pipe_list)
|
result = test_result(pipe_list=pipe_list)
|
||||||
|
if result:
|
||||||
|
return result
|
||||||
|
else:
|
||||||
return test_result
|
return test_result
|
||||||
|
# No result: fall through to normal processing
|
||||||
result = CommandResult()
|
result = CommandResult()
|
||||||
last_pipe = None
|
last_pipe = None
|
||||||
pipeline = list(pipe_list)
|
pipeline = list(pipe_list)
|
||||||
|
|
|
@ -3,16 +3,26 @@
|
||||||
# Copyright (c) 2016 Google, Inc
|
# Copyright (c) 2016 Google, Inc
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import command
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
import tout
|
import tout
|
||||||
|
|
||||||
|
# Output directly (generally this is temporary)
|
||||||
outdir = None
|
outdir = None
|
||||||
indirs = None
|
|
||||||
|
# True to keep the output directory around after exiting
|
||||||
preserve_outdir = False
|
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):
|
def PrepareOutputDir(dirname, preserve=False):
|
||||||
"""Select an output directory, ensuring it exists.
|
"""Select an output directory, ensuring it exists.
|
||||||
|
|
||||||
|
@ -106,8 +116,8 @@ def GetInputFilename(fname):
|
||||||
if os.path.exists(pathname):
|
if os.path.exists(pathname):
|
||||||
return pathname
|
return pathname
|
||||||
|
|
||||||
raise ValueError("Filename '%s' not found in input path (%s)" %
|
raise ValueError("Filename '%s' not found in input path (%s) (cwd='%s')" %
|
||||||
(fname, ','.join(indir)))
|
(fname, ','.join(indir), os.getcwd()))
|
||||||
|
|
||||||
def Align(pos, align):
|
def Align(pos, align):
|
||||||
if align:
|
if align:
|
||||||
|
@ -117,3 +127,67 @@ def Align(pos, align):
|
||||||
|
|
||||||
def NotPowerOfTwo(num):
|
def NotPowerOfTwo(num):
|
||||||
return num and (num & (num - 1))
|
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