mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-18 13:11:31 +00:00
Merge git://git.denx.de/u-boot-dm
This commit is contained in:
commit
36737f22b7
91 changed files with 3709 additions and 300 deletions
57
Makefile
57
Makefile
|
@ -903,6 +903,12 @@ u-boot.ldr: u-boot
|
|||
$(LDR) -T $(CONFIG_CPU) -c $@ $< $(LDR_FLAGS)
|
||||
$(BOARD_SIZE_CHECK)
|
||||
|
||||
# binman
|
||||
# ---------------------------------------------------------------------------
|
||||
quiet_cmd_binman = BINMAN $@
|
||||
cmd_binman = $(srctree)/tools/binman/binman -d u-boot.dtb -O . \
|
||||
-I . -I $(srctree)/board/$(BOARDDIR) $<
|
||||
|
||||
OBJCOPYFLAGS_u-boot.ldr.hex := -I binary -O ihex
|
||||
|
||||
OBJCOPYFLAGS_u-boot.ldr.srec := -I binary -O srec
|
||||
|
@ -1047,50 +1053,11 @@ endif
|
|||
|
||||
# x86 uses a large ROM. We fill it with 0xff, put the 16-bit stuff (including
|
||||
# reset vector) at the top, Intel ME descriptor at the bottom, and U-Boot in
|
||||
# the middle.
|
||||
# the middle. This is handled by binman based on an image description in the
|
||||
# board's device tree.
|
||||
ifneq ($(CONFIG_X86_RESET_VECTOR),)
|
||||
rom: u-boot.rom FORCE
|
||||
|
||||
IFDTOOL=$(objtree)/tools/ifdtool
|
||||
IFDTOOL_FLAGS = -f 0:$(objtree)/u-boot.dtb
|
||||
IFDTOOL_FLAGS += -m 0x$(shell $(NM) u-boot |grep _dt_ucode_base_size |cut -d' ' -f1)
|
||||
IFDTOOL_FLAGS += -U $(CONFIG_SYS_TEXT_BASE):$(objtree)/u-boot-nodtb.bin
|
||||
IFDTOOL_FLAGS += -w $(CONFIG_SYS_X86_START16):$(objtree)/u-boot-x86-16bit.bin
|
||||
IFDTOOL_FLAGS += -C
|
||||
|
||||
ifneq ($(CONFIG_HAVE_INTEL_ME),)
|
||||
IFDTOOL_ME_FLAGS = -D $(srctree)/board/$(BOARDDIR)/descriptor.bin
|
||||
IFDTOOL_ME_FLAGS += -i ME:$(srctree)/board/$(BOARDDIR)/me.bin
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_HAVE_MRC),)
|
||||
IFDTOOL_FLAGS += -w $(CONFIG_X86_MRC_ADDR):$(srctree)/board/$(BOARDDIR)/mrc.bin
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_HAVE_FSP),)
|
||||
IFDTOOL_FLAGS += -w $(CONFIG_FSP_ADDR):$(srctree)/board/$(BOARDDIR)/$(CONFIG_FSP_FILE)
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_HAVE_CMC),)
|
||||
IFDTOOL_FLAGS += -w $(CONFIG_CMC_ADDR):$(srctree)/board/$(BOARDDIR)/$(CONFIG_CMC_FILE)
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_HAVE_VGA_BIOS),)
|
||||
IFDTOOL_FLAGS += -w $(CONFIG_VGA_BIOS_ADDR):$(srctree)/board/$(BOARDDIR)/$(CONFIG_VGA_BIOS_FILE)
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_HAVE_REFCODE),)
|
||||
IFDTOOL_FLAGS += -w $(CONFIG_X86_REFCODE_ADDR):refcode.bin
|
||||
endif
|
||||
|
||||
quiet_cmd_ifdtool = IFDTOOL $@
|
||||
cmd_ifdtool = $(IFDTOOL) -c -r $(CONFIG_ROM_SIZE) u-boot.tmp;
|
||||
ifneq ($(CONFIG_HAVE_INTEL_ME),)
|
||||
cmd_ifdtool += $(IFDTOOL) $(IFDTOOL_ME_FLAGS) u-boot.tmp;
|
||||
endif
|
||||
cmd_ifdtool += $(IFDTOOL) $(IFDTOOL_FLAGS) u-boot.tmp;
|
||||
cmd_ifdtool += mv u-boot.tmp $@
|
||||
|
||||
refcode.bin: $(srctree)/board/$(BOARDDIR)/refcode.bin FORCE
|
||||
$(call if_changed,copy)
|
||||
|
||||
|
@ -1100,7 +1067,7 @@ cmd_ldr = $(LD) $(LDFLAGS_$(@F)) \
|
|||
|
||||
u-boot.rom: u-boot-x86-16bit.bin u-boot.bin FORCE \
|
||||
$(if $(CONFIG_HAVE_REFCODE),refcode.bin)
|
||||
$(call if_changed,ifdtool)
|
||||
$(call if_changed,binman)
|
||||
|
||||
OBJCOPYFLAGS_u-boot-x86-16bit.bin := -O binary -j .start16 -j .resetvec
|
||||
u-boot-x86-16bit.bin: u-boot FORCE
|
||||
|
@ -1108,10 +1075,8 @@ u-boot-x86-16bit.bin: u-boot FORCE
|
|||
endif
|
||||
|
||||
ifneq ($(CONFIG_ARCH_SUNXI),)
|
||||
OBJCOPYFLAGS_u-boot-sunxi-with-spl.bin = -I binary -O binary \
|
||||
--pad-to=$(CONFIG_SPL_PAD_TO) --gap-fill=0xff
|
||||
u-boot-sunxi-with-spl.bin: spl/sunxi-spl.bin u-boot.img FORCE
|
||||
$(call if_changed,pad_cat)
|
||||
u-boot-sunxi-with-spl.bin: spl/sunxi-spl.bin u-boot.img u-boot.dtb FORCE
|
||||
$(call if_changed,binman)
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_TEGRA),)
|
||||
|
|
14
arch/arm/dts/sunxi-u-boot.dtsi
Normal file
14
arch/arm/dts/sunxi-u-boot.dtsi
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include <config.h>
|
||||
|
||||
/ {
|
||||
binman {
|
||||
filename = "u-boot-sunxi-with-spl.bin";
|
||||
pad-byte = <0xff>;
|
||||
blob {
|
||||
filename = "spl/sunxi-spl.bin";
|
||||
};
|
||||
u-boot-img {
|
||||
pos = <CONFIG_SPL_PAD_TO>;
|
||||
};
|
||||
};
|
||||
};
|
15
arch/arm/dts/tegra124-nyan-big-u-boot.dtsi
Normal file
15
arch/arm/dts/tegra124-nyan-big-u-boot.dtsi
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/ {
|
||||
host1x@50000000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
dc@54200000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -27,9 +27,7 @@
|
|||
};
|
||||
|
||||
host1x@50000000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
dc@54200000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
display-timings {
|
||||
timing@0 {
|
||||
clock-frequency = <69500000>;
|
||||
|
|
8
arch/arm/dts/tegra20-u-boot.dtsi
Normal file
8
arch/arm/dts/tegra20-u-boot.dtsi
Normal file
|
@ -0,0 +1,8 @@
|
|||
/ {
|
||||
host1x@50000000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
dc@54200000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -10,7 +10,6 @@
|
|||
interrupt-parent = <&lic>;
|
||||
|
||||
host1x@50000000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "nvidia,tegra20-host1x", "simple-bus";
|
||||
reg = <0x50000000 0x00024000>;
|
||||
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>, /* syncpt */
|
||||
|
@ -78,7 +77,6 @@
|
|||
};
|
||||
|
||||
dc@54200000 {
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "nvidia,tegra20-dc";
|
||||
reg = <0x54200000 0x00040000>;
|
||||
interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
|
18
arch/x86/dts/emulation-u-boot.dtsi
Normal file
18
arch/x86/dts/emulation-u-boot.dtsi
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <u-boot.dtsi>
|
||||
|
||||
#ifdef CONFIG_ROM_SIZE
|
||||
/ {
|
||||
binman {
|
||||
u-boot-with-ucode-ptr {
|
||||
optional-ucode;
|
||||
};
|
||||
};
|
||||
};
|
||||
#endif
|
62
arch/x86/dts/u-boot.dtsi
Normal file
62
arch/x86/dts/u-boot.dtsi
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef CONFIG_ROM_SIZE
|
||||
/ {
|
||||
binman {
|
||||
filename = "u-boot.rom";
|
||||
end-at-4gb;
|
||||
sort-by-pos;
|
||||
pad-byte = <0xff>;
|
||||
size = <CONFIG_ROM_SIZE>;
|
||||
#ifdef CONFIG_HAVE_INTEL_ME
|
||||
intel-descriptor {
|
||||
};
|
||||
intel-me {
|
||||
};
|
||||
#endif
|
||||
u-boot-with-ucode-ptr {
|
||||
pos = <CONFIG_SYS_TEXT_BASE>;
|
||||
};
|
||||
u-boot-dtb-with-ucode {
|
||||
};
|
||||
u-boot-ucode {
|
||||
align = <16>;
|
||||
};
|
||||
#ifdef CONFIG_HAVE_MRC
|
||||
intel-mrc {
|
||||
pos = <CONFIG_X86_MRC_ADDR>;
|
||||
};
|
||||
#endif
|
||||
#ifdef CONFIG_HAVE_FSP
|
||||
intel-fsp {
|
||||
pos = <CONFIG_FSP_ADDR>;
|
||||
};
|
||||
#endif
|
||||
#ifdef CONFIG_HAVE_CMC
|
||||
intel-cmc {
|
||||
pos = <CONFIG_CMC_ADDR>;
|
||||
};
|
||||
#endif
|
||||
#ifdef CONFIG_HAVE_VGA_BIOS
|
||||
intel-vga {
|
||||
pos = <CONFIG_VGA_BIOS_ADDR>;
|
||||
};
|
||||
#endif
|
||||
#ifdef CONFIG_HAVE_REFCODE
|
||||
intel-refcode {
|
||||
pos = <CONFIG_X86_REFCODE_ADDR>;
|
||||
};
|
||||
#endif
|
||||
x86-start16 {
|
||||
pos = <CONFIG_SYS_X86_START16>;
|
||||
};
|
||||
};
|
||||
};
|
||||
#endif
|
|
@ -164,10 +164,30 @@ cpp_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(UBOOTINCLUDE) \
|
|||
|
||||
ld_flags = $(LDFLAGS) $(ldflags-y)
|
||||
|
||||
dts_dir = $(srctree)/arch/$(ARCH)/dts
|
||||
|
||||
# Try these files in order to find the U-Boot-specific .dtsi include file
|
||||
u_boot_dtsi_options = $(wildcard $(dts_dir)/$(basename $(notdir $<))-u-boot.dtsi) \
|
||||
$(wildcard $(dts_dir)/$(subst $\",,$(CONFIG_SYS_SOC))-u-boot.dtsi) \
|
||||
$(wildcard $(dts_dir)/$(subst $\",,$(CONFIG_SYS_CPU))-u-boot.dtsi) \
|
||||
$(wildcard $(dts_dir)/$(subst $\",,$(CONFIG_SYS_VENDOR))-u-boot.dtsi) \
|
||||
$(wildcard $(dts_dir)/u-boot.dtsi)
|
||||
|
||||
# Uncomment for debugging
|
||||
# $(warning u_boot_dtsi_options: $(u_boot_dtsi_options))
|
||||
|
||||
# We use the first match
|
||||
u_boot_dtsi = $(firstword $(u_boot_dtsi_options))
|
||||
|
||||
# Modified for U-Boot
|
||||
dtc_cpp_flags = -Wp,-MD,$(depfile).pre.tmp -nostdinc \
|
||||
-I$(srctree)/arch/$(ARCH)/dts \
|
||||
-I$(srctree)/arch/$(ARCH)/dts/include \
|
||||
-Iinclude \
|
||||
-I$(srctree)/include \
|
||||
-I$(srctree)/arch/$(ARCH)/include \
|
||||
-include $(srctree)/include/linux/kconfig.h \
|
||||
-D__ASSEMBLY__ \
|
||||
-undef -D__DTS__
|
||||
|
||||
# Finds the multi-part object the current object will be linked into
|
||||
|
@ -288,8 +308,11 @@ $(obj)/%.dtb.S: $(obj)/%.dtb
|
|||
|
||||
quiet_cmd_dtc = DTC $@
|
||||
# Modified for U-Boot
|
||||
# Bring in any U-Boot-specific include after the '/dts-v1/;' header
|
||||
cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \
|
||||
$(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \
|
||||
cat $< $(if $(u_boot_dtsi),\
|
||||
| sed 's%^/ {$$%\#include \"$(u_boot_dtsi)\"\n&%') | \
|
||||
$(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) - ; \
|
||||
$(DTC) -O dtb -o $@ -b 0 \
|
||||
-i $(dir $<) $(DTC_FLAGS) \
|
||||
-d $(depfile).dtc.tmp $(dtc-tmp) ; \
|
||||
|
|
1
tools/binman/.gitignore
vendored
Normal file
1
tools/binman/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
*.pyc
|
541
tools/binman/README
Normal file
541
tools/binman/README
Normal file
|
@ -0,0 +1,541 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Firmware often consists of several components which must be packaged together.
|
||||
For example, we may have SPL, U-Boot, a device tree and an environment area
|
||||
grouped together and placed in MMC flash. When the system starts, it must be
|
||||
able to find these pieces.
|
||||
|
||||
So far U-Boot has not provided a way to handle creating such images in a
|
||||
general way. Each SoC does what it needs to build an image, often packing or
|
||||
concatenating images in the U-Boot build system.
|
||||
|
||||
Binman aims to provide a mechanism for building images, from simple
|
||||
SPL + U-Boot combinations, to more complex arrangements with many parts.
|
||||
|
||||
|
||||
What it does
|
||||
------------
|
||||
|
||||
Binman reads your board's device tree and finds a node which describes the
|
||||
required image layout. It uses this to work out what to place where. The
|
||||
output file normally contains the device tree, so it is in principle possible
|
||||
to read an image and extract its constituent parts.
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
So far binman is pretty simple. It supports binary blobs, such as 'u-boot',
|
||||
'spl' and 'fdt'. It supports empty entries (such as setting to 0xff). It can
|
||||
place entries at a fixed location in the image, or fit them together with
|
||||
suitable padding and alignment. It provides a way to process binaries before
|
||||
they are included, by adding a Python plug-in. The device tree is available
|
||||
to U-Boot at run-time so that the images can be interpreted.
|
||||
|
||||
Binman does not yet update the device tree with the final location of
|
||||
everything when it is done. A simple C structure could be generated for
|
||||
constrained environments like SPL (using dtoc) but this is also not
|
||||
implemented.
|
||||
|
||||
Binman can also support incorporating filesystems in the image if required.
|
||||
For example x86 platforms may use CBFS in some cases.
|
||||
|
||||
Binman is intended for use with U-Boot but is designed to be general enough
|
||||
to be useful in other image-packaging situations.
|
||||
|
||||
|
||||
Motivation
|
||||
----------
|
||||
|
||||
Packaging of firmware is quite a different task from building the various
|
||||
parts. In many cases the various binaries which go into the image come from
|
||||
separate build systems. For example, ARM Trusted Firmware is used on ARMv8
|
||||
devices but is not built in the U-Boot tree. If a Linux kernel is included
|
||||
in the firmware image, it is built elsewhere.
|
||||
|
||||
It is of course possible to add more and more build rules to the U-Boot
|
||||
build system to cover these cases. It can shell out to other Makefiles and
|
||||
build scripts. But it seems better to create a clear divide between building
|
||||
software and packaging it.
|
||||
|
||||
At present this is handled by manual instructions, different for each board,
|
||||
on how to create images that will boot. By turning these instructions into a
|
||||
standard format, we can support making valid images for any board without
|
||||
manual effort, lots of READMEs, etc.
|
||||
|
||||
Benefits:
|
||||
- Each binary can have its own build system and tool chain without creating
|
||||
any dependencies between them
|
||||
- Avoids the need for a single-shot build: individual parts can be updated
|
||||
and brought in as needed
|
||||
- Provides for a standard image description available in the build and at
|
||||
run-time
|
||||
- SoC-specific image-signing tools can be accomodated
|
||||
- Avoids cluttering the U-Boot build system with image-building code
|
||||
- The image description is automatically available at run-time in U-Boot,
|
||||
SPL. It can be made available to other software also
|
||||
- The image description is easily readable (it's a text file in device-tree
|
||||
format) and permits flexible packing of binaries
|
||||
|
||||
|
||||
Terminology
|
||||
-----------
|
||||
|
||||
Binman uses the following terms:
|
||||
|
||||
- image - an output file containing a firmware image
|
||||
- binary - an input binary that goes into the image
|
||||
|
||||
|
||||
Relationship to FIT
|
||||
-------------------
|
||||
|
||||
FIT is U-Boot's official image format. It supports multiple binaries with
|
||||
load / execution addresses, compression. It also supports verification
|
||||
through hashing and RSA signatures.
|
||||
|
||||
FIT was originally designed to support booting a Linux kernel (with an
|
||||
optional ramdisk) and device tree chosen from various options in the FIT.
|
||||
Now that U-Boot supports configuration via device tree, it is possible to
|
||||
load U-Boot from a FIT, with the device tree chosen by SPL.
|
||||
|
||||
Binman considers FIT to be one of the binaries it can place in the image.
|
||||
|
||||
Where possible it is best to put as much as possible in the FIT, with binman
|
||||
used to deal with cases not covered by FIT. Examples include initial
|
||||
execution (since FIT itself does not have an executable header) and dealing
|
||||
with device boundaries, such as the read-only/read-write separation in SPI
|
||||
flash.
|
||||
|
||||
For U-Boot, binman should not be used to create ad-hoc images in place of
|
||||
FIT.
|
||||
|
||||
|
||||
Relationship to mkimage
|
||||
-----------------------
|
||||
|
||||
The mkimage tool provides a means to create a FIT. Traditionally it has
|
||||
needed an image description file: a device tree, like binman, but in a
|
||||
different format. More recently it has started to support a '-f auto' mode
|
||||
which can generate that automatically.
|
||||
|
||||
More relevant to binman, mkimage also permits creation of many SoC-specific
|
||||
image types. These can be listed by running 'mkimage -T list'. Examples
|
||||
include 'rksd', the Rockchip SD/MMC boot format. The mkimage tool is often
|
||||
called from the U-Boot build system for this reason.
|
||||
|
||||
Binman considers the output files created by mkimage to be binary blobs
|
||||
which it can place in an image. Binman does not replace the mkimage tool or
|
||||
this purpose. It would be possible in some situtions to create a new entry
|
||||
type for the images in mkimage, but this would not add functionality. It
|
||||
seems better to use the mkiamge tool to generate binaries and avoid blurring
|
||||
the boundaries between building input files (mkimage) and packaging then
|
||||
into a final image (binman).
|
||||
|
||||
|
||||
Example use of binman in U-Boot
|
||||
-------------------------------
|
||||
|
||||
Binman aims to replace some of the ad-hoc image creation in the U-Boot
|
||||
build system.
|
||||
|
||||
Consider sunxi. It has the following steps:
|
||||
|
||||
1. It uses a custom mksunxiboot tool to build an SPL image called
|
||||
sunxi-spl.bin. This should probably move into mkimage.
|
||||
|
||||
2. It uses mkimage to package U-Boot into a legacy image file (so that it can
|
||||
hold the load and execution address) called u-boot.img.
|
||||
|
||||
3. It builds a final output image called u-boot-sunxi-with-spl.bin which
|
||||
consists of sunxi-spl.bin, some padding and u-boot.img.
|
||||
|
||||
Binman is intended to replace the last step. The U-Boot build system builds
|
||||
u-boot.bin and sunxi-spl.bin. Binman can then take over creation of
|
||||
sunxi-spl.bin (by calling mksunxiboot, or hopefully one day mkimage). In any
|
||||
case, it would then create the image from the component parts.
|
||||
|
||||
This simplifies the U-Boot Makefile somewhat, since various pieces of logic
|
||||
can be replaced by a call to binman.
|
||||
|
||||
|
||||
Example use of binman for x86
|
||||
-----------------------------
|
||||
|
||||
In most cases x86 images have a lot of binary blobs, 'black-box' code
|
||||
provided by Intel which must be run for the platform to work. Typically
|
||||
these blobs are not relocatable and must be placed at fixed areas in the
|
||||
firmare image.
|
||||
|
||||
Currently this is handled by ifdtool, which places microcode, FSP, MRC, VGA
|
||||
BIOS, reference code and Intel ME binaries into a u-boot.rom file.
|
||||
|
||||
Binman is intended to replace all of this, with ifdtool left to handle only
|
||||
the configuration of the Intel-format descriptor.
|
||||
|
||||
|
||||
Running binman
|
||||
--------------
|
||||
|
||||
Type:
|
||||
|
||||
binman -b <board_name>
|
||||
|
||||
to build an image for a board. The board name is the same name used when
|
||||
configuring U-Boot (e.g. for sandbox_defconfig the board name is 'sandbox').
|
||||
Binman assumes that the input files for the build are in ../b/<board_name>.
|
||||
|
||||
Or you can specify this explicitly:
|
||||
|
||||
binman -I <build_path>
|
||||
|
||||
where <build_path> is the build directory containing the output of the U-Boot
|
||||
build.
|
||||
|
||||
(Future work will make this more configurable)
|
||||
|
||||
In either case, binman picks up the device tree file (u-boot.dtb) and looks
|
||||
for its instructions in the 'binman' node.
|
||||
|
||||
Binman has a few other options which you can see by running 'binman -h'.
|
||||
|
||||
|
||||
Image description format
|
||||
------------------------
|
||||
|
||||
The binman node is called 'binman'. An example image description is shown
|
||||
below:
|
||||
|
||||
binman {
|
||||
filename = "u-boot-sunxi-with-spl.bin";
|
||||
pad-byte = <0xff>;
|
||||
blob {
|
||||
filename = "spl/sunxi-spl.bin";
|
||||
};
|
||||
u-boot {
|
||||
pos = <CONFIG_SPL_PAD_TO>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
This requests binman to create an image file called u-boot-sunxi-with-spl.bin
|
||||
consisting of a specially formatted SPL (spl/sunxi-spl.bin, built by the
|
||||
normal U-Boot Makefile), some 0xff padding, and a U-Boot legacy image. The
|
||||
padding comes from the fact that the second binary is placed at
|
||||
CONFIG_SPL_PAD_TO. If that line were omitted then the U-Boot binary would
|
||||
immediately follow the SPL binary.
|
||||
|
||||
The binman node describes an image. The sub-nodes describe entries in the
|
||||
image. Each entry represents a region within the overall image. The name of
|
||||
the entry (blob, u-boot) tells binman what to put there. For 'blob' we must
|
||||
provide a filename. For 'u-boot', binman knows that this means 'u-boot.bin'.
|
||||
|
||||
Entries are normally placed into the image sequentially, one after the other.
|
||||
The image size is the total size of all entries. As you can see, you can
|
||||
specify the start position of an entry using the 'pos' property.
|
||||
|
||||
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
|
||||
use any unique name, with the 'type' property providing the type.
|
||||
|
||||
The attributes supported for entries are described below.
|
||||
|
||||
pos:
|
||||
This sets the position of an entry within the image. The first byte
|
||||
of the image is normally at position 0. If 'pos' is not provided,
|
||||
binman sets it to the end of the previous region, or the start of
|
||||
the image's entry area (normally 0) if there is no previous region.
|
||||
|
||||
align:
|
||||
This sets the alignment of the entry. The entry position is adjusted
|
||||
so that the entry starts on an aligned boundary within the image. For
|
||||
example 'align = <16>' means that the entry will start on a 16-byte
|
||||
boundary. Alignment shold be a power of 2. If 'align' is not
|
||||
provided, no alignment is performed.
|
||||
|
||||
size:
|
||||
This sets the size of the entry. The contents will be padded out to
|
||||
this size. If this is not provided, it will be set to the size of the
|
||||
contents.
|
||||
|
||||
pad-before:
|
||||
Padding before the contents of the entry. Normally this is 0, meaning
|
||||
that the contents start at the beginning of the entry. This can be
|
||||
offset the entry contents a little. Defaults to 0.
|
||||
|
||||
pad-after:
|
||||
Padding after the contents of the entry. Normally this is 0, meaning
|
||||
that the entry ends at the last byte of content (unless adjusted by
|
||||
other properties). This allows room to be created in the image for
|
||||
this entry to expand later. Defaults to 0.
|
||||
|
||||
align-size:
|
||||
This sets the alignment of the entry size. For example, to ensure
|
||||
that the size of an entry is a multiple of 64 bytes, set this to 64.
|
||||
If 'align-size' is not provided, no alignment is performed.
|
||||
|
||||
align-end:
|
||||
This sets the alignment of the end of an entry. Some entries require
|
||||
that they end on an alignment boundary, regardless of where they
|
||||
start. If 'align-end' is not provided, no alignment is performed.
|
||||
|
||||
Note: This is not yet implemented in binman.
|
||||
|
||||
filename:
|
||||
For 'blob' types this provides the filename containing the binary to
|
||||
put into the entry. If binman knows about the entry type (like
|
||||
u-boot-bin), then there is no need to specify this.
|
||||
|
||||
type:
|
||||
Sets the type of an entry. This defaults to the entry name, but it is
|
||||
possible to use any name, and then add (for example) 'type = "u-boot"'
|
||||
to specify the type.
|
||||
|
||||
|
||||
The attributes supported for images are described below. Several are similar
|
||||
to those for entries.
|
||||
|
||||
size:
|
||||
Sets the image size in bytes, for example 'size = <0x100000>' for a
|
||||
1MB image.
|
||||
|
||||
align-size:
|
||||
This sets the alignment of the image size. For example, to ensure
|
||||
that the image ends on a 512-byte boundary, use 'align-size = <512>'.
|
||||
If 'align-size' is not provided, no alignment is performed.
|
||||
|
||||
pad-before:
|
||||
This sets the padding before the image entries. The first entry will
|
||||
be positionad after the padding. This defaults to 0.
|
||||
|
||||
pad-after:
|
||||
This sets the padding after the image entries. The padding will be
|
||||
placed after the last entry. This defaults to 0.
|
||||
|
||||
pad-byte:
|
||||
This specifies the pad byte to use when padding in the image. It
|
||||
defaults to 0. To use 0xff, you would add 'pad-byte = <0xff>'.
|
||||
|
||||
filename:
|
||||
This specifies the image filename. It defaults to 'image.bin'.
|
||||
|
||||
sort-by-pos:
|
||||
This causes binman to reorder the entries as needed to make sure they
|
||||
are in increasing positional order. This can be used when your entry
|
||||
order may not match the positional order. A common situation is where
|
||||
the 'pos' properties are set by CONFIG options, so their ordering is
|
||||
not known a priori.
|
||||
|
||||
This is a boolean property so needs no value. To enable it, add a
|
||||
line 'sort-by-pos;' to your description.
|
||||
|
||||
multiple-images:
|
||||
Normally only a single image is generated. To create more than one
|
||||
image, put this property in the binman node. For example, this will
|
||||
create image1.bin containing u-boot.bin, and image2.bin containing
|
||||
both spl/u-boot-spl.bin and u-boot.bin:
|
||||
|
||||
binman {
|
||||
multiple-images;
|
||||
image1 {
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
|
||||
image2 {
|
||||
spl {
|
||||
};
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
end-at-4gb:
|
||||
For x86 machines the ROM positions start just before 4GB and extend
|
||||
up so that the image finished at the 4GB boundary. This boolean
|
||||
option can be enabled to support this. The image size must be
|
||||
provided so that binman knows when the image should start. For an
|
||||
8MB ROM, the position of the first entry would be 0xfff80000 with
|
||||
this option, instead of 0 without this option.
|
||||
|
||||
|
||||
Examples of the above options can be found in the tests. See the
|
||||
tools/binman/test directory.
|
||||
|
||||
|
||||
Special properties
|
||||
------------------
|
||||
|
||||
Some entries support special properties, documented here:
|
||||
|
||||
u-boot-with-ucode-ptr:
|
||||
optional-ucode: boolean property to make microcode optional. If the
|
||||
u-boot.bin image does not include microcode, no error will
|
||||
be generated.
|
||||
|
||||
|
||||
Order of image creation
|
||||
-----------------------
|
||||
|
||||
Image creation proceeds in the following order, for each entry in the image.
|
||||
|
||||
1. GetEntryContents() - the contents of each entry are obtained, normally by
|
||||
reading from a file. This calls the Entry.ObtainContents() to read the
|
||||
contents. The default version of Entry.ObtainContents() calls
|
||||
Entry.GetDefaultFilename() and then reads that file. So a common mechanism
|
||||
to select a file to read is to override that function in the subclass. The
|
||||
functions must return True when they have read the contents. Binman will
|
||||
retry calling the functions a few times if False is returned, allowing
|
||||
dependencies between the contents of different entries.
|
||||
|
||||
2. GetEntryPositions() - calls Entry.GetPositions() for each entry. This can
|
||||
return a dict containing entries that need updating. The key should be the
|
||||
entry name and the value is a tuple (pos, size). This allows an entry to
|
||||
provide the position and size for other entries. The default implementation
|
||||
of GetEntryPositions() returns {}.
|
||||
|
||||
3. PackEntries() - calls Entry.Pack() which figures out the position and
|
||||
size of an entry. The 'current' image position is passed in, and the function
|
||||
returns the position immediately after the entry being packed. The default
|
||||
implementation of Pack() is usually sufficient.
|
||||
|
||||
4. CheckSize() - checks that the contents of all the entries fits within
|
||||
the image size. If the image does not have a defined size, the size is set
|
||||
large enough to hold all the entries.
|
||||
|
||||
5. CheckEntries() - checks that the entries do not overlap, nor extend
|
||||
outside the image.
|
||||
|
||||
6. ProcessEntryContents() - this calls Entry.ProcessContents() on each entry.
|
||||
The default implementatoin does nothing. This can be overriden to adjust the
|
||||
contents of an entry in some way. For example, it would be possible to create
|
||||
an entry containing a hash of the contents of some other entries. At this
|
||||
stage the position and size of entries should not be adjusted.
|
||||
|
||||
7. BuildImage() - builds the image and writes it to a file. This is the final
|
||||
step.
|
||||
|
||||
|
||||
Automatic .dtsi inclusion
|
||||
-------------------------
|
||||
|
||||
It is sometimes inconvenient to add a 'binman' node to the .dts file for each
|
||||
board. This can be done by using #include to bring in a common file. Another
|
||||
approach supported by the U-Boot build system is to automatically include
|
||||
a common header. You can then put the binman node (and anything else that is
|
||||
specific to U-Boot, such as u-boot,dm-pre-reloc properies) in that header
|
||||
file.
|
||||
|
||||
Binman will search for the following files in arch/<arch>/dts:
|
||||
|
||||
<dts>-u-boot.dtsi where <dts> is the base name of the .dts file
|
||||
<CONFIG_SYS_SOC>-u-boot.dtsi
|
||||
<CONFIG_SYS_CPU>-u-boot.dtsi
|
||||
<CONFIG_SYS_VENDOR>-u-boot.dtsi
|
||||
u-boot.dtsi
|
||||
|
||||
U-Boot will only use the first one that it finds. If you need to include a
|
||||
more general file you can do that from the more specific file using #include.
|
||||
If you are having trouble figuring out what is going on, you can uncomment
|
||||
the 'warning' line in scripts/Makefile.lib to see what it has found:
|
||||
|
||||
# Uncomment for debugging
|
||||
# $(warning binman_dtsi_options: $(binman_dtsi_options))
|
||||
|
||||
|
||||
Code coverage
|
||||
-------------
|
||||
|
||||
Binman is a critical tool and is designed to be very testable. Entry
|
||||
implementations target 100% test coverage. Run 'binman -T' to check this.
|
||||
|
||||
To enable Python test coverage on Debian-type distributions (e.g. Ubuntu):
|
||||
|
||||
$ sudo apt-get install python-pip python-pytest
|
||||
$ sudo pip install coverage
|
||||
|
||||
|
||||
Advanced Features / Technical docs
|
||||
----------------------------------
|
||||
|
||||
The behaviour of entries is defined by the Entry class. All other entries are
|
||||
a subclass of this. An important subclass is Entry_blob which takes binary
|
||||
data from a file and places it in the entry. In fact most entry types are
|
||||
subclasses of Entry_blob.
|
||||
|
||||
Each entry type is a separate file in the tools/binman/etype directory. Each
|
||||
file contains a class called Entry_<type> where <type> is the entry type.
|
||||
New entry types can be supported by adding new files in that directory.
|
||||
These will automatically be detected by binman when needed.
|
||||
|
||||
Entry properties are documented in entry.py. The entry subclasses are free
|
||||
to change the values of properties to support special behaviour. For example,
|
||||
when Entry_blob loads a file, it sets content_size to the size of the file.
|
||||
Entry classes can adjust other entries. For example, an entry that knows
|
||||
where other entries should be positioned can set up those entries' positions
|
||||
so they don't need to be set in the binman decription. It can also adjust
|
||||
entry contents.
|
||||
|
||||
Most of the time such essoteric behaviour is not needed, but it can be
|
||||
essential for complex images.
|
||||
|
||||
|
||||
History / Credits
|
||||
-----------------
|
||||
|
||||
Binman takes a lot of inspiration from a Chrome OS tool called
|
||||
'cros_bundle_firmware', which I wrote some years ago. That tool was based on
|
||||
a reasonably simple and sound design but has expanded greatly over the
|
||||
years. In particular its handling of x86 images is convoluted.
|
||||
|
||||
Quite a few lessons have been learned which are hopefully be applied here.
|
||||
|
||||
|
||||
Design notes
|
||||
------------
|
||||
|
||||
On the face of it, a tool to create firmware images should be fairly simple:
|
||||
just find all the input binaries and place them at the right place in the
|
||||
image. The difficulty comes from the wide variety of input types (simple
|
||||
flat binaries containing code, packaged data with various headers), packing
|
||||
requirments (alignment, spacing, device boundaries) and other required
|
||||
features such as hierarchical images.
|
||||
|
||||
The design challenge is to make it easy to create simple images, while
|
||||
allowing the more complex cases to be supported. For example, for most
|
||||
images we don't much care exactly where each binary ends up, so we should
|
||||
not have to specify that unnecessarily.
|
||||
|
||||
New entry types should aim to provide simple usage where possible. If new
|
||||
core features are needed, they can be added in the Entry base class.
|
||||
|
||||
|
||||
To do
|
||||
-----
|
||||
|
||||
Some ideas:
|
||||
- Fill out the device tree to include the final position and size of each
|
||||
entry (since the input file may not always specify these)
|
||||
- Use of-platdata to make the information available to code that is unable
|
||||
to use device tree (such as a very small SPL image)
|
||||
- Write an image map to a text file
|
||||
- Allow easy building of images by specifying just the board name
|
||||
- Produce a full Python binding for libfdt (for upstream)
|
||||
- Add an option to decode an image into the constituent binaries
|
||||
- Suppoort hierarchical images (packing of binaries into another binary
|
||||
which is then placed in the image)
|
||||
- Support building an image for a board (-b) more completely, with a
|
||||
configurable build directory
|
||||
- Consider making binman work with buildman, although if it is used in the
|
||||
Makefile, this will be automatic
|
||||
- Implement align-end
|
||||
|
||||
--
|
||||
Simon Glass <sjg@chromium.org>
|
||||
7/7/2016
|
1
tools/binman/binman
Symbolic link
1
tools/binman/binman
Symbolic link
|
@ -0,0 +1 @@
|
|||
binman.py
|
114
tools/binman/binman.py
Executable file
114
tools/binman/binman.py
Executable file
|
@ -0,0 +1,114 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Creates binary images from input files controlled by a description
|
||||
#
|
||||
|
||||
"""See README for more information"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
import unittest
|
||||
|
||||
# Bring in the patman and dtoc libraries
|
||||
our_path = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.join(our_path, '../patman'))
|
||||
sys.path.append(os.path.join(our_path, '../dtoc'))
|
||||
|
||||
# Also allow entry-type modules to be brought in from the etype directory.
|
||||
sys.path.append(os.path.join(our_path, 'etype'))
|
||||
|
||||
import cmdline
|
||||
import command
|
||||
import control
|
||||
|
||||
def RunTests():
|
||||
"""Run the functional tests and any embedded doctests"""
|
||||
import entry_test
|
||||
import fdt_test
|
||||
import func_test
|
||||
import test
|
||||
import doctest
|
||||
|
||||
result = unittest.TestResult()
|
||||
for module in []:
|
||||
suite = doctest.DocTestSuite(module)
|
||||
suite.run(result)
|
||||
|
||||
sys.argv = [sys.argv[0]]
|
||||
for module in (func_test.TestFunctional, fdt_test.TestFdt,
|
||||
entry_test.TestEntry):
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase(module)
|
||||
suite.run(result)
|
||||
|
||||
print result
|
||||
for test, err in result.errors:
|
||||
print test.id(), err
|
||||
for test, err in result.failures:
|
||||
print err
|
||||
|
||||
def RunTestCoverage():
|
||||
"""Run the tests and check that we get 100% coverage"""
|
||||
# This uses the build output from sandbox_spl to get _libfdt.so
|
||||
cmd = ('PYTHONPATH=%s/sandbox_spl/tools coverage run '
|
||||
'--include "tools/binman/*.py" --omit "*test*,*binman.py" '
|
||||
'tools/binman/binman.py -t' % options.build_dir)
|
||||
os.system(cmd)
|
||||
stdout = command.Output('coverage', 'report')
|
||||
coverage = stdout.splitlines()[-1].split(' ')[-1]
|
||||
if coverage != '100%':
|
||||
print stdout
|
||||
print "Type 'coverage html' to get a report in htmlcov/index.html"
|
||||
raise ValueError('Coverage error: %s, but should be 100%%' % coverage)
|
||||
|
||||
|
||||
def RunBinman(options, args):
|
||||
"""Main entry point to binman once arguments are parsed
|
||||
|
||||
Args:
|
||||
options: Command-line options
|
||||
args: Non-option arguments
|
||||
"""
|
||||
ret_code = 0
|
||||
|
||||
# For testing: This enables full exception traces.
|
||||
#options.debug = True
|
||||
|
||||
if not options.debug:
|
||||
sys.tracebacklimit = 0
|
||||
|
||||
if options.test:
|
||||
RunTests()
|
||||
|
||||
elif options.test_coverage:
|
||||
RunTestCoverage()
|
||||
|
||||
elif options.full_help:
|
||||
pager = os.getenv('PAGER')
|
||||
if not pager:
|
||||
pager = 'more'
|
||||
fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
|
||||
'README')
|
||||
command.Run(pager, fname)
|
||||
|
||||
else:
|
||||
try:
|
||||
ret_code = control.Binman(options, args)
|
||||
except Exception as e:
|
||||
print 'binman: %s' % e
|
||||
if options.debug:
|
||||
print
|
||||
traceback.print_exc()
|
||||
ret_code = 1
|
||||
return ret_code
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
(options, args) = cmdline.ParseArgs(sys.argv)
|
||||
ret_code = RunBinman(options, args)
|
||||
sys.exit(ret_code)
|
53
tools/binman/cmdline.py
Normal file
53
tools/binman/cmdline.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Command-line parser for binman
|
||||
#
|
||||
|
||||
from optparse import OptionParser
|
||||
|
||||
def ParseArgs(argv):
|
||||
"""Parse the binman command-line arguments
|
||||
|
||||
Args:
|
||||
argv: List of string arguments
|
||||
Returns:
|
||||
Tuple (options, args) with the command-line options and arugments.
|
||||
options provides access to the options (e.g. option.debug)
|
||||
args is a list of string arguments
|
||||
"""
|
||||
parser = OptionParser()
|
||||
parser.add_option('-b', '--board', type='string',
|
||||
help='Board name to build')
|
||||
parser.add_option('-B', '--build-dir', type='string', default='b',
|
||||
help='Directory containing the build output')
|
||||
parser.add_option('-d', '--dt', type='string',
|
||||
help='Configuration file (.dtb) to use')
|
||||
parser.add_option('-D', '--debug', action='store_true',
|
||||
help='Enabling debugging (provides a full traceback on error)')
|
||||
parser.add_option('-I', '--indir', action='append',
|
||||
help='Add a path to a directory to use for input files')
|
||||
parser.add_option('-H', '--full-help', action='store_true',
|
||||
default=False, help='Display the README file')
|
||||
parser.add_option('-O', '--outdir', type='string',
|
||||
action='store', help='Path to directory to use for intermediate and '
|
||||
'output files')
|
||||
parser.add_option('-p', '--preserve', action='store_true',\
|
||||
help='Preserve temporary output directory even if option -O is not '
|
||||
'given')
|
||||
parser.add_option('-t', '--test', action='store_true',
|
||||
default=False, help='run tests')
|
||||
parser.add_option('-T', '--test-coverage', action='store_true',
|
||||
default=False, help='run tests and check for 100% coverage')
|
||||
parser.add_option('-v', '--verbosity', default=1,
|
||||
type='int', help='Control verbosity: 0=silent, 1=progress, 3=full, '
|
||||
'4=debug')
|
||||
|
||||
parser.usage += """
|
||||
|
||||
Create images for a board from a set of binaries. It is controlled by a
|
||||
description in the board device tree."""
|
||||
|
||||
return parser.parse_args(argv)
|
118
tools/binman/control.py
Normal file
118
tools/binman/control.py
Normal file
|
@ -0,0 +1,118 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Creates binary images from input files controlled by a description
|
||||
#
|
||||
|
||||
from collections import OrderedDict
|
||||
import os
|
||||
import sys
|
||||
import tools
|
||||
|
||||
import command
|
||||
import fdt_select
|
||||
import fdt_util
|
||||
from image import Image
|
||||
import tout
|
||||
|
||||
# List of images we plan to create
|
||||
# Make this global so that it can be referenced from tests
|
||||
images = OrderedDict()
|
||||
|
||||
def _ReadImageDesc(binman_node):
|
||||
"""Read the image descriptions from the /binman node
|
||||
|
||||
This normally produces a single Image object called 'image'. But if
|
||||
multiple images are present, they will all be returned.
|
||||
|
||||
Args:
|
||||
binman_node: Node object of the /binman node
|
||||
Returns:
|
||||
OrderedDict of Image objects, each of which describes an image
|
||||
"""
|
||||
images = OrderedDict()
|
||||
if 'multiple-images' in binman_node.props:
|
||||
for node in binman_node.subnodes:
|
||||
images[node.name] = Image(node.name, node)
|
||||
else:
|
||||
images['image'] = Image('image', binman_node)
|
||||
return images
|
||||
|
||||
def _FindBinmanNode(fdt):
|
||||
"""Find the 'binman' node in the device tree
|
||||
|
||||
Args:
|
||||
fdt: Fdt object to scan
|
||||
Returns:
|
||||
Node object of /binman node, or None if not found
|
||||
"""
|
||||
for node in fdt.GetRoot().subnodes:
|
||||
if node.name == 'binman':
|
||||
return node
|
||||
return None
|
||||
|
||||
def Binman(options, args):
|
||||
"""The main control code for binman
|
||||
|
||||
This assumes that help and test options have already been dealt with. It
|
||||
deals with the core task of building images.
|
||||
|
||||
Args:
|
||||
options: Command line options object
|
||||
args: Command line arguments (list of strings)
|
||||
"""
|
||||
global images
|
||||
|
||||
if options.full_help:
|
||||
pager = os.getenv('PAGER')
|
||||
if not pager:
|
||||
pager = 'more'
|
||||
fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
|
||||
'README')
|
||||
command.Run(pager, fname)
|
||||
return 0
|
||||
|
||||
# Try to figure out which device tree contains our image description
|
||||
if options.dt:
|
||||
dtb_fname = options.dt
|
||||
else:
|
||||
board = options.board
|
||||
if not board:
|
||||
raise ValueError('Must provide a board to process (use -b <board>)')
|
||||
board_pathname = os.path.join(options.build_dir, board)
|
||||
dtb_fname = os.path.join(board_pathname, 'u-boot.dtb')
|
||||
if not options.indir:
|
||||
options.indir = ['.']
|
||||
options.indir.append(board_pathname)
|
||||
|
||||
try:
|
||||
tout.Init(options.verbosity)
|
||||
try:
|
||||
tools.SetInputDirs(options.indir)
|
||||
tools.PrepareOutputDir(options.outdir, options.preserve)
|
||||
fdt = fdt_select.FdtScan(dtb_fname)
|
||||
node = _FindBinmanNode(fdt)
|
||||
if not node:
|
||||
raise ValueError("Device tree '%s' does not have a 'binman' "
|
||||
"node" % dtb_fname)
|
||||
images = _ReadImageDesc(node)
|
||||
for image in images.values():
|
||||
# Perform all steps for this image, including checking and
|
||||
# writing it. This means that errors found with a later
|
||||
# image will be reported after earlier images are already
|
||||
# completed and written, but that does not seem important.
|
||||
image.GetEntryContents()
|
||||
image.GetEntryPositions()
|
||||
image.PackEntries()
|
||||
image.CheckSize()
|
||||
image.CheckEntries()
|
||||
image.ProcessEntryContents()
|
||||
image.BuildImage()
|
||||
finally:
|
||||
tools.FinaliseOutputDir()
|
||||
finally:
|
||||
tout.Uninit()
|
||||
|
||||
return 0
|
27
tools/binman/entry_test.py
Normal file
27
tools/binman/entry_test.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
#
|
||||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Test for the Entry class
|
||||
|
||||
import collections
|
||||
import unittest
|
||||
|
||||
import entry
|
||||
|
||||
class TestEntry(unittest.TestCase):
|
||||
def testEntryContents(self):
|
||||
"""Test the Entry bass class"""
|
||||
base_entry = entry.Entry(None, None, None, read_node=False)
|
||||
self.assertEqual(True, base_entry.ObtainContents())
|
||||
|
||||
def testUnknownEntry(self):
|
||||
"""Test that unknown entry types are detected"""
|
||||
Node = collections.namedtuple('Node', ['name', 'path'])
|
||||
node = Node('invalid-name', 'invalid-path')
|
||||
with self.assertRaises(ValueError) as e:
|
||||
entry.Entry.Create(None, node, node.name)
|
||||
self.assertIn("Unknown entry type 'invalid-name' in node "
|
||||
"'invalid-path'", str(e.exception))
|
26
tools/binman/etype/_testing.py
Normal file
26
tools/binman/etype/_testing.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for testing purposes. Not used in real images.
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
import fdt_util
|
||||
import tools
|
||||
|
||||
class Entry__testing(Entry):
|
||||
def __init__(self, image, etype, node):
|
||||
Entry.__init__(self, image, etype, node)
|
||||
|
||||
def ObtainContents(self):
|
||||
self.data = 'a'
|
||||
self.contents_size = len(self.data)
|
||||
return True
|
||||
|
||||
def ReadContents(self):
|
||||
return True
|
||||
|
||||
def GetPositions(self):
|
||||
return {'invalid-entry': [1, 2]}
|
37
tools/binman/etype/blob.py
Normal file
37
tools/binman/etype/blob.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for blobs, which are binary objects read from files
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
import fdt_util
|
||||
import tools
|
||||
|
||||
class Entry_blob(Entry):
|
||||
def __init__(self, image, etype, node):
|
||||
Entry.__init__(self, image, etype, node)
|
||||
self._filename = fdt_util.GetString(self._node, "filename", self.etype)
|
||||
|
||||
def ObtainContents(self):
|
||||
self._filename = self.GetDefaultFilename()
|
||||
self._pathname = tools.GetInputFilename(self._filename)
|
||||
self.ReadContents()
|
||||
return True
|
||||
|
||||
def ReadContents(self):
|
||||
with open(self._pathname) as fd:
|
||||
# We assume the data is small enough to fit into memory. If this
|
||||
# is used for large filesystem image that might not be true.
|
||||
# In that case, Image.BuildImage() could be adjusted to use a
|
||||
# new Entry method which can read in chunks. Then we could copy
|
||||
# the data in chunks and avoid reading it all at once. For now
|
||||
# this seems like an unnecessary complication.
|
||||
self.data = fd.read()
|
||||
self.contents_size = len(self.data)
|
||||
return True
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return self._filename
|
200
tools/binman/etype/entry.py
Normal file
200
tools/binman/etype/entry.py
Normal file
|
@ -0,0 +1,200 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Base class for all entries
|
||||
#
|
||||
|
||||
# importlib was introduced in Python 2.7 but there was a report of it not
|
||||
# working in 2.7.12, so we work around this:
|
||||
# http://lists.denx.de/pipermail/u-boot/2016-October/269729.html
|
||||
try:
|
||||
import importlib
|
||||
have_importlib = True
|
||||
except:
|
||||
have_importlib = False
|
||||
|
||||
import fdt_util
|
||||
import tools
|
||||
|
||||
modules = {}
|
||||
|
||||
class Entry(object):
|
||||
"""An Entry in the image
|
||||
|
||||
An entry corresponds to a single node in the device-tree description
|
||||
of the image. Each entry ends up being a part of the final image.
|
||||
Entries can be placed either right next to each other, or with padding
|
||||
between them. The type of the entry determines the data that is in it.
|
||||
|
||||
This class is not used by itself. All entry objects are subclasses of
|
||||
Entry.
|
||||
|
||||
Attributes:
|
||||
image: The image containing this entry
|
||||
node: The node that created this entry
|
||||
pos: Absolute position of entry within the image, None if not known
|
||||
size: Entry size in bytes, None if not known
|
||||
contents_size: Size of contents in bytes, 0 by default
|
||||
align: Entry start position alignment, or None
|
||||
align_size: Entry size alignment, or None
|
||||
align_end: Entry end position alignment, or None
|
||||
pad_before: Number of pad bytes before the contents, 0 if none
|
||||
pad_after: Number of pad bytes after the contents, 0 if none
|
||||
data: Contents of entry (string of bytes)
|
||||
"""
|
||||
def __init__(self, image, etype, node, read_node=True):
|
||||
self.image = image
|
||||
self.etype = etype
|
||||
self._node = node
|
||||
self.pos = None
|
||||
self.size = None
|
||||
self.contents_size = 0
|
||||
self.align = None
|
||||
self.align_size = None
|
||||
self.align_end = None
|
||||
self.pad_before = 0
|
||||
self.pad_after = 0
|
||||
self.pos_unset = False
|
||||
if read_node:
|
||||
self.ReadNode()
|
||||
|
||||
@staticmethod
|
||||
def Create(image, node, etype=None):
|
||||
"""Create a new entry for a node.
|
||||
|
||||
Args:
|
||||
image: Image object containing this node
|
||||
node: Node object containing information about the entry to create
|
||||
etype: Entry type to use, or None to work it out (used for tests)
|
||||
|
||||
Returns:
|
||||
A new Entry object of the correct type (a subclass of Entry)
|
||||
"""
|
||||
if not etype:
|
||||
etype = fdt_util.GetString(node, 'type', node.name)
|
||||
module_name = etype.replace('-', '_')
|
||||
module = modules.get(module_name)
|
||||
|
||||
# Import the module if we have not already done so.
|
||||
if not module:
|
||||
try:
|
||||
if have_importlib:
|
||||
module = importlib.import_module(module_name)
|
||||
else:
|
||||
module = __import__(module_name)
|
||||
except ImportError:
|
||||
raise ValueError("Unknown entry type '%s' in node '%s'" %
|
||||
(etype, node.path))
|
||||
modules[module_name] = module
|
||||
|
||||
# Call its constructor to get the object we want.
|
||||
obj = getattr(module, 'Entry_%s' % module_name)
|
||||
return obj(image, etype, node)
|
||||
|
||||
def ReadNode(self):
|
||||
"""Read entry information from the node
|
||||
|
||||
This reads all the fields we recognise from the node, ready for use.
|
||||
"""
|
||||
self.pos = fdt_util.GetInt(self._node, 'pos')
|
||||
self.size = fdt_util.GetInt(self._node, 'size')
|
||||
self.align = fdt_util.GetInt(self._node, 'align')
|
||||
if tools.NotPowerOfTwo(self.align):
|
||||
raise ValueError("Node '%s': Alignment %s must be a power of two" %
|
||||
(self._node.path, self.align))
|
||||
self.pad_before = fdt_util.GetInt(self._node, 'pad-before', 0)
|
||||
self.pad_after = fdt_util.GetInt(self._node, 'pad-after', 0)
|
||||
self.align_size = fdt_util.GetInt(self._node, 'align-size')
|
||||
if tools.NotPowerOfTwo(self.align_size):
|
||||
raise ValueError("Node '%s': Alignment size %s must be a power "
|
||||
"of two" % (self._node.path, self.align_size))
|
||||
self.align_end = fdt_util.GetInt(self._node, 'align-end')
|
||||
self.pos_unset = fdt_util.GetBool(self._node, 'pos-unset')
|
||||
|
||||
def ObtainContents(self):
|
||||
"""Figure out the contents of an entry.
|
||||
|
||||
Returns:
|
||||
True if the contents were found, False if another call is needed
|
||||
after the other entries are processed.
|
||||
"""
|
||||
# No contents by default: subclasses can implement this
|
||||
return True
|
||||
|
||||
def Pack(self, pos):
|
||||
"""Figure out how to pack the entry into the image
|
||||
|
||||
Most of the time the entries are not fully specified. There may be
|
||||
an alignment but no size. In that case we take the size from the
|
||||
contents of the entry.
|
||||
|
||||
If an entry has no hard-coded position, it will be placed at @pos.
|
||||
|
||||
Once this function is complete, both the position and size of the
|
||||
entry will be know.
|
||||
|
||||
Args:
|
||||
Current image position pointer
|
||||
|
||||
Returns:
|
||||
New image position pointer (after this entry)
|
||||
"""
|
||||
if self.pos is None:
|
||||
if self.pos_unset:
|
||||
self.Raise('No position set with pos-unset: should another '
|
||||
'entry provide this correct position?')
|
||||
self.pos = tools.Align(pos, self.align)
|
||||
needed = self.pad_before + self.contents_size + self.pad_after
|
||||
needed = tools.Align(needed, self.align_size)
|
||||
size = self.size
|
||||
if not size:
|
||||
size = needed
|
||||
new_pos = self.pos + size
|
||||
aligned_pos = tools.Align(new_pos, self.align_end)
|
||||
if aligned_pos != new_pos:
|
||||
size = aligned_pos - self.pos
|
||||
new_pos = aligned_pos
|
||||
|
||||
if not self.size:
|
||||
self.size = size
|
||||
|
||||
if self.size < needed:
|
||||
self.Raise("Entry contents size is %#x (%d) but entry size is "
|
||||
"%#x (%d)" % (needed, needed, self.size, self.size))
|
||||
# Check that the alignment is correct. It could be wrong if the
|
||||
# and pos or size values were provided (i.e. not calculated), but
|
||||
# conflict with the provided alignment values
|
||||
if self.size != tools.Align(self.size, self.align_size):
|
||||
self.Raise("Size %#x (%d) does not match align-size %#x (%d)" %
|
||||
(self.size, self.size, self.align_size, self.align_size))
|
||||
if self.pos != tools.Align(self.pos, self.align):
|
||||
self.Raise("Position %#x (%d) does not match align %#x (%d)" %
|
||||
(self.pos, self.pos, self.align, self.align))
|
||||
|
||||
return new_pos
|
||||
|
||||
def Raise(self, msg):
|
||||
"""Convenience function to raise an error referencing a node"""
|
||||
raise ValueError("Node '%s': %s" % (self._node.path, msg))
|
||||
|
||||
def GetPath(self):
|
||||
"""Get the path of a node
|
||||
|
||||
Returns:
|
||||
Full path of the node for this entry
|
||||
"""
|
||||
return self._node.path
|
||||
|
||||
def GetData(self):
|
||||
return self.data
|
||||
|
||||
def GetPositions(self):
|
||||
return {}
|
||||
|
||||
def SetPositionSize(self, pos, size):
|
||||
self.pos = pos
|
||||
self.size = size
|
||||
|
||||
def ProcessContents(self):
|
||||
pass
|
17
tools/binman/etype/intel_cmc.py
Normal file
17
tools/binman/etype/intel_cmc.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for Intel Chip Microcode binary blob
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
|
||||
class Entry_intel_cmc(Entry_blob):
|
||||
def __init__(self, image, etype, node):
|
||||
Entry_blob.__init__(self, image, etype, node)
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'cmc.bin'
|
55
tools/binman/etype/intel_descriptor.py
Normal file
55
tools/binman/etype/intel_descriptor.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for 'u-boot'
|
||||
#
|
||||
|
||||
import struct
|
||||
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
|
||||
FD_SIGNATURE = struct.pack('<L', 0x0ff0a55a)
|
||||
MAX_REGIONS = 5
|
||||
|
||||
(REGION_DESCRIPTOR, REGION_BIOS, REGION_ME, REGION_GBE,
|
||||
REGION_PDATA) = range(5)
|
||||
|
||||
class Region:
|
||||
def __init__(self, data, frba, region_num):
|
||||
pos = frba + region_num * 4
|
||||
val = struct.unpack('<L', data[pos:pos + 4])[0]
|
||||
self.base = (val & 0xfff) << 12
|
||||
self.limit = ((val & 0x0fff0000) >> 4) | 0xfff
|
||||
self.size = self.limit - self.base + 1
|
||||
|
||||
class Entry_intel_descriptor(Entry_blob):
|
||||
"""Intel flash descriptor block (4KB)
|
||||
|
||||
This is placed at the start of flash and provides information about
|
||||
the SPI flash regions. In particular it provides the base address and
|
||||
size of the ME region, allowing us to place the ME binary in the right
|
||||
place.
|
||||
"""
|
||||
def __init__(self, image, etype, node):
|
||||
Entry_blob.__init__(self, image, etype, node)
|
||||
self._regions = []
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'descriptor.bin'
|
||||
|
||||
def GetPositions(self):
|
||||
pos = self.data.find(FD_SIGNATURE)
|
||||
if pos == -1:
|
||||
self.Raise('Cannot find FD signature')
|
||||
flvalsig, flmap0, flmap1, flmap2 = struct.unpack('<LLLL',
|
||||
self.data[pos:pos + 16])
|
||||
frba = ((flmap0 >> 16) & 0xff) << 4
|
||||
for i in range(MAX_REGIONS):
|
||||
self._regions.append(Region(self.data, frba, i))
|
||||
|
||||
# Set the offset for ME only, for now, since the others are not used
|
||||
return {'intel-me': [self._regions[REGION_ME].base,
|
||||
self._regions[REGION_ME].size]}
|
17
tools/binman/etype/intel_fsp.py
Normal file
17
tools/binman/etype/intel_fsp.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for Intel Firmware Support Package binary blob
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
|
||||
class Entry_intel_fsp(Entry_blob):
|
||||
def __init__(self, image, etype, node):
|
||||
Entry_blob.__init__(self, image, etype, node)
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'fsp.bin'
|
17
tools/binman/etype/intel_me.py
Normal file
17
tools/binman/etype/intel_me.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for Intel Management Engine binary blob
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
|
||||
class Entry_intel_me(Entry_blob):
|
||||
def __init__(self, image, etype, node):
|
||||
Entry_blob.__init__(self, image, etype, node)
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'me.bin'
|
17
tools/binman/etype/intel_mrc.py
Normal file
17
tools/binman/etype/intel_mrc.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for Intel Memory Reference Code binary blob
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
|
||||
class Entry_intel_mrc(Entry_blob):
|
||||
def __init__(self, image, etype, node):
|
||||
Entry_blob.__init__(self, image, etype, node)
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'mrc.bin'
|
17
tools/binman/etype/intel_vga.py
Normal file
17
tools/binman/etype/intel_vga.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for x86 VGA ROM binary blob
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
|
||||
class Entry_intel_vga(Entry_blob):
|
||||
def __init__(self, image, etype, node):
|
||||
Entry_blob.__init__(self, image, etype, node)
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'vga.bin'
|
17
tools/binman/etype/u_boot.py
Normal file
17
tools/binman/etype/u_boot.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for U-Boot binary
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
|
||||
class Entry_u_boot(Entry_blob):
|
||||
def __init__(self, image, etype, node):
|
||||
Entry_blob.__init__(self, image, etype, node)
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'u-boot.bin'
|
17
tools/binman/etype/u_boot_dtb.py
Normal file
17
tools/binman/etype/u_boot_dtb.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for U-Boot device tree
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
|
||||
class Entry_u_boot_dtb(Entry_blob):
|
||||
def __init__(self, image, etype, node):
|
||||
Entry_blob.__init__(self, image, etype, node)
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'u-boot.dtb'
|
78
tools/binman/etype/u_boot_dtb_with_ucode.py
Normal file
78
tools/binman/etype/u_boot_dtb_with_ucode.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
## Written by Simon Glass <sjg@chromium.org>
|
||||
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for U-Boot device tree with the microcode removed
|
||||
#
|
||||
|
||||
import fdt_select
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
import tools
|
||||
|
||||
class Entry_u_boot_dtb_with_ucode(Entry_blob):
|
||||
"""A U-Boot device tree file, with the microcode removed
|
||||
|
||||
See Entry_u_boot_ucode for full details of the 3 entries involved in this
|
||||
process.
|
||||
"""
|
||||
def __init__(self, image, etype, node):
|
||||
Entry_blob.__init__(self, image, etype, node)
|
||||
self.ucode_data = ''
|
||||
self.collate = False
|
||||
self.ucode_offset = None
|
||||
self.ucode_size = None
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'u-boot.dtb'
|
||||
|
||||
def ObtainContents(self):
|
||||
Entry_blob.ObtainContents(self)
|
||||
|
||||
# If the image does not need microcode, there is nothing to do
|
||||
ucode_dest_entry = self.image.FindEntryType('u-boot-spl-with-ucode-ptr')
|
||||
if not ucode_dest_entry or not ucode_dest_entry.target_pos:
|
||||
ucode_dest_entry = self.image.FindEntryType('u-boot-with-ucode-ptr')
|
||||
if not ucode_dest_entry or not ucode_dest_entry.target_pos:
|
||||
return True
|
||||
|
||||
# Create a new file to hold the copied device tree
|
||||
dtb_name = 'u-boot-dtb-with-ucode.dtb'
|
||||
fname = tools.GetOutputFilename(dtb_name)
|
||||
with open(fname, 'wb') as fd:
|
||||
fd.write(self.data)
|
||||
|
||||
# Remove the microcode
|
||||
fdt = fdt_select.FdtScan(fname)
|
||||
fdt.Scan()
|
||||
ucode = fdt.GetNode('/microcode')
|
||||
if not ucode:
|
||||
raise self.Raise("No /microcode node found in '%s'" % fname)
|
||||
|
||||
# There's no need to collate it (move all microcode into one place)
|
||||
# if we only have one chunk of microcode.
|
||||
self.collate = len(ucode.subnodes) > 1
|
||||
for node in ucode.subnodes:
|
||||
data_prop = node.props.get('data')
|
||||
if data_prop:
|
||||
self.ucode_data += ''.join(data_prop.bytes)
|
||||
if not self.collate:
|
||||
poffset = data_prop.GetOffset()
|
||||
if poffset is None:
|
||||
# We cannot obtain a property offset. Collate instead.
|
||||
self.collate = True
|
||||
else:
|
||||
# Find the offset in the device tree of the ucode data
|
||||
self.ucode_offset = poffset + 12
|
||||
self.ucode_size = len(data_prop.bytes)
|
||||
if self.collate:
|
||||
prop = node.DeleteProp('data')
|
||||
if self.collate:
|
||||
fdt.Pack()
|
||||
fdt.Flush()
|
||||
|
||||
# Make this file the contents of this entry
|
||||
self._pathname = fname
|
||||
self.ReadContents()
|
||||
return True
|
17
tools/binman/etype/u_boot_img.py
Normal file
17
tools/binman/etype/u_boot_img.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for U-Boot binary
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
|
||||
class Entry_u_boot_img(Entry_blob):
|
||||
def __init__(self, image, etype, node):
|
||||
Entry_blob.__init__(self, image, etype, node)
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'u-boot.img'
|
17
tools/binman/etype/u_boot_nodtb.py
Normal file
17
tools/binman/etype/u_boot_nodtb.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for 'u-boot-nodtb.bin'
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
|
||||
class Entry_u_boot_nodtb(Entry_blob):
|
||||
def __init__(self, image, etype, node):
|
||||
Entry_blob.__init__(self, image, etype, node)
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'u-boot-nodtb.bin'
|
17
tools/binman/etype/u_boot_spl.py
Normal file
17
tools/binman/etype/u_boot_spl.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for spl/u-boot-spl.bin
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
|
||||
class Entry_u_boot_spl(Entry_blob):
|
||||
def __init__(self, image, etype, node):
|
||||
Entry_blob.__init__(self, image, etype, node)
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'spl/u-boot-spl.bin'
|
26
tools/binman/etype/u_boot_spl_bss_pad.py
Normal file
26
tools/binman/etype/u_boot_spl_bss_pad.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for BSS padding for spl/u-boot-spl.bin. This padding
|
||||
# can be added after the SPL binary to ensure that anything concatenated
|
||||
# to it will appear to SPL to be at the end of BSS rather than the start.
|
||||
#
|
||||
|
||||
import command
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
import tools
|
||||
|
||||
class Entry_u_boot_spl_bss_pad(Entry_blob):
|
||||
def __init__(self, image, etype, node):
|
||||
Entry_blob.__init__(self, image, etype, node)
|
||||
|
||||
def ObtainContents(self):
|
||||
fname = tools.GetInputFilename('spl/u-boot-spl')
|
||||
args = [['nm', fname], ['grep', '__bss_size']]
|
||||
out = command.RunPipe(args, capture=True).stdout.splitlines()
|
||||
bss_size = int(out[0].split()[0], 16)
|
||||
self.data = chr(0) * bss_size
|
||||
self.contents_size = bss_size
|
28
tools/binman/etype/u_boot_spl_with_ucode_ptr.py
Normal file
28
tools/binman/etype/u_boot_spl_with_ucode_ptr.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for an SPL binary with an embedded microcode pointer
|
||||
#
|
||||
|
||||
import struct
|
||||
|
||||
import command
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
from u_boot_with_ucode_ptr import Entry_u_boot_with_ucode_ptr
|
||||
import tools
|
||||
|
||||
class Entry_u_boot_spl_with_ucode_ptr(Entry_u_boot_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.
|
||||
"""
|
||||
def __init__(self, image, etype, node):
|
||||
Entry_blob.__init__(self, image, etype, node)
|
||||
self.elf_fname = 'spl/u-boot-spl'
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'spl/u-boot-spl.bin'
|
84
tools/binman/etype/u_boot_ucode.py
Normal file
84
tools/binman/etype/u_boot_ucode.py
Normal file
|
@ -0,0 +1,84 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for a U-Boot binary with an embedded microcode pointer
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
import tools
|
||||
|
||||
class Entry_u_boot_ucode(Entry_blob):
|
||||
"""U-Boot microcode block
|
||||
|
||||
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.
|
||||
"""
|
||||
def __init__(self, image, etype, node):
|
||||
Entry_blob.__init__(self, image, etype, node)
|
||||
|
||||
def ObtainContents(self):
|
||||
# If the image does not need microcode, there is nothing to do
|
||||
ucode_dest_entry = self.image.FindEntryType('u-boot-with-ucode-ptr')
|
||||
if ucode_dest_entry and not ucode_dest_entry.target_pos:
|
||||
self.data = ''
|
||||
return True
|
||||
|
||||
# Get the microcode from the device tree entry
|
||||
fdt_entry = self.image.FindEntryType('u-boot-dtb-with-ucode')
|
||||
if not fdt_entry or not fdt_entry.ucode_data:
|
||||
return False
|
||||
|
||||
if not fdt_entry.collate:
|
||||
# This section can be empty
|
||||
self.data = ''
|
||||
return True
|
||||
|
||||
# Write it out to a file
|
||||
dtb_name = 'u-boot-ucode.bin'
|
||||
fname = tools.GetOutputFilename(dtb_name)
|
||||
with open(fname, 'wb') as fd:
|
||||
fd.write(fdt_entry.ucode_data)
|
||||
|
||||
self._pathname = fname
|
||||
self.ReadContents()
|
||||
|
||||
return True
|
87
tools/binman/etype/u_boot_with_ucode_ptr.py
Normal file
87
tools/binman/etype/u_boot_with_ucode_ptr.py
Normal file
|
@ -0,0 +1,87 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for a U-Boot binary with an embedded microcode pointer
|
||||
#
|
||||
|
||||
import struct
|
||||
|
||||
import command
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
import fdt_util
|
||||
import tools
|
||||
|
||||
class Entry_u_boot_with_ucode_ptr(Entry_blob):
|
||||
"""U-Boot with embedded microcode pointer
|
||||
|
||||
See Entry_u_boot_ucode for full details of the 3 entries involved in this
|
||||
process.
|
||||
"""
|
||||
def __init__(self, image, etype, node):
|
||||
Entry_blob.__init__(self, image, etype, node)
|
||||
self.elf_fname = 'u-boot'
|
||||
self.target_pos = None
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'u-boot-nodtb.bin'
|
||||
|
||||
def ObtainContents(self):
|
||||
# Figure out where to put the microcode pointer
|
||||
fname = tools.GetInputFilename(self.elf_fname)
|
||||
args = [['nm', fname], ['grep', '-w', '_dt_ucode_base_size']]
|
||||
out = (command.RunPipe(args, capture=True, raise_on_error=False).
|
||||
stdout.splitlines())
|
||||
if len(out) == 1:
|
||||
self.target_pos = int(out[0].split()[0], 16)
|
||||
elif not fdt_util.GetBool(self._node, 'optional-ucode'):
|
||||
self.Raise('Cannot locate _dt_ucode_base_size symbol in u-boot')
|
||||
|
||||
return Entry_blob.ObtainContents(self)
|
||||
|
||||
def ProcessContents(self):
|
||||
# If the image does not need microcode, there is nothing to do
|
||||
if not self.target_pos:
|
||||
return
|
||||
|
||||
# Get the position of the microcode
|
||||
ucode_entry = self.image.FindEntryType('u-boot-ucode')
|
||||
if not ucode_entry:
|
||||
self.Raise('Cannot find microcode region u-boot-ucode')
|
||||
|
||||
# Check the target pos is in the image. If it is not, then U-Boot is
|
||||
# being linked incorrectly, or is being placed at the wrong position
|
||||
# in the image.
|
||||
#
|
||||
# The image must be set up so that U-Boot is placed at the
|
||||
# flash address to which it is linked. For example, if
|
||||
# CONFIG_SYS_TEXT_BASE is 0xfff00000, and the ROM is 8MB, then
|
||||
# the U-Boot region must start at position 7MB in the image. In this
|
||||
# case the ROM starts at 0xff800000, so the position of the first
|
||||
# entry in the image corresponds to that.
|
||||
if (self.target_pos < self.pos or
|
||||
self.target_pos >= self.pos + self.size):
|
||||
self.Raise('Microcode pointer _dt_ucode_base_size at %08x is '
|
||||
'outside the image ranging from %08x to %08x' %
|
||||
(self.target_pos, self.pos, self.pos + self.size))
|
||||
|
||||
# Get the microcode, either from u-boot-ucode or u-boot-dtb-with-ucode.
|
||||
# If we have left the microcode in the device tree, then it will be
|
||||
# in the former. If we extracted the microcode from the device tree
|
||||
# and collated it in one place, it will be in the latter.
|
||||
if ucode_entry.size:
|
||||
pos, size = ucode_entry.pos, ucode_entry.size
|
||||
else:
|
||||
dtb_entry = self.image.FindEntryType('u-boot-dtb-with-ucode')
|
||||
if not dtb_entry:
|
||||
self.Raise('Cannot find microcode region u-boot-dtb-with-ucode')
|
||||
pos = dtb_entry.pos + dtb_entry.ucode_offset
|
||||
size = dtb_entry.ucode_size
|
||||
|
||||
# Write the microcode position and size into the entry
|
||||
pos_and_size = struct.pack('<2L', pos, size)
|
||||
self.target_pos -= self.pos
|
||||
self.data = (self.data[:self.target_pos] + pos_and_size +
|
||||
self.data[self.target_pos + 8:])
|
17
tools/binman/etype/x86_start16.py
Normal file
17
tools/binman/etype/x86_start16.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for the 16-bit x86 start-up code for U-Boot
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
|
||||
class Entry_x86_start16(Entry_blob):
|
||||
def __init__(self, image, etype, node):
|
||||
Entry_blob.__init__(self, image, etype, node)
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'u-boot-x86-16bit.bin'
|
17
tools/binman/etype/x86_start16_spl.py
Normal file
17
tools/binman/etype/x86_start16_spl.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Entry-type module for the 16-bit x86 start-up code for U-Boot SPL
|
||||
#
|
||||
|
||||
from entry import Entry
|
||||
from blob import Entry_blob
|
||||
|
||||
class Entry_x86_start16_spl(Entry_blob):
|
||||
def __init__(self, image, etype, node):
|
||||
Entry_blob.__init__(self, image, etype, node)
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'spl/u-boot-x86-16bit-spl.bin'
|
48
tools/binman/fdt_test.py
Normal file
48
tools/binman/fdt_test.py
Normal file
|
@ -0,0 +1,48 @@
|
|||
#
|
||||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Test for the fdt modules
|
||||
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
from fdt_select import FdtScan
|
||||
import fdt_util
|
||||
import tools
|
||||
|
||||
class TestFdt(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
|
||||
self._indir = tempfile.mkdtemp(prefix='binmant.')
|
||||
tools.PrepareOutputDir(self._indir, True)
|
||||
|
||||
def TestFile(self, fname):
|
||||
return os.path.join(self._binman_dir, 'test', fname)
|
||||
|
||||
def GetCompiled(self, fname):
|
||||
return fdt_util.EnsureCompiled(self.TestFile(fname))
|
||||
|
||||
def _DeleteProp(self, fdt):
|
||||
node = fdt.GetNode('/microcode/update@0')
|
||||
node.DeleteProp('data')
|
||||
|
||||
def testFdtNormal(self):
|
||||
fname = self.GetCompiled('34_x86_ucode.dts')
|
||||
fdt = FdtScan(fname)
|
||||
self._DeleteProp(fdt)
|
||||
|
||||
def testFdtFallback(self):
|
||||
fname = self.GetCompiled('34_x86_ucode.dts')
|
||||
fdt = FdtScan(fname, True)
|
||||
fdt.GetProp('/microcode/update@0', 'data')
|
||||
self.assertEqual('fred',
|
||||
fdt.GetProp('/microcode/update@0', 'none', default='fred'))
|
||||
self.assertEqual('12345678 12345679',
|
||||
fdt.GetProp('/microcode/update@0', 'data', typespec='x'))
|
||||
self._DeleteProp(fdt)
|
822
tools/binman/func_test.py
Normal file
822
tools/binman/func_test.py
Normal file
|
@ -0,0 +1,822 @@
|
|||
#
|
||||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# To run a single test, change to this directory, and:
|
||||
#
|
||||
# python -m unittest func_test.TestFunctional.testHelp
|
||||
|
||||
from optparse import OptionParser
|
||||
import os
|
||||
import shutil
|
||||
import struct
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
import binman
|
||||
import cmdline
|
||||
import command
|
||||
import control
|
||||
import entry
|
||||
import fdt_select
|
||||
import fdt_util
|
||||
import tools
|
||||
import tout
|
||||
|
||||
# Contents of test files, corresponding to different entry types
|
||||
U_BOOT_DATA = '1234'
|
||||
U_BOOT_IMG_DATA = 'img'
|
||||
U_BOOT_SPL_DATA = '567'
|
||||
BLOB_DATA = '89'
|
||||
ME_DATA = '0abcd'
|
||||
VGA_DATA = 'vga'
|
||||
U_BOOT_DTB_DATA = 'udtb'
|
||||
X86_START16_DATA = 'start16'
|
||||
U_BOOT_NODTB_DATA = 'nodtb with microcode pointer somewhere in here'
|
||||
FSP_DATA = 'fsp'
|
||||
CMC_DATA = 'cmc'
|
||||
|
||||
class TestFunctional(unittest.TestCase):
|
||||
"""Functional tests for binman
|
||||
|
||||
Most of these use a sample .dts file to build an image and then check
|
||||
that it looks correct. The sample files are in the test/ subdirectory
|
||||
and are numbered.
|
||||
|
||||
For each entry type a very small test file is created using fixed
|
||||
string contents. This makes it easy to test that things look right, and
|
||||
debug problems.
|
||||
|
||||
In some cases a 'real' file must be used - these are also supplied in
|
||||
the test/ diurectory.
|
||||
"""
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
# Handle the case where argv[0] is 'python'
|
||||
self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
|
||||
self._binman_pathname = os.path.join(self._binman_dir, 'binman')
|
||||
|
||||
# Create a temporary directory for input files
|
||||
self._indir = tempfile.mkdtemp(prefix='binmant.')
|
||||
|
||||
# Create some test files
|
||||
TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
|
||||
TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
|
||||
TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
|
||||
TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
|
||||
TestFunctional._MakeInputFile('me.bin', ME_DATA)
|
||||
TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
|
||||
TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
|
||||
TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
|
||||
TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
|
||||
TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
|
||||
TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
|
||||
self._output_setup = False
|
||||
|
||||
# ELF file with a '_dt_ucode_base_size' symbol
|
||||
with open(self.TestFile('u_boot_ucode_ptr')) as fd:
|
||||
TestFunctional._MakeInputFile('u-boot', fd.read())
|
||||
|
||||
# Intel flash descriptor file
|
||||
with open(self.TestFile('descriptor.bin')) as fd:
|
||||
TestFunctional._MakeInputFile('descriptor.bin', fd.read())
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(self):
|
||||
"""Remove the temporary input directory and its contents"""
|
||||
if self._indir:
|
||||
shutil.rmtree(self._indir)
|
||||
self._indir = None
|
||||
|
||||
def setUp(self):
|
||||
# Enable this to turn on debugging output
|
||||
# tout.Init(tout.DEBUG)
|
||||
command.test_result = None
|
||||
|
||||
def tearDown(self):
|
||||
"""Remove the temporary output directory"""
|
||||
tools._FinaliseForTest()
|
||||
|
||||
def _RunBinman(self, *args, **kwargs):
|
||||
"""Run binman using the command line
|
||||
|
||||
Args:
|
||||
Arguments to pass, as a list of strings
|
||||
kwargs: Arguments to pass to Command.RunPipe()
|
||||
"""
|
||||
result = command.RunPipe([[self._binman_pathname] + list(args)],
|
||||
capture=True, capture_stderr=True, raise_on_error=False)
|
||||
if result.return_code and kwargs.get('raise_on_error', True):
|
||||
raise Exception("Error running '%s': %s" % (' '.join(args),
|
||||
result.stdout + result.stderr))
|
||||
return result
|
||||
|
||||
def _DoBinman(self, *args):
|
||||
"""Run binman using directly (in the same process)
|
||||
|
||||
Args:
|
||||
Arguments to pass, as a list of strings
|
||||
Returns:
|
||||
Return value (0 for success)
|
||||
"""
|
||||
(options, args) = cmdline.ParseArgs(list(args))
|
||||
options.pager = 'binman-invalid-pager'
|
||||
options.build_dir = self._indir
|
||||
|
||||
# For testing, you can force an increase in verbosity here
|
||||
# options.verbosity = tout.DEBUG
|
||||
return control.Binman(options, args)
|
||||
|
||||
def _DoTestFile(self, fname):
|
||||
"""Run binman with a given test file
|
||||
|
||||
Args:
|
||||
fname: Device tree source filename to use (e.g. 05_simple.dts)
|
||||
"""
|
||||
return self._DoBinman('-p', '-I', self._indir,
|
||||
'-d', self.TestFile(fname))
|
||||
|
||||
def _SetupDtb(self, fname, outfile='u-boot.dtb'):
|
||||
"""Set up a new test device-tree file
|
||||
|
||||
The given file is compiled and set up as the device tree to be used
|
||||
for ths test.
|
||||
|
||||
Args:
|
||||
fname: Filename of .dts file to read
|
||||
outfile: Output filename for compiled device tree binary
|
||||
|
||||
Returns:
|
||||
Contents of device tree binary
|
||||
"""
|
||||
if not self._output_setup:
|
||||
tools.PrepareOutputDir(self._indir, True)
|
||||
self._output_setup = True
|
||||
dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
|
||||
with open(dtb) as fd:
|
||||
data = fd.read()
|
||||
TestFunctional._MakeInputFile(outfile, data)
|
||||
return data
|
||||
|
||||
def _DoReadFileDtb(self, fname, use_real_dtb=False):
|
||||
"""Run binman and return the resulting image
|
||||
|
||||
This runs binman with a given test file and then reads the resulting
|
||||
output file. It is a shortcut function since most tests need to do
|
||||
these steps.
|
||||
|
||||
Raises an assertion failure if binman returns a non-zero exit code.
|
||||
|
||||
Args:
|
||||
fname: Device tree source filename to use (e.g. 05_simple.dts)
|
||||
use_real_dtb: True to use the test file as the contents of
|
||||
the u-boot-dtb entry. Normally this is not needed and the
|
||||
test contents (the U_BOOT_DTB_DATA string) can be used.
|
||||
But in some test we need the real contents.
|
||||
|
||||
Returns:
|
||||
Tuple:
|
||||
Resulting image contents
|
||||
Device tree contents
|
||||
"""
|
||||
dtb_data = None
|
||||
# Use the compiled test file as the u-boot-dtb input
|
||||
if use_real_dtb:
|
||||
dtb_data = self._SetupDtb(fname)
|
||||
|
||||
try:
|
||||
retcode = self._DoTestFile(fname)
|
||||
self.assertEqual(0, retcode)
|
||||
|
||||
# Find the (only) image, read it and return its contents
|
||||
image = control.images['image']
|
||||
fname = tools.GetOutputFilename('image.bin')
|
||||
self.assertTrue(os.path.exists(fname))
|
||||
with open(fname) as fd:
|
||||
return fd.read(), dtb_data
|
||||
finally:
|
||||
# Put the test file back
|
||||
if use_real_dtb:
|
||||
TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
|
||||
|
||||
def _DoReadFile(self, fname, use_real_dtb=False):
|
||||
"""Helper function which discards the device-tree binary"""
|
||||
return self._DoReadFileDtb(fname, use_real_dtb)[0]
|
||||
|
||||
@classmethod
|
||||
def _MakeInputFile(self, fname, contents):
|
||||
"""Create a new test input file, creating directories as needed
|
||||
|
||||
Args:
|
||||
fname: Filenaem to create
|
||||
contents: File contents to write in to the file
|
||||
Returns:
|
||||
Full pathname of file created
|
||||
"""
|
||||
pathname = os.path.join(self._indir, fname)
|
||||
dirname = os.path.dirname(pathname)
|
||||
if dirname and not os.path.exists(dirname):
|
||||
os.makedirs(dirname)
|
||||
with open(pathname, 'wb') as fd:
|
||||
fd.write(contents)
|
||||
return pathname
|
||||
|
||||
@classmethod
|
||||
def TestFile(self, fname):
|
||||
return os.path.join(self._binman_dir, 'test', fname)
|
||||
|
||||
def AssertInList(self, grep_list, target):
|
||||
"""Assert that at least one of a list of things is in a target
|
||||
|
||||
Args:
|
||||
grep_list: List of strings to check
|
||||
target: Target string
|
||||
"""
|
||||
for grep in grep_list:
|
||||
if grep in target:
|
||||
return
|
||||
self.fail("Error: '%' not found in '%s'" % (grep_list, target))
|
||||
|
||||
def CheckNoGaps(self, entries):
|
||||
"""Check that all entries fit together without gaps
|
||||
|
||||
Args:
|
||||
entries: List of entries to check
|
||||
"""
|
||||
pos = 0
|
||||
for entry in entries.values():
|
||||
self.assertEqual(pos, entry.pos)
|
||||
pos += entry.size
|
||||
|
||||
def GetFdtLen(self, dtb):
|
||||
"""Get the totalsize field from a device tree binary
|
||||
|
||||
Args:
|
||||
dtb: Device tree binary contents
|
||||
|
||||
Returns:
|
||||
Total size of device tree binary, from the header
|
||||
"""
|
||||
return struct.unpack('>L', dtb[4:8])[0]
|
||||
|
||||
def testRun(self):
|
||||
"""Test a basic run with valid args"""
|
||||
result = self._RunBinman('-h')
|
||||
|
||||
def testFullHelp(self):
|
||||
"""Test that the full help is displayed with -H"""
|
||||
result = self._RunBinman('-H')
|
||||
help_file = os.path.join(self._binman_dir, 'README')
|
||||
self.assertEqual(len(result.stdout), os.path.getsize(help_file))
|
||||
self.assertEqual(0, len(result.stderr))
|
||||
self.assertEqual(0, result.return_code)
|
||||
|
||||
def testFullHelpInternal(self):
|
||||
"""Test that the full help is displayed with -H"""
|
||||
try:
|
||||
command.test_result = command.CommandResult()
|
||||
result = self._DoBinman('-H')
|
||||
help_file = os.path.join(self._binman_dir, 'README')
|
||||
finally:
|
||||
command.test_result = None
|
||||
|
||||
def testHelp(self):
|
||||
"""Test that the basic help is displayed with -h"""
|
||||
result = self._RunBinman('-h')
|
||||
self.assertTrue(len(result.stdout) > 200)
|
||||
self.assertEqual(0, len(result.stderr))
|
||||
self.assertEqual(0, result.return_code)
|
||||
|
||||
# Not yet available.
|
||||
def testBoard(self):
|
||||
"""Test that we can run it with a specific board"""
|
||||
self._SetupDtb('05_simple.dts', 'sandbox/u-boot.dtb')
|
||||
TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
|
||||
result = self._DoBinman('-b', 'sandbox')
|
||||
self.assertEqual(0, result)
|
||||
|
||||
def testNeedBoard(self):
|
||||
"""Test that we get an error when no board ius supplied"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
result = self._DoBinman()
|
||||
self.assertIn("Must provide a board to process (use -b <board>)",
|
||||
str(e.exception))
|
||||
|
||||
def testMissingDt(self):
|
||||
"""Test that an invalid device tree file generates an error"""
|
||||
with self.assertRaises(Exception) as e:
|
||||
self._RunBinman('-d', 'missing_file')
|
||||
# We get one error from libfdt, and a different one from fdtget.
|
||||
self.AssertInList(["Couldn't open blob from 'missing_file'",
|
||||
'No such file or directory'], str(e.exception))
|
||||
|
||||
def testBrokenDt(self):
|
||||
"""Test that an invalid device tree source file generates an error
|
||||
|
||||
Since this is a source file it should be compiled and the error
|
||||
will come from the device-tree compiler (dtc).
|
||||
"""
|
||||
with self.assertRaises(Exception) as e:
|
||||
self._RunBinman('-d', self.TestFile('01_invalid.dts'))
|
||||
self.assertIn("FATAL ERROR: Unable to parse input tree",
|
||||
str(e.exception))
|
||||
|
||||
def testMissingNode(self):
|
||||
"""Test that a device tree without a 'binman' node generates an error"""
|
||||
with self.assertRaises(Exception) as e:
|
||||
self._DoBinman('-d', self.TestFile('02_missing_node.dts'))
|
||||
self.assertIn("does not have a 'binman' node", str(e.exception))
|
||||
|
||||
def testEmpty(self):
|
||||
"""Test that an empty binman node works OK (i.e. does nothing)"""
|
||||
result = self._RunBinman('-d', self.TestFile('03_empty.dts'))
|
||||
self.assertEqual(0, len(result.stderr))
|
||||
self.assertEqual(0, result.return_code)
|
||||
|
||||
def testInvalidEntry(self):
|
||||
"""Test that an invalid entry is flagged"""
|
||||
with self.assertRaises(Exception) as e:
|
||||
result = self._RunBinman('-d',
|
||||
self.TestFile('04_invalid_entry.dts'))
|
||||
#print e.exception
|
||||
self.assertIn("Unknown entry type 'not-a-valid-type' in node "
|
||||
"'/binman/not-a-valid-type'", str(e.exception))
|
||||
|
||||
def testSimple(self):
|
||||
"""Test a simple binman with a single file"""
|
||||
data = self._DoReadFile('05_simple.dts')
|
||||
self.assertEqual(U_BOOT_DATA, data)
|
||||
|
||||
def testDual(self):
|
||||
"""Test that we can handle creating two images
|
||||
|
||||
This also tests image padding.
|
||||
"""
|
||||
retcode = self._DoTestFile('06_dual_image.dts')
|
||||
self.assertEqual(0, retcode)
|
||||
|
||||
image = control.images['image1']
|
||||
self.assertEqual(len(U_BOOT_DATA), image._size)
|
||||
fname = tools.GetOutputFilename('image1.bin')
|
||||
self.assertTrue(os.path.exists(fname))
|
||||
with open(fname) as fd:
|
||||
data = fd.read()
|
||||
self.assertEqual(U_BOOT_DATA, data)
|
||||
|
||||
image = control.images['image2']
|
||||
self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
|
||||
fname = tools.GetOutputFilename('image2.bin')
|
||||
self.assertTrue(os.path.exists(fname))
|
||||
with open(fname) as fd:
|
||||
data = fd.read()
|
||||
self.assertEqual(U_BOOT_DATA, data[3:7])
|
||||
self.assertEqual(chr(0) * 3, data[:3])
|
||||
self.assertEqual(chr(0) * 5, data[7:])
|
||||
|
||||
def testBadAlign(self):
|
||||
"""Test that an invalid alignment value is detected"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('07_bad_align.dts')
|
||||
self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
|
||||
"of two", str(e.exception))
|
||||
|
||||
def testPackSimple(self):
|
||||
"""Test that packing works as expected"""
|
||||
retcode = self._DoTestFile('08_pack.dts')
|
||||
self.assertEqual(0, retcode)
|
||||
self.assertIn('image', control.images)
|
||||
image = control.images['image']
|
||||
entries = image._entries
|
||||
self.assertEqual(5, len(entries))
|
||||
|
||||
# First u-boot
|
||||
self.assertIn('u-boot', entries)
|
||||
entry = entries['u-boot']
|
||||
self.assertEqual(0, entry.pos)
|
||||
self.assertEqual(len(U_BOOT_DATA), entry.size)
|
||||
|
||||
# Second u-boot, aligned to 16-byte boundary
|
||||
self.assertIn('u-boot-align', entries)
|
||||
entry = entries['u-boot-align']
|
||||
self.assertEqual(16, entry.pos)
|
||||
self.assertEqual(len(U_BOOT_DATA), entry.size)
|
||||
|
||||
# Third u-boot, size 23 bytes
|
||||
self.assertIn('u-boot-size', entries)
|
||||
entry = entries['u-boot-size']
|
||||
self.assertEqual(20, entry.pos)
|
||||
self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
|
||||
self.assertEqual(23, entry.size)
|
||||
|
||||
# Fourth u-boot, placed immediate after the above
|
||||
self.assertIn('u-boot-next', entries)
|
||||
entry = entries['u-boot-next']
|
||||
self.assertEqual(43, entry.pos)
|
||||
self.assertEqual(len(U_BOOT_DATA), entry.size)
|
||||
|
||||
# Fifth u-boot, placed at a fixed position
|
||||
self.assertIn('u-boot-fixed', entries)
|
||||
entry = entries['u-boot-fixed']
|
||||
self.assertEqual(61, entry.pos)
|
||||
self.assertEqual(len(U_BOOT_DATA), entry.size)
|
||||
|
||||
self.assertEqual(65, image._size)
|
||||
|
||||
def testPackExtra(self):
|
||||
"""Test that extra packing feature works as expected"""
|
||||
retcode = self._DoTestFile('09_pack_extra.dts')
|
||||
|
||||
self.assertEqual(0, retcode)
|
||||
self.assertIn('image', control.images)
|
||||
image = control.images['image']
|
||||
entries = image._entries
|
||||
self.assertEqual(5, len(entries))
|
||||
|
||||
# First u-boot with padding before and after
|
||||
self.assertIn('u-boot', entries)
|
||||
entry = entries['u-boot']
|
||||
self.assertEqual(0, entry.pos)
|
||||
self.assertEqual(3, entry.pad_before)
|
||||
self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
|
||||
|
||||
# Second u-boot has an aligned size, but it has no effect
|
||||
self.assertIn('u-boot-align-size-nop', entries)
|
||||
entry = entries['u-boot-align-size-nop']
|
||||
self.assertEqual(12, entry.pos)
|
||||
self.assertEqual(4, entry.size)
|
||||
|
||||
# Third u-boot has an aligned size too
|
||||
self.assertIn('u-boot-align-size', entries)
|
||||
entry = entries['u-boot-align-size']
|
||||
self.assertEqual(16, entry.pos)
|
||||
self.assertEqual(32, entry.size)
|
||||
|
||||
# Fourth u-boot has an aligned end
|
||||
self.assertIn('u-boot-align-end', entries)
|
||||
entry = entries['u-boot-align-end']
|
||||
self.assertEqual(48, entry.pos)
|
||||
self.assertEqual(16, entry.size)
|
||||
|
||||
# Fifth u-boot immediately afterwards
|
||||
self.assertIn('u-boot-align-both', entries)
|
||||
entry = entries['u-boot-align-both']
|
||||
self.assertEqual(64, entry.pos)
|
||||
self.assertEqual(64, entry.size)
|
||||
|
||||
self.CheckNoGaps(entries)
|
||||
self.assertEqual(128, image._size)
|
||||
|
||||
def testPackAlignPowerOf2(self):
|
||||
"""Test that invalid entry alignment is detected"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('10_pack_align_power2.dts')
|
||||
self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
|
||||
"of two", str(e.exception))
|
||||
|
||||
def testPackAlignSizePowerOf2(self):
|
||||
"""Test that invalid entry size alignment is detected"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('11_pack_align_size_power2.dts')
|
||||
self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
|
||||
"power of two", str(e.exception))
|
||||
|
||||
def testPackInvalidAlign(self):
|
||||
"""Test detection of an position that does not match its alignment"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('12_pack_inv_align.dts')
|
||||
self.assertIn("Node '/binman/u-boot': Position 0x5 (5) does not match "
|
||||
"align 0x4 (4)", str(e.exception))
|
||||
|
||||
def testPackInvalidSizeAlign(self):
|
||||
"""Test that invalid entry size alignment is detected"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('13_pack_inv_size_align.dts')
|
||||
self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
|
||||
"align-size 0x4 (4)", str(e.exception))
|
||||
|
||||
def testPackOverlap(self):
|
||||
"""Test that overlapping regions are detected"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('14_pack_overlap.dts')
|
||||
self.assertIn("Node '/binman/u-boot-align': Position 0x3 (3) overlaps "
|
||||
"with previous entry '/binman/u-boot' ending at 0x4 (4)",
|
||||
str(e.exception))
|
||||
|
||||
def testPackEntryOverflow(self):
|
||||
"""Test that entries that overflow their size are detected"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('15_pack_overflow.dts')
|
||||
self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
|
||||
"but entry size is 0x3 (3)", str(e.exception))
|
||||
|
||||
def testPackImageOverflow(self):
|
||||
"""Test that entries which overflow the image size are detected"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('16_pack_image_overflow.dts')
|
||||
self.assertIn("Image '/binman': contents size 0x4 (4) exceeds image "
|
||||
"size 0x3 (3)", str(e.exception))
|
||||
|
||||
def testPackImageSize(self):
|
||||
"""Test that the image size can be set"""
|
||||
retcode = self._DoTestFile('17_pack_image_size.dts')
|
||||
self.assertEqual(0, retcode)
|
||||
self.assertIn('image', control.images)
|
||||
image = control.images['image']
|
||||
self.assertEqual(7, image._size)
|
||||
|
||||
def testPackImageSizeAlign(self):
|
||||
"""Test that image size alignemnt works as expected"""
|
||||
retcode = self._DoTestFile('18_pack_image_align.dts')
|
||||
self.assertEqual(0, retcode)
|
||||
self.assertIn('image', control.images)
|
||||
image = control.images['image']
|
||||
self.assertEqual(16, image._size)
|
||||
|
||||
def testPackInvalidImageAlign(self):
|
||||
"""Test that invalid image alignment is detected"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('19_pack_inv_image_align.dts')
|
||||
self.assertIn("Image '/binman': Size 0x7 (7) does not match "
|
||||
"align-size 0x8 (8)", str(e.exception))
|
||||
|
||||
def testPackAlignPowerOf2(self):
|
||||
"""Test that invalid image alignment is detected"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('20_pack_inv_image_align_power2.dts')
|
||||
self.assertIn("Image '/binman': Alignment size 131 must be a power of "
|
||||
"two", str(e.exception))
|
||||
|
||||
def testImagePadByte(self):
|
||||
"""Test that the image pad byte can be specified"""
|
||||
data = self._DoReadFile('21_image_pad.dts')
|
||||
self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 9) + U_BOOT_DATA, data)
|
||||
|
||||
def testImageName(self):
|
||||
"""Test that image files can be named"""
|
||||
retcode = self._DoTestFile('22_image_name.dts')
|
||||
self.assertEqual(0, retcode)
|
||||
image = control.images['image1']
|
||||
fname = tools.GetOutputFilename('test-name')
|
||||
self.assertTrue(os.path.exists(fname))
|
||||
|
||||
image = control.images['image2']
|
||||
fname = tools.GetOutputFilename('test-name.xx')
|
||||
self.assertTrue(os.path.exists(fname))
|
||||
|
||||
def testBlobFilename(self):
|
||||
"""Test that generic blobs can be provided by filename"""
|
||||
data = self._DoReadFile('23_blob.dts')
|
||||
self.assertEqual(BLOB_DATA, data)
|
||||
|
||||
def testPackSorted(self):
|
||||
"""Test that entries can be sorted"""
|
||||
data = self._DoReadFile('24_sorted.dts')
|
||||
self.assertEqual(chr(0) * 5 + U_BOOT_SPL_DATA + chr(0) * 2 +
|
||||
U_BOOT_DATA, data)
|
||||
|
||||
def testPackZeroPosition(self):
|
||||
"""Test that an entry at position 0 is not given a new position"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('25_pack_zero_size.dts')
|
||||
self.assertIn("Node '/binman/u-boot-spl': Position 0x0 (0) overlaps "
|
||||
"with previous entry '/binman/u-boot' ending at 0x4 (4)",
|
||||
str(e.exception))
|
||||
|
||||
def testPackUbootDtb(self):
|
||||
"""Test that a device tree can be added to U-Boot"""
|
||||
data = self._DoReadFile('26_pack_u_boot_dtb.dts')
|
||||
self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
|
||||
|
||||
def testPackX86RomNoSize(self):
|
||||
"""Test that the end-at-4gb property requires a size property"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('27_pack_4gb_no_size.dts')
|
||||
self.assertIn("Image '/binman': Image size must be provided when "
|
||||
"using end-at-4gb", str(e.exception))
|
||||
|
||||
def testPackX86RomOutside(self):
|
||||
"""Test that the end-at-4gb property checks for position boundaries"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('28_pack_4gb_outside.dts')
|
||||
self.assertIn("Node '/binman/u-boot': Position 0x0 (0) is outside "
|
||||
"the image starting at 0xfffffff0 (4294967280)",
|
||||
str(e.exception))
|
||||
|
||||
def testPackX86Rom(self):
|
||||
"""Test that a basic x86 ROM can be created"""
|
||||
data = self._DoReadFile('29_x86-rom.dts')
|
||||
self.assertEqual(U_BOOT_DATA + chr(0) * 3 + U_BOOT_SPL_DATA +
|
||||
chr(0) * 6, data)
|
||||
|
||||
def testPackX86RomMeNoDesc(self):
|
||||
"""Test that an invalid Intel descriptor entry is detected"""
|
||||
TestFunctional._MakeInputFile('descriptor.bin', '')
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('31_x86-rom-me.dts')
|
||||
self.assertIn("Node '/binman/intel-descriptor': Cannot find FD "
|
||||
"signature", str(e.exception))
|
||||
|
||||
def testPackX86RomBadDesc(self):
|
||||
"""Test that the Intel requires a descriptor entry"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoTestFile('30_x86-rom-me-no-desc.dts')
|
||||
self.assertIn("Node '/binman/intel-me': No position set with "
|
||||
"pos-unset: should another entry provide this correct "
|
||||
"position?", str(e.exception))
|
||||
|
||||
def testPackX86RomMe(self):
|
||||
"""Test that an x86 ROM with an ME region can be created"""
|
||||
data = self._DoReadFile('31_x86-rom-me.dts')
|
||||
self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
|
||||
|
||||
def testPackVga(self):
|
||||
"""Test that an image with a VGA binary can be created"""
|
||||
data = self._DoReadFile('32_intel-vga.dts')
|
||||
self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
|
||||
|
||||
def testPackStart16(self):
|
||||
"""Test that an image with an x86 start16 region can be created"""
|
||||
data = self._DoReadFile('33_x86-start16.dts')
|
||||
self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
|
||||
|
||||
def testPackUbootMicrocode(self):
|
||||
"""Test that x86 microcode can be handled correctly
|
||||
|
||||
We expect to see the following in the image, in order:
|
||||
u-boot-nodtb.bin with a microcode pointer inserted at the correct
|
||||
place
|
||||
u-boot.dtb with the microcode removed
|
||||
the microcode
|
||||
"""
|
||||
data = self._DoReadFile('34_x86_ucode.dts', True)
|
||||
|
||||
# Now check the device tree has no microcode
|
||||
second = data[len(U_BOOT_NODTB_DATA):]
|
||||
fname = tools.GetOutputFilename('test.dtb')
|
||||
with open(fname, 'wb') as fd:
|
||||
fd.write(second)
|
||||
fdt = fdt_select.FdtScan(fname)
|
||||
ucode = fdt.GetNode('/microcode')
|
||||
self.assertTrue(ucode)
|
||||
for node in ucode.subnodes:
|
||||
self.assertFalse(node.props.get('data'))
|
||||
|
||||
fdt_len = self.GetFdtLen(second)
|
||||
third = second[fdt_len:]
|
||||
|
||||
# Check that the microcode appears immediately after the Fdt
|
||||
# This matches the concatenation of the data properties in
|
||||
# the /microcode/update@xxx nodes in x86_ucode.dts.
|
||||
ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
|
||||
0x78235609)
|
||||
self.assertEqual(ucode_data, third[:len(ucode_data)])
|
||||
ucode_pos = len(U_BOOT_NODTB_DATA) + fdt_len
|
||||
|
||||
# Check that the microcode pointer was inserted. It should match the
|
||||
# expected position and size
|
||||
pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
|
||||
len(ucode_data))
|
||||
first = data[:len(U_BOOT_NODTB_DATA)]
|
||||
self.assertEqual('nodtb with microcode' + pos_and_size +
|
||||
' somewhere in here', first)
|
||||
|
||||
def _RunPackUbootSingleMicrocode(self, collate):
|
||||
"""Test that x86 microcode can be handled correctly
|
||||
|
||||
We expect to see the following in the image, in order:
|
||||
u-boot-nodtb.bin with a microcode pointer inserted at the correct
|
||||
place
|
||||
u-boot.dtb with the microcode
|
||||
an empty microcode region
|
||||
"""
|
||||
# We need the libfdt library to run this test since only that allows
|
||||
# finding the offset of a property. This is required by
|
||||
# Entry_u_boot_dtb_with_ucode.ObtainContents().
|
||||
if not fdt_select.have_libfdt:
|
||||
return
|
||||
data = self._DoReadFile('35_x86_single_ucode.dts', True)
|
||||
|
||||
second = data[len(U_BOOT_NODTB_DATA):]
|
||||
|
||||
fdt_len = self.GetFdtLen(second)
|
||||
third = second[fdt_len:]
|
||||
second = second[:fdt_len]
|
||||
|
||||
if not collate:
|
||||
ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
|
||||
self.assertIn(ucode_data, second)
|
||||
ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
|
||||
|
||||
# Check that the microcode pointer was inserted. It should match the
|
||||
# expected position and size
|
||||
pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
|
||||
len(ucode_data))
|
||||
first = data[:len(U_BOOT_NODTB_DATA)]
|
||||
self.assertEqual('nodtb with microcode' + pos_and_size +
|
||||
' somewhere in here', first)
|
||||
|
||||
def testPackUbootSingleMicrocode(self):
|
||||
"""Test that x86 microcode can be handled correctly with fdt_normal.
|
||||
"""
|
||||
self._RunPackUbootSingleMicrocode(False)
|
||||
|
||||
def testPackUbootSingleMicrocodeFallback(self):
|
||||
"""Test that x86 microcode can be handled correctly with fdt_fallback.
|
||||
|
||||
This only supports collating the microcode.
|
||||
"""
|
||||
try:
|
||||
old_val = fdt_select.UseFallback(True)
|
||||
self._RunPackUbootSingleMicrocode(True)
|
||||
finally:
|
||||
fdt_select.UseFallback(old_val)
|
||||
|
||||
def testUBootImg(self):
|
||||
"""Test that u-boot.img can be put in a file"""
|
||||
data = self._DoReadFile('36_u_boot_img.dts')
|
||||
self.assertEqual(U_BOOT_IMG_DATA, data)
|
||||
|
||||
def testNoMicrocode(self):
|
||||
"""Test that a missing microcode region is detected"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFile('37_x86_no_ucode.dts', True)
|
||||
self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
|
||||
"node found in ", str(e.exception))
|
||||
|
||||
def testMicrocodeWithoutNode(self):
|
||||
"""Test that a missing u-boot-dtb-with-ucode node is detected"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFile('38_x86_ucode_missing_node.dts', True)
|
||||
self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
|
||||
"microcode region u-boot-dtb-with-ucode", str(e.exception))
|
||||
|
||||
def testMicrocodeWithoutNode2(self):
|
||||
"""Test that a missing u-boot-ucode node is detected"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFile('39_x86_ucode_missing_node2.dts', True)
|
||||
self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
|
||||
"microcode region u-boot-ucode", str(e.exception))
|
||||
|
||||
def testMicrocodeWithoutPtrInElf(self):
|
||||
"""Test that a U-Boot binary without the microcode symbol is detected"""
|
||||
# ELF file without a '_dt_ucode_base_size' symbol
|
||||
if not fdt_select.have_libfdt:
|
||||
return
|
||||
try:
|
||||
with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
|
||||
TestFunctional._MakeInputFile('u-boot', fd.read())
|
||||
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._RunPackUbootSingleMicrocode(False)
|
||||
self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
|
||||
"_dt_ucode_base_size symbol in u-boot", str(e.exception))
|
||||
|
||||
finally:
|
||||
# Put the original file back
|
||||
with open(self.TestFile('u_boot_ucode_ptr')) as fd:
|
||||
TestFunctional._MakeInputFile('u-boot', fd.read())
|
||||
|
||||
def testMicrocodeNotInImage(self):
|
||||
"""Test that microcode must be placed within the image"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFile('40_x86_ucode_not_in_image.dts', True)
|
||||
self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
|
||||
"pointer _dt_ucode_base_size at fffffe14 is outside the "
|
||||
"image ranging from 00000000 to 0000002e", str(e.exception))
|
||||
|
||||
def testWithoutMicrocode(self):
|
||||
"""Test that we can cope with an image without microcode (e.g. qemu)"""
|
||||
with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
|
||||
TestFunctional._MakeInputFile('u-boot', fd.read())
|
||||
data, dtb = self._DoReadFileDtb('44_x86_optional_ucode.dts', True)
|
||||
|
||||
# Now check the device tree has no microcode
|
||||
self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
|
||||
second = data[len(U_BOOT_NODTB_DATA):]
|
||||
|
||||
fdt_len = self.GetFdtLen(second)
|
||||
self.assertEqual(dtb, second[:fdt_len])
|
||||
|
||||
used_len = len(U_BOOT_NODTB_DATA) + fdt_len
|
||||
third = data[used_len:]
|
||||
self.assertEqual(chr(0) * (0x200 - used_len), third)
|
||||
|
||||
def testUnknownPosSize(self):
|
||||
"""Test that microcode must be placed within the image"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFile('41_unknown_pos_size.dts', True)
|
||||
self.assertIn("Image '/binman': Unable to set pos/size for unknown "
|
||||
"entry 'invalid-entry'", str(e.exception))
|
||||
|
||||
def testPackFsp(self):
|
||||
"""Test that an image with a FSP binary can be created"""
|
||||
data = self._DoReadFile('42_intel-fsp.dts')
|
||||
self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
|
||||
|
||||
def testPackCmc(self):
|
||||
"""Test that an image with a FSP binary can be created"""
|
||||
data = self._DoReadFile('43_intel-cmc.dts')
|
||||
self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
|
229
tools/binman/image.py
Normal file
229
tools/binman/image.py
Normal file
|
@ -0,0 +1,229 @@
|
|||
# Copyright (c) 2016 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Class for an image, the output of binman
|
||||
#
|
||||
|
||||
from collections import OrderedDict
|
||||
from operator import attrgetter
|
||||
|
||||
import entry
|
||||
from entry import Entry
|
||||
import fdt_util
|
||||
import tools
|
||||
|
||||
class Image:
|
||||
"""A Image, representing an output from binman
|
||||
|
||||
An image is comprised of a collection of entries each containing binary
|
||||
data. The image size must be large enough to hold all of this data.
|
||||
|
||||
This class implements the various operations needed for images.
|
||||
|
||||
Atrtributes:
|
||||
_node: Node object that contains the image definition in device tree
|
||||
_name: Image name
|
||||
_size: Image size in bytes, or None if not known yet
|
||||
_align_size: Image size alignment, or None
|
||||
_pad_before: Number of bytes before the first entry starts. This
|
||||
effectively changes the place where entry position 0 starts
|
||||
_pad_after: Number of bytes after the last entry ends. The last
|
||||
entry will finish on or before this boundary
|
||||
_pad_byte: Byte to use to pad the image where there is no entry
|
||||
_filename: Output filename for image
|
||||
_sort: True if entries should be sorted by position, False if they
|
||||
must be in-order in the device tree description
|
||||
_skip_at_start: Number of bytes before the first entry starts. These
|
||||
effecively adjust the starting position of entries. For example,
|
||||
if _pad_before is 16, then the first entry would start at 16.
|
||||
An entry with pos = 20 would in fact be written at position 4
|
||||
in the image file.
|
||||
_end_4gb: Indicates that the image ends at the 4GB boundary. This is
|
||||
used for x86 images, which want to use positions such that a
|
||||
memory address (like 0xff800000) is the first entry position.
|
||||
This causes _skip_at_start to be set to the starting memory
|
||||
address.
|
||||
_entries: OrderedDict() of entries
|
||||
"""
|
||||
def __init__(self, name, node):
|
||||
self._node = node
|
||||
self._name = name
|
||||
self._size = None
|
||||
self._align_size = None
|
||||
self._pad_before = 0
|
||||
self._pad_after = 0
|
||||
self._pad_byte = 0
|
||||
self._filename = '%s.bin' % self._name
|
||||
self._sort = False
|
||||
self._skip_at_start = 0
|
||||
self._end_4gb = False
|
||||
self._entries = OrderedDict()
|
||||
|
||||
self._ReadNode()
|
||||
self._ReadEntries()
|
||||
|
||||
def _ReadNode(self):
|
||||
"""Read properties from the image node"""
|
||||
self._size = fdt_util.GetInt(self._node, 'size')
|
||||
self._align_size = fdt_util.GetInt(self._node, 'align-size')
|
||||
if tools.NotPowerOfTwo(self._align_size):
|
||||
self._Raise("Alignment size %s must be a power of two" %
|
||||
self._align_size)
|
||||
self._pad_before = fdt_util.GetInt(self._node, 'pad-before', 0)
|
||||
self._pad_after = fdt_util.GetInt(self._node, 'pad-after', 0)
|
||||
self._pad_byte = fdt_util.GetInt(self._node, 'pad-byte', 0)
|
||||
filename = fdt_util.GetString(self._node, 'filename')
|
||||
if filename:
|
||||
self._filename = filename
|
||||
self._sort = fdt_util.GetBool(self._node, 'sort-by-pos')
|
||||
self._end_4gb = fdt_util.GetBool(self._node, 'end-at-4gb')
|
||||
if self._end_4gb and not self._size:
|
||||
self._Raise("Image size must be provided when using end-at-4gb")
|
||||
if self._end_4gb:
|
||||
self._skip_at_start = 0x100000000 - self._size
|
||||
|
||||
def CheckSize(self):
|
||||
"""Check that the image contents does not exceed its size, etc."""
|
||||
contents_size = 0
|
||||
for entry in self._entries.values():
|
||||
contents_size = max(contents_size, entry.pos + entry.size)
|
||||
|
||||
contents_size -= self._skip_at_start
|
||||
|
||||
size = self._size
|
||||
if not size:
|
||||
size = self._pad_before + contents_size + self._pad_after
|
||||
size = tools.Align(size, self._align_size)
|
||||
|
||||
if self._size and contents_size > self._size:
|
||||
self._Raise("contents size %#x (%d) exceeds image size %#x (%d)" %
|
||||
(contents_size, contents_size, self._size, self._size))
|
||||
if not self._size:
|
||||
self._size = size
|
||||
if self._size != tools.Align(self._size, self._align_size):
|
||||
self._Raise("Size %#x (%d) does not match align-size %#x (%d)" %
|
||||
(self._size, self._size, self._align_size, self._align_size))
|
||||
|
||||
def _Raise(self, msg):
|
||||
"""Raises an error for this image
|
||||
|
||||
Args:
|
||||
msg: Error message to use in the raise string
|
||||
Raises:
|
||||
ValueError()
|
||||
"""
|
||||
raise ValueError("Image '%s': %s" % (self._node.path, msg))
|
||||
|
||||
def _ReadEntries(self):
|
||||
for node in self._node.subnodes:
|
||||
self._entries[node.name] = Entry.Create(self, node)
|
||||
|
||||
def FindEntryType(self, etype):
|
||||
"""Find an entry type in the image
|
||||
|
||||
Args:
|
||||
etype: Entry type to find
|
||||
Returns:
|
||||
entry matching that type, or None if not found
|
||||
"""
|
||||
for entry in self._entries.values():
|
||||
if entry.etype == etype:
|
||||
return entry
|
||||
return None
|
||||
|
||||
def GetEntryContents(self):
|
||||
"""Call ObtainContents() for each entry
|
||||
|
||||
This calls each entry's ObtainContents() a few times until they all
|
||||
return True. We stop calling an entry's function once it returns
|
||||
True. This allows the contents of one entry to depend on another.
|
||||
|
||||
After 3 rounds we give up since it's likely an error.
|
||||
"""
|
||||
todo = self._entries.values()
|
||||
for passnum in range(3):
|
||||
next_todo = []
|
||||
for entry in todo:
|
||||
if not entry.ObtainContents():
|
||||
next_todo.append(entry)
|
||||
todo = next_todo
|
||||
if not todo:
|
||||
break
|
||||
|
||||
def _SetEntryPosSize(self, name, pos, size):
|
||||
"""Set the position and size of an entry
|
||||
|
||||
Args:
|
||||
name: Entry name to update
|
||||
pos: New position
|
||||
size: New size
|
||||
"""
|
||||
entry = self._entries.get(name)
|
||||
if not entry:
|
||||
self._Raise("Unable to set pos/size for unknown entry '%s'" % name)
|
||||
entry.SetPositionSize(self._skip_at_start + pos, size)
|
||||
|
||||
def GetEntryPositions(self):
|
||||
"""Handle entries that want to set the position/size of other entries
|
||||
|
||||
This calls each entry's GetPositions() method. If it returns a list
|
||||
of entries to update, it updates them.
|
||||
"""
|
||||
for entry in self._entries.values():
|
||||
pos_dict = entry.GetPositions()
|
||||
for name, info in pos_dict.iteritems():
|
||||
self._SetEntryPosSize(name, *info)
|
||||
|
||||
def PackEntries(self):
|
||||
"""Pack all entries into the image"""
|
||||
pos = self._skip_at_start
|
||||
for entry in self._entries.values():
|
||||
pos = entry.Pack(pos)
|
||||
|
||||
def _SortEntries(self):
|
||||
"""Sort entries by position"""
|
||||
entries = sorted(self._entries.values(), key=lambda entry: entry.pos)
|
||||
self._entries.clear()
|
||||
for entry in entries:
|
||||
self._entries[entry._node.name] = entry
|
||||
|
||||
def CheckEntries(self):
|
||||
"""Check that entries do not overlap or extend outside the image"""
|
||||
if self._sort:
|
||||
self._SortEntries()
|
||||
pos = 0
|
||||
prev_name = 'None'
|
||||
for entry in self._entries.values():
|
||||
if (entry.pos < self._skip_at_start or
|
||||
entry.pos >= self._skip_at_start + self._size):
|
||||
entry.Raise("Position %#x (%d) is outside the image starting "
|
||||
"at %#x (%d)" %
|
||||
(entry.pos, entry.pos, self._skip_at_start,
|
||||
self._skip_at_start))
|
||||
if entry.pos < pos:
|
||||
entry.Raise("Position %#x (%d) overlaps with previous entry '%s' "
|
||||
"ending at %#x (%d)" %
|
||||
(entry.pos, entry.pos, prev_name, pos, pos))
|
||||
pos = entry.pos + entry.size
|
||||
prev_name = entry.GetPath()
|
||||
|
||||
def ProcessEntryContents(self):
|
||||
"""Call the ProcessContents() method for each entry
|
||||
|
||||
This is intended to adjust the contents as needed by the entry type.
|
||||
"""
|
||||
for entry in self._entries.values():
|
||||
entry.ProcessContents()
|
||||
|
||||
def BuildImage(self):
|
||||
"""Write the image to a file"""
|
||||
fname = tools.GetOutputFilename(self._filename)
|
||||
with open(fname, 'wb') as fd:
|
||||
fd.write(chr(self._pad_byte) * self._size)
|
||||
|
||||
for entry in self._entries.values():
|
||||
data = entry.GetData()
|
||||
fd.seek(self._pad_before + entry.pos - self._skip_at_start)
|
||||
fd.write(data)
|
5
tools/binman/test/01_invalid.dts
Normal file
5
tools/binman/test/01_invalid.dts
Normal file
|
@ -0,0 +1,5 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
6
tools/binman/test/02_missing_node.dts
Normal file
6
tools/binman/test/02_missing_node.dts
Normal file
|
@ -0,0 +1,6 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
};
|
9
tools/binman/test/03_empty.dts
Normal file
9
tools/binman/test/03_empty.dts
Normal file
|
@ -0,0 +1,9 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
};
|
||||
};
|
11
tools/binman/test/04_invalid_entry.dts
Normal file
11
tools/binman/test/04_invalid_entry.dts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
not-a-valid-type {
|
||||
};
|
||||
};
|
||||
};
|
11
tools/binman/test/05_simple.dts
Normal file
11
tools/binman/test/05_simple.dts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
};
|
22
tools/binman/test/06_dual_image.dts
Normal file
22
tools/binman/test/06_dual_image.dts
Normal file
|
@ -0,0 +1,22 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
multiple-images;
|
||||
image1 {
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
|
||||
image2 {
|
||||
pad-before = <3>;
|
||||
pad-after = <5>;
|
||||
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
12
tools/binman/test/07_bad_align.dts
Normal file
12
tools/binman/test/07_bad_align.dts
Normal file
|
@ -0,0 +1,12 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u-boot {
|
||||
align = <23>;
|
||||
};
|
||||
};
|
||||
};
|
30
tools/binman/test/08_pack.dts
Normal file
30
tools/binman/test/08_pack.dts
Normal file
|
@ -0,0 +1,30 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u-boot {
|
||||
};
|
||||
|
||||
u-boot-align {
|
||||
type = "u-boot";
|
||||
align = <16>;
|
||||
};
|
||||
|
||||
u-boot-size {
|
||||
type = "u-boot";
|
||||
size = <23>;
|
||||
};
|
||||
|
||||
u-boot-next {
|
||||
type = "u-boot";
|
||||
};
|
||||
|
||||
u-boot-fixed {
|
||||
type = "u-boot";
|
||||
pos = <61>;
|
||||
};
|
||||
};
|
||||
};
|
35
tools/binman/test/09_pack_extra.dts
Normal file
35
tools/binman/test/09_pack_extra.dts
Normal file
|
@ -0,0 +1,35 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u-boot {
|
||||
pad-before = <3>;
|
||||
pad-after = <5>;
|
||||
};
|
||||
|
||||
u-boot-align-size-nop {
|
||||
type = "u-boot";
|
||||
align-size = <4>;
|
||||
};
|
||||
|
||||
u-boot-align-size {
|
||||
type = "u-boot";
|
||||
align = <16>;
|
||||
align-size = <32>;
|
||||
};
|
||||
|
||||
u-boot-align-end {
|
||||
type = "u-boot";
|
||||
align-end = <64>;
|
||||
};
|
||||
|
||||
u-boot-align-both {
|
||||
type = "u-boot";
|
||||
align= <64>;
|
||||
align-end = <128>;
|
||||
};
|
||||
};
|
||||
};
|
12
tools/binman/test/10_pack_align_power2.dts
Normal file
12
tools/binman/test/10_pack_align_power2.dts
Normal file
|
@ -0,0 +1,12 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u-boot {
|
||||
align = <5>;
|
||||
};
|
||||
};
|
||||
};
|
12
tools/binman/test/11_pack_align_size_power2.dts
Normal file
12
tools/binman/test/11_pack_align_size_power2.dts
Normal file
|
@ -0,0 +1,12 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u-boot {
|
||||
align-size = <55>;
|
||||
};
|
||||
};
|
||||
};
|
13
tools/binman/test/12_pack_inv_align.dts
Normal file
13
tools/binman/test/12_pack_inv_align.dts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u-boot {
|
||||
pos = <5>;
|
||||
align = <4>;
|
||||
};
|
||||
};
|
||||
};
|
13
tools/binman/test/13_pack_inv_size_align.dts
Normal file
13
tools/binman/test/13_pack_inv_size_align.dts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u-boot {
|
||||
size = <5>;
|
||||
align-size = <4>;
|
||||
};
|
||||
};
|
||||
};
|
16
tools/binman/test/14_pack_overlap.dts
Normal file
16
tools/binman/test/14_pack_overlap.dts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u-boot {
|
||||
};
|
||||
|
||||
u-boot-align {
|
||||
type = "u-boot";
|
||||
pos = <3>;
|
||||
};
|
||||
};
|
||||
};
|
12
tools/binman/test/15_pack_overflow.dts
Normal file
12
tools/binman/test/15_pack_overflow.dts
Normal file
|
@ -0,0 +1,12 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u-boot {
|
||||
size = <3>;
|
||||
};
|
||||
};
|
||||
};
|
13
tools/binman/test/16_pack_image_overflow.dts
Normal file
13
tools/binman/test/16_pack_image_overflow.dts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
size = <3>;
|
||||
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
};
|
13
tools/binman/test/17_pack_image_size.dts
Normal file
13
tools/binman/test/17_pack_image_size.dts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
size = <7>;
|
||||
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
};
|
13
tools/binman/test/18_pack_image_align.dts
Normal file
13
tools/binman/test/18_pack_image_align.dts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
align-size = <16>;
|
||||
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
};
|
14
tools/binman/test/19_pack_inv_image_align.dts
Normal file
14
tools/binman/test/19_pack_inv_image_align.dts
Normal file
|
@ -0,0 +1,14 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
size = <7>;
|
||||
align-size = <8>;
|
||||
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
};
|
13
tools/binman/test/20_pack_inv_image_align_power2.dts
Normal file
13
tools/binman/test/20_pack_inv_image_align_power2.dts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
align-size = <131>;
|
||||
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
};
|
16
tools/binman/test/21_image_pad.dts
Normal file
16
tools/binman/test/21_image_pad.dts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
pad-byte = <0xff>;
|
||||
u-boot-spl {
|
||||
};
|
||||
|
||||
u-boot {
|
||||
pos = <12>;
|
||||
};
|
||||
};
|
||||
};
|
21
tools/binman/test/22_image_name.dts
Normal file
21
tools/binman/test/22_image_name.dts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
multiple-images;
|
||||
image1 {
|
||||
filename = "test-name";
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
|
||||
image2 {
|
||||
filename = "test-name.xx";
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
12
tools/binman/test/23_blob.dts
Normal file
12
tools/binman/test/23_blob.dts
Normal file
|
@ -0,0 +1,12 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
blob {
|
||||
filename = "blobfile";
|
||||
};
|
||||
};
|
||||
};
|
17
tools/binman/test/24_sorted.dts
Normal file
17
tools/binman/test/24_sorted.dts
Normal file
|
@ -0,0 +1,17 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
u-boot {
|
||||
pos = <10>;
|
||||
};
|
||||
|
||||
u-boot-spl {
|
||||
pos = <5>;
|
||||
};
|
||||
};
|
||||
};
|
15
tools/binman/test/25_pack_zero_size.dts
Normal file
15
tools/binman/test/25_pack_zero_size.dts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u-boot {
|
||||
};
|
||||
|
||||
u-boot-spl {
|
||||
pos = <0>;
|
||||
};
|
||||
};
|
||||
};
|
14
tools/binman/test/26_pack_u_boot_dtb.dts
Normal file
14
tools/binman/test/26_pack_u_boot_dtb.dts
Normal file
|
@ -0,0 +1,14 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u-boot-nodtb {
|
||||
};
|
||||
|
||||
u-boot-dtb {
|
||||
};
|
||||
};
|
||||
};
|
18
tools/binman/test/27_pack_4gb_no_size.dts
Normal file
18
tools/binman/test/27_pack_4gb_no_size.dts
Normal file
|
@ -0,0 +1,18 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
end-at-4gb;
|
||||
u-boot {
|
||||
pos = <0xfffffff0>;
|
||||
};
|
||||
|
||||
u-boot-spl {
|
||||
pos = <0xfffffff7>;
|
||||
};
|
||||
};
|
||||
};
|
19
tools/binman/test/28_pack_4gb_outside.dts
Normal file
19
tools/binman/test/28_pack_4gb_outside.dts
Normal file
|
@ -0,0 +1,19 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
end-at-4gb;
|
||||
size = <16>;
|
||||
u-boot {
|
||||
pos = <0>;
|
||||
};
|
||||
|
||||
u-boot-spl {
|
||||
pos = <0xfffffff7>;
|
||||
};
|
||||
};
|
||||
};
|
19
tools/binman/test/29_x86-rom.dts
Normal file
19
tools/binman/test/29_x86-rom.dts
Normal file
|
@ -0,0 +1,19 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
end-at-4gb;
|
||||
size = <16>;
|
||||
u-boot {
|
||||
pos = <0xfffffff0>;
|
||||
};
|
||||
|
||||
u-boot-spl {
|
||||
pos = <0xfffffff7>;
|
||||
};
|
||||
};
|
||||
};
|
15
tools/binman/test/30_x86-rom-me-no-desc.dts
Normal file
15
tools/binman/test/30_x86-rom-me-no-desc.dts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
end-at-4gb;
|
||||
size = <16>;
|
||||
intel-me {
|
||||
pos-unset;
|
||||
};
|
||||
};
|
||||
};
|
18
tools/binman/test/31_x86-rom-me.dts
Normal file
18
tools/binman/test/31_x86-rom-me.dts
Normal file
|
@ -0,0 +1,18 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
end-at-4gb;
|
||||
size = <0x800000>;
|
||||
intel-descriptor {
|
||||
};
|
||||
|
||||
intel-me {
|
||||
pos-unset;
|
||||
};
|
||||
};
|
||||
};
|
13
tools/binman/test/32_intel-vga.dts
Normal file
13
tools/binman/test/32_intel-vga.dts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
size = <16>;
|
||||
|
||||
intel-vga {
|
||||
};
|
||||
};
|
||||
};
|
13
tools/binman/test/33_x86-start16.dts
Normal file
13
tools/binman/test/33_x86-start16.dts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
size = <16>;
|
||||
|
||||
x86-start16 {
|
||||
};
|
||||
};
|
||||
};
|
29
tools/binman/test/34_x86_ucode.dts
Normal file
29
tools/binman/test/34_x86_ucode.dts
Normal file
|
@ -0,0 +1,29 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
end-at-4gb;
|
||||
size = <0x200>;
|
||||
u-boot-with-ucode-ptr {
|
||||
};
|
||||
|
||||
u-boot-dtb-with-ucode {
|
||||
};
|
||||
|
||||
u-boot-ucode {
|
||||
};
|
||||
};
|
||||
|
||||
microcode {
|
||||
update@0 {
|
||||
data = <0x12345678 0x12345679>;
|
||||
};
|
||||
update@1 {
|
||||
data = <0xabcd0000 0x78235609>;
|
||||
};
|
||||
};
|
||||
};
|
26
tools/binman/test/35_x86_single_ucode.dts
Normal file
26
tools/binman/test/35_x86_single_ucode.dts
Normal file
|
@ -0,0 +1,26 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
end-at-4gb;
|
||||
size = <0x200>;
|
||||
u-boot-with-ucode-ptr {
|
||||
};
|
||||
|
||||
u-boot-dtb-with-ucode {
|
||||
};
|
||||
|
||||
u-boot-ucode {
|
||||
};
|
||||
};
|
||||
|
||||
microcode {
|
||||
update@0 {
|
||||
data = <0x12345678 0x12345679>;
|
||||
};
|
||||
};
|
||||
};
|
11
tools/binman/test/36_u_boot_img.dts
Normal file
11
tools/binman/test/36_u_boot_img.dts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u-boot-img {
|
||||
};
|
||||
};
|
||||
};
|
20
tools/binman/test/37_x86_no_ucode.dts
Normal file
20
tools/binman/test/37_x86_no_ucode.dts
Normal file
|
@ -0,0 +1,20 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
end-at-4gb;
|
||||
size = <0x200>;
|
||||
u-boot-with-ucode-ptr {
|
||||
};
|
||||
|
||||
u-boot-dtb-with-ucode {
|
||||
};
|
||||
|
||||
u-boot-ucode {
|
||||
};
|
||||
};
|
||||
};
|
26
tools/binman/test/38_x86_ucode_missing_node.dts
Normal file
26
tools/binman/test/38_x86_ucode_missing_node.dts
Normal file
|
@ -0,0 +1,26 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
end-at-4gb;
|
||||
size = <0x200>;
|
||||
u-boot-with-ucode-ptr {
|
||||
};
|
||||
|
||||
u-boot-ucode {
|
||||
};
|
||||
};
|
||||
|
||||
microcode {
|
||||
update@0 {
|
||||
data = <0x12345678 0x12345679>;
|
||||
};
|
||||
update@1 {
|
||||
data = <0xabcd0000 0x78235609>;
|
||||
};
|
||||
};
|
||||
};
|
23
tools/binman/test/39_x86_ucode_missing_node2.dts
Normal file
23
tools/binman/test/39_x86_ucode_missing_node2.dts
Normal file
|
@ -0,0 +1,23 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
end-at-4gb;
|
||||
size = <0x200>;
|
||||
u-boot-with-ucode-ptr {
|
||||
};
|
||||
};
|
||||
|
||||
microcode {
|
||||
update@0 {
|
||||
data = <0x12345678 0x12345679>;
|
||||
};
|
||||
update@1 {
|
||||
data = <0xabcd0000 0x78235609>;
|
||||
};
|
||||
};
|
||||
};
|
28
tools/binman/test/40_x86_ucode_not_in_image.dts
Normal file
28
tools/binman/test/40_x86_ucode_not_in_image.dts
Normal file
|
@ -0,0 +1,28 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
size = <0x200>;
|
||||
u-boot-with-ucode-ptr {
|
||||
};
|
||||
|
||||
u-boot-dtb-with-ucode {
|
||||
};
|
||||
|
||||
u-boot-ucode {
|
||||
};
|
||||
};
|
||||
|
||||
microcode {
|
||||
update@0 {
|
||||
data = <0x12345678 0x12345679>;
|
||||
};
|
||||
update@1 {
|
||||
data = <0xabcd0000 0x78235609>;
|
||||
};
|
||||
};
|
||||
};
|
11
tools/binman/test/41_unknown_pos_size.dts
Normal file
11
tools/binman/test/41_unknown_pos_size.dts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
_testing {
|
||||
};
|
||||
};
|
||||
};
|
13
tools/binman/test/42_intel-fsp.dts
Normal file
13
tools/binman/test/42_intel-fsp.dts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
size = <16>;
|
||||
|
||||
intel-fsp {
|
||||
};
|
||||
};
|
||||
};
|
13
tools/binman/test/43_intel-cmc.dts
Normal file
13
tools/binman/test/43_intel-cmc.dts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
size = <16>;
|
||||
|
||||
intel-cmc {
|
||||
};
|
||||
};
|
||||
};
|
30
tools/binman/test/44_x86_optional_ucode.dts
Normal file
30
tools/binman/test/44_x86_optional_ucode.dts
Normal file
|
@ -0,0 +1,30 @@
|
|||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
sort-by-pos;
|
||||
end-at-4gb;
|
||||
size = <0x200>;
|
||||
u-boot-with-ucode-ptr {
|
||||
optional-ucode;
|
||||
};
|
||||
|
||||
u-boot-dtb-with-ucode {
|
||||
};
|
||||
|
||||
u-boot-ucode {
|
||||
};
|
||||
};
|
||||
|
||||
microcode {
|
||||
update@0 {
|
||||
data = <0x12345678 0x12345679>;
|
||||
};
|
||||
update@1 {
|
||||
data = <0xabcd0000 0x78235609>;
|
||||
};
|
||||
};
|
||||
};
|
BIN
tools/binman/test/descriptor.bin
Normal file
BIN
tools/binman/test/descriptor.bin
Normal file
Binary file not shown.
BIN
tools/binman/test/u_boot_no_ucode_ptr
Executable file
BIN
tools/binman/test/u_boot_no_ucode_ptr
Executable file
Binary file not shown.
15
tools/binman/test/u_boot_no_ucode_ptr.c
Normal file
15
tools/binman/test/u_boot_no_ucode_ptr.c
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Simple program to create a bad _dt_ucode_base_size symbol to create an
|
||||
* error when it is used. This is used by binman tests.
|
||||
*
|
||||
* Build with:
|
||||
* cc -march=i386 -m32 -o u_boot_no_ucode_ptr -T u_boot_ucode_ptr.lds \
|
||||
-nostdlib u_boot_no_ucode_ptr.c
|
||||
*/
|
||||
|
||||
static unsigned long not__dt_ucode_base_size[2]
|
||||
__attribute__((section(".ucode"))) = {1, 2};
|
BIN
tools/binman/test/u_boot_ucode_ptr
Executable file
BIN
tools/binman/test/u_boot_ucode_ptr
Executable file
Binary file not shown.
15
tools/binman/test/u_boot_ucode_ptr.c
Normal file
15
tools/binman/test/u_boot_ucode_ptr.c
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Simple program to create a _dt_ucode_base_size symbol which can be read
|
||||
* by 'nm'. This is used by binman tests.
|
||||
*
|
||||
* Build with:
|
||||
* cc -march=i386 -m32 -o u_boot_ucode_ptr -T u_boot_ucode_ptr.lds -nostdlib \
|
||||
u_boot_ucode_ptr.c
|
||||
*/
|
||||
|
||||
static unsigned long _dt_ucode_base_size[2]
|
||||
__attribute__((section(".ucode"))) = {1, 2};
|
18
tools/binman/test/u_boot_ucode_ptr.lds
Normal file
18
tools/binman/test/u_boot_ucode_ptr.lds
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0xfffffdf0;
|
||||
_start = .;
|
||||
.ucode : {
|
||||
*(.ucode)
|
||||
}
|
||||
}
|
254
tools/ifdtool.c
254
tools/ifdtool.c
|
@ -33,16 +33,9 @@
|
|||
#define FLREG_BASE(reg) ((reg & 0x00000fff) << 12);
|
||||
#define FLREG_LIMIT(reg) (((reg & 0x0fff0000) >> 4) | 0xfff);
|
||||
|
||||
enum input_file_type_t {
|
||||
IF_normal,
|
||||
IF_fdt,
|
||||
IF_uboot,
|
||||
};
|
||||
|
||||
struct input_file {
|
||||
char *fname;
|
||||
unsigned int addr;
|
||||
enum input_file_type_t type;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -760,219 +753,6 @@ static int write_data(char *image, int size, unsigned int addr,
|
|||
return write_size;
|
||||
}
|
||||
|
||||
static int scan_ucode(const void *blob, char *ucode_base, int *countp,
|
||||
const char **datap, int *data_sizep)
|
||||
{
|
||||
const char *data = NULL;
|
||||
int node, count;
|
||||
int data_size;
|
||||
char *ucode;
|
||||
|
||||
for (node = 0, count = 0, ucode = ucode_base; node >= 0; count++) {
|
||||
node = fdt_node_offset_by_compatible(blob, node,
|
||||
"intel,microcode");
|
||||
if (node < 0)
|
||||
break;
|
||||
|
||||
data = fdt_getprop(blob, node, "data", &data_size);
|
||||
if (!data) {
|
||||
debug("Missing microcode data in FDT '%s': %s\n",
|
||||
fdt_get_name(blob, node, NULL),
|
||||
fdt_strerror(data_size));
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (ucode_base)
|
||||
memcpy(ucode, data, data_size);
|
||||
ucode += data_size;
|
||||
}
|
||||
|
||||
if (countp)
|
||||
*countp = count;
|
||||
if (datap)
|
||||
*datap = data;
|
||||
if (data_sizep)
|
||||
*data_sizep = data_size;
|
||||
|
||||
return ucode - ucode_base;
|
||||
}
|
||||
|
||||
static int remove_ucode(char *blob)
|
||||
{
|
||||
int node, count;
|
||||
int ret;
|
||||
|
||||
/* Keep going until we find no more microcode to remove */
|
||||
do {
|
||||
for (node = 0, count = 0; node >= 0;) {
|
||||
int ret;
|
||||
|
||||
node = fdt_node_offset_by_compatible(blob, node,
|
||||
"intel,microcode");
|
||||
if (node < 0)
|
||||
break;
|
||||
|
||||
ret = fdt_delprop(blob, node, "data");
|
||||
|
||||
/*
|
||||
* -FDT_ERR_NOTFOUND means we already removed the
|
||||
* data for this one, so we just continue.
|
||||
* 0 means we did remove it, so offsets may have
|
||||
* changed and we need to restart our scan.
|
||||
* Anything else indicates an error we should report.
|
||||
*/
|
||||
if (ret == -FDT_ERR_NOTFOUND)
|
||||
continue;
|
||||
else if (!ret)
|
||||
node = 0;
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
} while (count);
|
||||
|
||||
/* Pack down to remove excees space */
|
||||
ret = fdt_pack(blob);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return fdt_totalsize(blob);
|
||||
}
|
||||
|
||||
static int write_ucode(char *image, int size, struct input_file *fdt,
|
||||
int fdt_size, unsigned int ucode_ptr,
|
||||
int collate_ucode)
|
||||
{
|
||||
const char *data = NULL;
|
||||
char *ucode_buf;
|
||||
const void *blob;
|
||||
char *ucode_base;
|
||||
uint32_t *ptr;
|
||||
int ucode_size;
|
||||
int data_size;
|
||||
int offset;
|
||||
int count;
|
||||
int ret;
|
||||
|
||||
blob = (void *)image + (uint32_t)(fdt->addr + size);
|
||||
|
||||
debug("DTB at %lx\n", (char *)blob - image);
|
||||
|
||||
/* Find out about the micrcode we have */
|
||||
ucode_size = scan_ucode(blob, NULL, &count, &data, &data_size);
|
||||
if (ucode_size < 0)
|
||||
return ucode_size;
|
||||
if (!count) {
|
||||
debug("No microcode found in FDT\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (count > 1 && !collate_ucode) {
|
||||
fprintf(stderr,
|
||||
"Cannot handle multiple microcode blocks - please use -C flag to collate them\n");
|
||||
return -EMLINK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Collect the microcode into a buffer, remove it from the device
|
||||
* tree and place it immediately above the (now smaller) device tree.
|
||||
*/
|
||||
if (collate_ucode && count > 1) {
|
||||
ucode_buf = malloc(ucode_size);
|
||||
if (!ucode_buf) {
|
||||
fprintf(stderr,
|
||||
"Out of memory for microcode (%d bytes)\n",
|
||||
ucode_size);
|
||||
return -ENOMEM;
|
||||
}
|
||||
ret = scan_ucode(blob, ucode_buf, NULL, NULL, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Remove the microcode from the device tree */
|
||||
ret = remove_ucode((char *)blob);
|
||||
if (ret < 0) {
|
||||
debug("Could not remove FDT microcode: %s\n",
|
||||
fdt_strerror(ret));
|
||||
return -EINVAL;
|
||||
}
|
||||
debug("Collated %d microcode block(s)\n", count);
|
||||
debug("Device tree reduced from %x to %x bytes\n",
|
||||
fdt_size, ret);
|
||||
fdt_size = ret;
|
||||
|
||||
/*
|
||||
* Place microcode area immediately above the FDT, aligned
|
||||
* to a 16-byte boundary.
|
||||
*/
|
||||
ucode_base = (char *)(((unsigned long)blob + fdt_size + 15) &
|
||||
~15);
|
||||
|
||||
data = ucode_base;
|
||||
data_size = ucode_size;
|
||||
memcpy(ucode_base, ucode_buf, ucode_size);
|
||||
free(ucode_buf);
|
||||
}
|
||||
|
||||
offset = (uint32_t)(ucode_ptr + size);
|
||||
ptr = (void *)image + offset;
|
||||
|
||||
ptr[0] = (data - image) - size;
|
||||
ptr[1] = data_size;
|
||||
debug("Wrote microcode pointer at %x: addr=%x, size=%x\n", ucode_ptr,
|
||||
ptr[0], ptr[1]);
|
||||
|
||||
return (collate_ucode ? data + data_size : (char *)blob + fdt_size) -
|
||||
image;
|
||||
}
|
||||
|
||||
/**
|
||||
* write_uboot() - Write U-Boot, device tree and microcode pointer
|
||||
*
|
||||
* This writes U-Boot into a place in the flash, followed by its device tree.
|
||||
* The microcode pointer is written so that U-Boot can find the microcode in
|
||||
* the device tree very early in boot.
|
||||
*
|
||||
* @image: Pointer to image
|
||||
* @size: Size of image in bytes
|
||||
* @uboot: Input file information for u-boot.bin
|
||||
* @fdt: Input file information for u-boot.dtb
|
||||
* @ucode_ptr: Address in U-Boot where the microcode pointer should be placed
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
static int write_uboot(char *image, int size, struct input_file *uboot,
|
||||
struct input_file *fdt, unsigned int ucode_ptr,
|
||||
int collate_ucode, int *offset_uboot_top,
|
||||
int *offset_uboot_start)
|
||||
{
|
||||
int uboot_size, fdt_size;
|
||||
int uboot_top;
|
||||
|
||||
uboot_size = write_data(image, size, uboot->addr, uboot->fname, 0, 0);
|
||||
if (uboot_size < 0)
|
||||
return uboot_size;
|
||||
fdt->addr = uboot->addr + uboot_size;
|
||||
debug("U-Boot size %#x, FDT at %#x\n", uboot_size, fdt->addr);
|
||||
fdt_size = write_data(image, size, fdt->addr, fdt->fname, 0, 0);
|
||||
if (fdt_size < 0)
|
||||
return fdt_size;
|
||||
|
||||
uboot_top = (uint32_t)(fdt->addr + size) + fdt_size;
|
||||
|
||||
if (ucode_ptr) {
|
||||
uboot_top = write_ucode(image, size, fdt, fdt_size, ucode_ptr,
|
||||
collate_ucode);
|
||||
if (uboot_top < 0)
|
||||
return uboot_top;
|
||||
}
|
||||
|
||||
if (offset_uboot_top && offset_uboot_start) {
|
||||
*offset_uboot_top = uboot_top;
|
||||
*offset_uboot_start = (uint32_t)(uboot->addr + size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_version(void)
|
||||
{
|
||||
printf("ifdtool v%s -- ", IFDTOOL_VERSION);
|
||||
|
@ -1034,7 +814,7 @@ int main(int argc, char *argv[])
|
|||
int mode_dump = 0, mode_extract = 0, mode_inject = 0;
|
||||
int mode_spifreq = 0, mode_em100 = 0, mode_locked = 0;
|
||||
int mode_unlocked = 0, mode_write = 0, mode_write_descriptor = 0;
|
||||
int create = 0, collate_ucode = 0;
|
||||
int create = 0;
|
||||
char *region_type_string = NULL, *inject_fname = NULL;
|
||||
char *desc_fname = NULL, *addr_str = NULL;
|
||||
int region_type = -1, inputfreq = 0;
|
||||
|
@ -1047,14 +827,12 @@ int main(int argc, char *argv[])
|
|||
char *outfile = NULL;
|
||||
struct stat buf;
|
||||
int size = 0;
|
||||
unsigned int ucode_ptr = 0;
|
||||
bool have_uboot = false;
|
||||
int bios_fd;
|
||||
char *image;
|
||||
int ret;
|
||||
static struct option long_options[] = {
|
||||
{"create", 0, NULL, 'c'},
|
||||
{"collate-microcode", 0, NULL, 'C'},
|
||||
{"dump", 0, NULL, 'd'},
|
||||
{"descriptor", 1, NULL, 'D'},
|
||||
{"em100", 0, NULL, 'e'},
|
||||
|
@ -1062,7 +840,6 @@ int main(int argc, char *argv[])
|
|||
{"fdt", 1, NULL, 'f'},
|
||||
{"inject", 1, NULL, 'i'},
|
||||
{"lock", 0, NULL, 'l'},
|
||||
{"microcode", 1, NULL, 'm'},
|
||||
{"romsize", 1, NULL, 'r'},
|
||||
{"spifreq", 1, NULL, 's'},
|
||||
{"unlock", 0, NULL, 'u'},
|
||||
|
@ -1073,15 +850,12 @@ int main(int argc, char *argv[])
|
|||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "cCdD:ef:hi:lm:r:s:uU:vw:x?",
|
||||
while ((opt = getopt_long(argc, argv, "cdD:ef:hi:lr:s:uU:vw:x?",
|
||||
long_options, &option_index)) != EOF) {
|
||||
switch (opt) {
|
||||
case 'c':
|
||||
create = 1;
|
||||
break;
|
||||
case 'C':
|
||||
collate_ucode = 1;
|
||||
break;
|
||||
case 'd':
|
||||
mode_dump = 1;
|
||||
break;
|
||||
|
@ -1119,9 +893,6 @@ int main(int argc, char *argv[])
|
|||
case 'l':
|
||||
mode_locked = 1;
|
||||
break;
|
||||
case 'm':
|
||||
ucode_ptr = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'r':
|
||||
rom_size = strtol(optarg, NULL, 0);
|
||||
debug("ROM size %d\n", rom_size);
|
||||
|
@ -1166,12 +937,6 @@ int main(int argc, char *argv[])
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
ifile->addr = strtoll(optarg, NULL, 0);
|
||||
ifile->type = opt == 'f' ? IF_fdt :
|
||||
opt == 'U' ? IF_uboot : IF_normal;
|
||||
if (ifile->type == IF_fdt)
|
||||
fdt = ifile;
|
||||
else if (ifile->type == IF_uboot)
|
||||
have_uboot = true;
|
||||
wr_num++;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
|
@ -1302,18 +1067,9 @@ int main(int argc, char *argv[])
|
|||
|
||||
for (wr_idx = 0; wr_idx < wr_num; wr_idx++) {
|
||||
ifile = &input_file[wr_idx];
|
||||
if (ifile->type == IF_fdt) {
|
||||
continue;
|
||||
} else if (ifile->type == IF_uboot) {
|
||||
ret = write_uboot(image, size, ifile, fdt,
|
||||
ucode_ptr, collate_ucode,
|
||||
&offset_uboot_top,
|
||||
&offset_uboot_start);
|
||||
} else {
|
||||
ret = write_data(image, size, ifile->addr,
|
||||
ifile->fname, offset_uboot_top,
|
||||
offset_uboot_start);
|
||||
}
|
||||
ret = write_data(image, size, ifile->addr,
|
||||
ifile->fname, offset_uboot_top,
|
||||
offset_uboot_start);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue