mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-06-28 09:31:32 +00:00
Merge git://git.denx.de/u-boot-dm
This commit is contained in:
commit
d24c1d0f4d
97 changed files with 3211 additions and 199 deletions
|
@ -27,6 +27,7 @@ addons:
|
||||||
- wget
|
- wget
|
||||||
- device-tree-compiler
|
- device-tree-compiler
|
||||||
- lzop
|
- lzop
|
||||||
|
- liblz4-tool
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
|
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
gdsys Gazerbeam board driver
|
||||||
|
|
||||||
|
This driver provides capabilities to access the gdsys Gazerbeam board's device
|
||||||
|
information. Furthermore, phandles to some internal devices are provided for
|
||||||
|
the board files.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: should be "gdsys,board_gazerbeam"
|
||||||
|
- csb: phandle to the board's coherent system bus (CSB) device node
|
||||||
|
- rxaui[0-3]: phandles to the rxaui control device nodes
|
||||||
|
- fpga[0-1]: phandles to the board's gdsys FPGA device nodes
|
||||||
|
- ioep[0-1]: phandles to the board's IO endpoint device nodes
|
||||||
|
- ver-gpios: GPIO list to read the hardware version from
|
||||||
|
- var-gpios: GPIO list to read the hardware variant information from
|
||||||
|
- reset-gpios: GPIO list for the board's reset GPIOs
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
|
||||||
|
board {
|
||||||
|
compatible = "gdsys,board_gazerbeam";
|
||||||
|
csb = <&board_soc>;
|
||||||
|
serdes = <&SERDES>;
|
||||||
|
rxaui0 = <&RXAUI0>;
|
||||||
|
rxaui1 = <&RXAUI1>;
|
||||||
|
rxaui2 = <&RXAUI2>;
|
||||||
|
rxaui3 = <&RXAUI3>;
|
||||||
|
fpga0 = <&FPGA0>;
|
||||||
|
fpga1 = <&FPGA1>;
|
||||||
|
ioep0 = <&IOEP0>;
|
||||||
|
ioep1 = <&IOEP1>;
|
||||||
|
|
||||||
|
ver-gpios = <&PPCPCA 12 0
|
||||||
|
&PPCPCA 13 0
|
||||||
|
&PPCPCA 14 0
|
||||||
|
&PPCPCA 15 0>;
|
||||||
|
|
||||||
|
/* MC2/SC-Board */
|
||||||
|
var-gpios-mc2 = <&GPIO_VB0 0 0 /* VAR-MC_SC */
|
||||||
|
&GPIO_VB0 11 0>; /* VAR-CON */
|
||||||
|
/* MC4-Board */
|
||||||
|
var-gpios-mc4 = <&GPIO_VB1 0 0 /* VAR-MC_SC */
|
||||||
|
&GPIO_VB1 11 0>; /* VAR-CON */
|
||||||
|
|
||||||
|
reset-gpios = <&gpio0 1 0 &gpio0 2 1>;
|
||||||
|
};
|
|
@ -89,6 +89,7 @@ config SANDBOX
|
||||||
imply CMD_SF_TEST
|
imply CMD_SF_TEST
|
||||||
imply CRC32_VERIFY
|
imply CRC32_VERIFY
|
||||||
imply FAT_WRITE
|
imply FAT_WRITE
|
||||||
|
imply FIRMWARE
|
||||||
imply HASH_VERIFY
|
imply HASH_VERIFY
|
||||||
imply LZMA
|
imply LZMA
|
||||||
imply SCSI
|
imply SCSI
|
||||||
|
|
|
@ -191,6 +191,12 @@
|
||||||
fake-host-hwaddr = [00 00 66 44 22 22];
|
fake-host-hwaddr = [00 00 66 44 22 22];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
firmware {
|
||||||
|
sandbox_firmware: sandbox-firmware {
|
||||||
|
compatible = "sandbox,firmware";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
gpio_a: base-gpios {
|
gpio_a: base-gpios {
|
||||||
compatible = "sandbox,gpio";
|
compatible = "sandbox,gpio";
|
||||||
gpio-controller;
|
gpio-controller;
|
||||||
|
@ -647,6 +653,10 @@
|
||||||
osd {
|
osd {
|
||||||
compatible = "sandbox,sandbox_osd";
|
compatible = "sandbox,sandbox_osd";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
board {
|
||||||
|
compatible = "sandbox,board_sandbox";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "sandbox_pmic.dtsi"
|
#include "sandbox_pmic.dtsi"
|
||||||
|
|
|
@ -193,6 +193,30 @@ device are supported.
|
||||||
Also sandbox supports driver model (CONFIG_DM) and associated commands.
|
Also sandbox supports driver model (CONFIG_DM) and associated commands.
|
||||||
|
|
||||||
|
|
||||||
|
Sandbox Variants
|
||||||
|
----------------
|
||||||
|
|
||||||
|
There are unfortunately quite a few variants at present:
|
||||||
|
|
||||||
|
sandbox - should be used for most tests
|
||||||
|
sandbox64 - special build that forces a 64-bit host
|
||||||
|
sandbox_flattree - builds with dev_read_...() functions defined as inline.
|
||||||
|
We need this build so that we can test those inline functions, and we
|
||||||
|
cannot build with both the inline functions and the non-inline functions
|
||||||
|
since they are named the same.
|
||||||
|
sandbox_noblk - builds without CONFIG_BLK, which means the legacy block
|
||||||
|
drivers are used. We cannot use both the legacy and driver-model block
|
||||||
|
drivers since they implement the same functions
|
||||||
|
sandbox_spl - builds sandbox with SPL support, so you can run spl/u-boot-spl
|
||||||
|
and it will start up and then load ./u-boot. It is also possible to
|
||||||
|
run ./u-boot directly.
|
||||||
|
|
||||||
|
Of these sandbox_noblk can be removed once CONFIG_BLK is used everwhere, and
|
||||||
|
sandbox_spl can probably be removed since it is a superset of sandbox.
|
||||||
|
|
||||||
|
Most of the config options should be identical between these variants.
|
||||||
|
|
||||||
|
|
||||||
Linux RAW Networking Bridge
|
Linux RAW Networking Bridge
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
|
|
37
cmd/clk.c
37
cmd/clk.c
|
@ -5,11 +5,48 @@
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <command.h>
|
#include <command.h>
|
||||||
#include <clk.h>
|
#include <clk.h>
|
||||||
|
#if defined(CONFIG_DM) && defined(CONFIG_CLK)
|
||||||
|
#include <dm.h>
|
||||||
|
#include <dm/device-internal.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
int __weak soc_clk_dump(void)
|
int __weak soc_clk_dump(void)
|
||||||
{
|
{
|
||||||
|
#if defined(CONFIG_DM) && defined(CONFIG_CLK)
|
||||||
|
struct udevice *dev;
|
||||||
|
struct uclass *uc;
|
||||||
|
struct clk clk;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Device addresses start at 1 */
|
||||||
|
ret = uclass_get(UCLASS_CLK, &uc);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
uclass_foreach_dev(dev, uc) {
|
||||||
|
memset(&clk, 0, sizeof(clk));
|
||||||
|
ret = device_probe(dev);
|
||||||
|
if (ret) {
|
||||||
|
printf("%-30.30s : ? Hz\n", dev->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = clk_request(dev, &clk);
|
||||||
|
if (ret) {
|
||||||
|
printf("%-30.30s : ? Hz\n", dev->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%-30.30s : %lu Hz\n", dev->name, clk_get_rate(&clk));
|
||||||
|
|
||||||
|
clk_free(&clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
puts("Not implemented\n");
|
puts("Not implemented\n");
|
||||||
return 1;
|
return 1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_clk_dump(cmd_tbl_t *cmdtp, int flag, int argc,
|
static int do_clk_dump(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||||
|
|
|
@ -87,6 +87,8 @@ CONFIG_CPU=y
|
||||||
CONFIG_DM_DEMO=y
|
CONFIG_DM_DEMO=y
|
||||||
CONFIG_DM_DEMO_SIMPLE=y
|
CONFIG_DM_DEMO_SIMPLE=y
|
||||||
CONFIG_DM_DEMO_SHAPE=y
|
CONFIG_DM_DEMO_SHAPE=y
|
||||||
|
CONFIG_BOARD=y
|
||||||
|
CONFIG_BOARD_SANDBOX=y
|
||||||
CONFIG_PM8916_GPIO=y
|
CONFIG_PM8916_GPIO=y
|
||||||
CONFIG_SANDBOX_GPIO=y
|
CONFIG_SANDBOX_GPIO=y
|
||||||
CONFIG_DM_I2C_COMPAT=y
|
CONFIG_DM_I2C_COMPAT=y
|
||||||
|
|
|
@ -92,6 +92,8 @@ CONFIG_CPU=y
|
||||||
CONFIG_DM_DEMO=y
|
CONFIG_DM_DEMO=y
|
||||||
CONFIG_DM_DEMO_SIMPLE=y
|
CONFIG_DM_DEMO_SIMPLE=y
|
||||||
CONFIG_DM_DEMO_SHAPE=y
|
CONFIG_DM_DEMO_SHAPE=y
|
||||||
|
CONFIG_BOARD=y
|
||||||
|
CONFIG_BOARD_SANDBOX=y
|
||||||
CONFIG_PM8916_GPIO=y
|
CONFIG_PM8916_GPIO=y
|
||||||
CONFIG_SANDBOX_GPIO=y
|
CONFIG_SANDBOX_GPIO=y
|
||||||
CONFIG_DM_I2C_COMPAT=y
|
CONFIG_DM_I2C_COMPAT=y
|
||||||
|
|
|
@ -71,6 +71,8 @@ CONFIG_CPU=y
|
||||||
CONFIG_DM_DEMO=y
|
CONFIG_DM_DEMO=y
|
||||||
CONFIG_DM_DEMO_SIMPLE=y
|
CONFIG_DM_DEMO_SIMPLE=y
|
||||||
CONFIG_DM_DEMO_SHAPE=y
|
CONFIG_DM_DEMO_SHAPE=y
|
||||||
|
CONFIG_BOARD=y
|
||||||
|
CONFIG_BOARD_SANDBOX=y
|
||||||
CONFIG_PM8916_GPIO=y
|
CONFIG_PM8916_GPIO=y
|
||||||
CONFIG_SANDBOX_GPIO=y
|
CONFIG_SANDBOX_GPIO=y
|
||||||
CONFIG_DM_I2C_COMPAT=y
|
CONFIG_DM_I2C_COMPAT=y
|
||||||
|
|
|
@ -78,6 +78,8 @@ CONFIG_CPU=y
|
||||||
CONFIG_DM_DEMO=y
|
CONFIG_DM_DEMO=y
|
||||||
CONFIG_DM_DEMO_SIMPLE=y
|
CONFIG_DM_DEMO_SIMPLE=y
|
||||||
CONFIG_DM_DEMO_SHAPE=y
|
CONFIG_DM_DEMO_SHAPE=y
|
||||||
|
CONFIG_BOARD=y
|
||||||
|
CONFIG_BOARD_SANDBOX=y
|
||||||
CONFIG_PM8916_GPIO=y
|
CONFIG_PM8916_GPIO=y
|
||||||
CONFIG_SANDBOX_GPIO=y
|
CONFIG_SANDBOX_GPIO=y
|
||||||
CONFIG_DM_I2C_COMPAT=y
|
CONFIG_DM_I2C_COMPAT=y
|
||||||
|
|
|
@ -92,6 +92,8 @@ CONFIG_CPU=y
|
||||||
CONFIG_DM_DEMO=y
|
CONFIG_DM_DEMO=y
|
||||||
CONFIG_DM_DEMO_SIMPLE=y
|
CONFIG_DM_DEMO_SIMPLE=y
|
||||||
CONFIG_DM_DEMO_SHAPE=y
|
CONFIG_DM_DEMO_SHAPE=y
|
||||||
|
CONFIG_BOARD=y
|
||||||
|
CONFIG_BOARD_SANDBOX=y
|
||||||
CONFIG_PM8916_GPIO=y
|
CONFIG_PM8916_GPIO=y
|
||||||
CONFIG_SANDBOX_GPIO=y
|
CONFIG_SANDBOX_GPIO=y
|
||||||
CONFIG_DM_I2C_COMPAT=y
|
CONFIG_DM_I2C_COMPAT=y
|
||||||
|
|
|
@ -24,6 +24,8 @@ source "drivers/ddr/Kconfig"
|
||||||
|
|
||||||
source "drivers/demo/Kconfig"
|
source "drivers/demo/Kconfig"
|
||||||
|
|
||||||
|
source "drivers/board/Kconfig"
|
||||||
|
|
||||||
source "drivers/ddr/fsl/Kconfig"
|
source "drivers/ddr/fsl/Kconfig"
|
||||||
|
|
||||||
source "drivers/dfu/Kconfig"
|
source "drivers/dfu/Kconfig"
|
||||||
|
|
|
@ -71,6 +71,7 @@ obj-y += ata/
|
||||||
obj-$(CONFIG_DM_DEMO) += demo/
|
obj-$(CONFIG_DM_DEMO) += demo/
|
||||||
obj-$(CONFIG_BIOSEMU) += bios_emulator/
|
obj-$(CONFIG_BIOSEMU) += bios_emulator/
|
||||||
obj-y += block/
|
obj-y += block/
|
||||||
|
obj-y += board/
|
||||||
obj-$(CONFIG_BOOTCOUNT_LIMIT) += bootcount/
|
obj-$(CONFIG_BOOTCOUNT_LIMIT) += bootcount/
|
||||||
obj-$(CONFIG_CPU) += cpu/
|
obj-$(CONFIG_CPU) += cpu/
|
||||||
obj-y += crypto/
|
obj-y += crypto/
|
||||||
|
|
22
drivers/board/Kconfig
Normal file
22
drivers/board/Kconfig
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
menuconfig BOARD
|
||||||
|
bool "Device Information"
|
||||||
|
help
|
||||||
|
Support methods to query hardware configurations from internal
|
||||||
|
mechanisms (e.g. reading GPIO values, determining the presence of
|
||||||
|
devices on busses, etc.). This enables the usage of U-Boot with
|
||||||
|
modular board architectures.
|
||||||
|
|
||||||
|
if BOARD
|
||||||
|
|
||||||
|
|
||||||
|
config BOARD_GAZERBEAM
|
||||||
|
bool "Enable board driver for the Gazerbeam board"
|
||||||
|
help
|
||||||
|
Support querying device information for the gdsys Gazerbeam board.
|
||||||
|
|
||||||
|
config BOARD_SANDBOX
|
||||||
|
bool "Enable board driver for the Sandbox board"
|
||||||
|
help
|
||||||
|
Support querying device information for the Sandbox boards.
|
||||||
|
|
||||||
|
endif
|
7
drivers/board/Makefile
Normal file
7
drivers/board/Makefile
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
#
|
||||||
|
# (C) Copyright 2017
|
||||||
|
# Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||||
|
obj-$(CONFIG_BOARD) += board-uclass.o
|
||||||
|
obj-$(CONFIG_BOARD_GAZERBEAM) += gazerbeam.o
|
||||||
|
obj-$(CONFIG_BOARD_SANDBOX) += sandbox.o
|
60
drivers/board/board-uclass.c
Normal file
60
drivers/board/board-uclass.c
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* (C) Copyright 2017
|
||||||
|
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <dm.h>
|
||||||
|
#include <board.h>
|
||||||
|
|
||||||
|
int board_get(struct udevice **devp)
|
||||||
|
{
|
||||||
|
return uclass_first_device_err(UCLASS_BOARD, devp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int board_detect(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct board_ops *ops = board_get_ops(dev);
|
||||||
|
|
||||||
|
if (!ops->detect)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return ops->detect(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
int board_get_bool(struct udevice *dev, int id, bool *val)
|
||||||
|
{
|
||||||
|
struct board_ops *ops = board_get_ops(dev);
|
||||||
|
|
||||||
|
if (!ops->get_bool)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return ops->get_bool(dev, id, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
int board_get_int(struct udevice *dev, int id, int *val)
|
||||||
|
{
|
||||||
|
struct board_ops *ops = board_get_ops(dev);
|
||||||
|
|
||||||
|
if (!ops->get_int)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return ops->get_int(dev, id, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
int board_get_str(struct udevice *dev, int id, size_t size, char *val)
|
||||||
|
{
|
||||||
|
struct board_ops *ops = board_get_ops(dev);
|
||||||
|
|
||||||
|
if (!ops->get_str)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return ops->get_str(dev, id, size, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
UCLASS_DRIVER(board) = {
|
||||||
|
.id = UCLASS_BOARD,
|
||||||
|
.name = "board",
|
||||||
|
.post_bind = dm_scan_fdt_dev,
|
||||||
|
};
|
262
drivers/board/gazerbeam.c
Normal file
262
drivers/board/gazerbeam.c
Normal file
|
@ -0,0 +1,262 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* (C) Copyright 2017
|
||||||
|
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <dm.h>
|
||||||
|
#include <board.h>
|
||||||
|
#include <i2c.h>
|
||||||
|
#include <asm/gpio.h>
|
||||||
|
|
||||||
|
#include "gazerbeam.h"
|
||||||
|
|
||||||
|
/* Sequence number of I2C bus that holds the GPIO expanders */
|
||||||
|
static const int I2C_BUS_SEQ_NO = 1;
|
||||||
|
|
||||||
|
/* I2C address of SC/MC2 expander */
|
||||||
|
static const int MC2_EXPANDER_ADDR = 0x20;
|
||||||
|
/* I2C address of MC4 expander */
|
||||||
|
static const int MC4_EXPANDER_ADDR = 0x22;
|
||||||
|
|
||||||
|
/* Number of the GPIO to read the SC data from */
|
||||||
|
static const int SC_GPIO_NO;
|
||||||
|
/* Number of the GPIO to read the CON data from */
|
||||||
|
static const int CON_GPIO_NO = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct board_gazerbeam_priv - Private data structure for the gazerbeam board
|
||||||
|
* driver.
|
||||||
|
* @reset_gpios: GPIOs for the board's reset GPIOs.
|
||||||
|
* @var_gpios: GPIOs for the board's hardware variant GPIOs
|
||||||
|
* @ver_gpios: GPIOs for the board's hardware version GPIOs
|
||||||
|
* @variant: Container for the board's hardware variant (CON/CPU)
|
||||||
|
* @multichannel: Container for the board's multichannel variant (MC4/MC2/SC)
|
||||||
|
* @hwversion: Container for the board's hardware version
|
||||||
|
*/
|
||||||
|
struct board_gazerbeam_priv {
|
||||||
|
struct gpio_desc reset_gpios[2];
|
||||||
|
struct gpio_desc var_gpios[2];
|
||||||
|
struct gpio_desc ver_gpios[4];
|
||||||
|
int variant;
|
||||||
|
int multichannel;
|
||||||
|
int hwversion;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _read_board_variant_data() - Read variant information from the hardware.
|
||||||
|
* @dev: The board device for which to determine the multichannel and device
|
||||||
|
* type information.
|
||||||
|
*
|
||||||
|
* The data read from the board's hardware (mostly hard-wired GPIOs) is stored
|
||||||
|
* in the private data structure of the driver to be used by other driver
|
||||||
|
* methods.
|
||||||
|
*
|
||||||
|
* Return: 0 if OK, -ve on error.
|
||||||
|
*/
|
||||||
|
static int _read_board_variant_data(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct board_gazerbeam_priv *priv = dev_get_priv(dev);
|
||||||
|
struct udevice *i2c_bus;
|
||||||
|
struct udevice *dummy;
|
||||||
|
char *listname;
|
||||||
|
int mc4, mc2, sc, con;
|
||||||
|
int gpio_num;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = uclass_get_device_by_seq(UCLASS_I2C, I2C_BUS_SEQ_NO, &i2c_bus);
|
||||||
|
if (res) {
|
||||||
|
debug("%s: Could not get I2C bus %d (err = %d)\n",
|
||||||
|
dev->name, I2C_BUS_SEQ_NO, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!i2c_bus) {
|
||||||
|
debug("%s: Could not get I2C bus %d\n",
|
||||||
|
dev->name, I2C_BUS_SEQ_NO);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
mc2 = !dm_i2c_probe(i2c_bus, MC2_EXPANDER_ADDR, 0, &dummy);
|
||||||
|
mc4 = !dm_i2c_probe(i2c_bus, MC4_EXPANDER_ADDR, 0, &dummy);
|
||||||
|
|
||||||
|
if (mc2 && mc4) {
|
||||||
|
debug("%s: Board hardware configuration inconsistent.\n",
|
||||||
|
dev->name);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
listname = mc2 ? "var-gpios-mc2" : "var-gpios-mc4";
|
||||||
|
|
||||||
|
gpio_num = gpio_request_list_by_name(dev, listname, priv->var_gpios,
|
||||||
|
ARRAY_SIZE(priv->var_gpios),
|
||||||
|
GPIOD_IS_IN);
|
||||||
|
if (gpio_num < 0) {
|
||||||
|
debug("%s: Requesting gpio list %s failed (err = %d).\n",
|
||||||
|
dev->name, listname, gpio_num);
|
||||||
|
return gpio_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc = dm_gpio_get_value(&priv->var_gpios[SC_GPIO_NO]);
|
||||||
|
if (sc < 0) {
|
||||||
|
debug("%s: Error while reading 'sc' GPIO (err = %d)",
|
||||||
|
dev->name, sc);
|
||||||
|
return sc;
|
||||||
|
}
|
||||||
|
|
||||||
|
con = dm_gpio_get_value(&priv->var_gpios[CON_GPIO_NO]);
|
||||||
|
if (con < 0) {
|
||||||
|
debug("%s: Error while reading 'con' GPIO (err = %d)",
|
||||||
|
dev->name, con);
|
||||||
|
return con;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sc && mc2) || (sc && mc4) || (!sc && !mc2 && !mc4)) {
|
||||||
|
debug("%s: Board hardware configuration inconsistent.\n",
|
||||||
|
dev->name);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->variant = con ? VAR_CON : VAR_CPU;
|
||||||
|
|
||||||
|
priv->multichannel = mc4 ? 4 : (mc2 ? 2 : (sc ? 1 : 0));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _read_hwversion() - Read the hardware version from the board.
|
||||||
|
* @dev: The board device for which to read the hardware version.
|
||||||
|
*
|
||||||
|
* The hardware version read from the board (from hard-wired GPIOs) is stored
|
||||||
|
* in the private data structure of the driver to be used by other driver
|
||||||
|
* methods.
|
||||||
|
*
|
||||||
|
* Return: 0 if OK, -ve on error.
|
||||||
|
*/
|
||||||
|
static int _read_hwversion(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct board_gazerbeam_priv *priv = dev_get_priv(dev);
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = gpio_request_list_by_name(dev, "ver-gpios", priv->ver_gpios,
|
||||||
|
ARRAY_SIZE(priv->ver_gpios),
|
||||||
|
GPIOD_IS_IN);
|
||||||
|
if (res < 0) {
|
||||||
|
debug("%s: Error getting GPIO list 'ver-gpios' (err = %d)\n",
|
||||||
|
dev->name, res);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = dm_gpio_get_values_as_int(priv->ver_gpios,
|
||||||
|
ARRAY_SIZE(priv->ver_gpios));
|
||||||
|
if (res < 0) {
|
||||||
|
debug("%s: Error reading HW version from expander (err = %d)\n",
|
||||||
|
dev->name, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->hwversion = res;
|
||||||
|
|
||||||
|
res = gpio_free_list(dev, priv->ver_gpios, ARRAY_SIZE(priv->ver_gpios));
|
||||||
|
if (res < 0) {
|
||||||
|
debug("%s: Error freeing HW version GPIO list (err = %d)\n",
|
||||||
|
dev->name, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int board_gazerbeam_detect(struct udevice *dev)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = _read_board_variant_data(dev);
|
||||||
|
if (res) {
|
||||||
|
debug("%s: Error reading multichannel variant (err = %d)\n",
|
||||||
|
dev->name, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = _read_hwversion(dev);
|
||||||
|
if (res) {
|
||||||
|
debug("%s: Error reading hardware version (err = %d)\n",
|
||||||
|
dev->name, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int board_gazerbeam_get_int(struct udevice *dev, int id, int *val)
|
||||||
|
{
|
||||||
|
struct board_gazerbeam_priv *priv = dev_get_priv(dev);
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case BOARD_MULTICHANNEL:
|
||||||
|
*val = priv->multichannel;
|
||||||
|
break;
|
||||||
|
case BOARD_VARIANT:
|
||||||
|
*val = priv->variant;
|
||||||
|
break;
|
||||||
|
case BOARD_HWVERSION:
|
||||||
|
*val = priv->hwversion;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
debug("%s: Integer value %d unknown\n", dev->name, id);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct udevice_id board_gazerbeam_ids[] = {
|
||||||
|
{ .compatible = "gdsys,board_gazerbeam" },
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct board_ops board_gazerbeam_ops = {
|
||||||
|
.detect = board_gazerbeam_detect,
|
||||||
|
.get_int = board_gazerbeam_get_int,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int board_gazerbeam_probe(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct board_gazerbeam_priv *priv = dev_get_priv(dev);
|
||||||
|
int gpio_num, i;
|
||||||
|
|
||||||
|
gpio_num = gpio_request_list_by_name(dev, "reset-gpios",
|
||||||
|
priv->reset_gpios,
|
||||||
|
ARRAY_SIZE(priv->reset_gpios),
|
||||||
|
GPIOD_IS_OUT);
|
||||||
|
|
||||||
|
if (gpio_num < 0) {
|
||||||
|
debug("%s: Error getting GPIO list 'reset-gpios' (err = %d)\n",
|
||||||
|
dev->name, gpio_num);
|
||||||
|
return gpio_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set startup-finished GPIOs */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(priv->reset_gpios); i++) {
|
||||||
|
int res = dm_gpio_set_value(&priv->reset_gpios[i], 0);
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
debug("%s: Error while setting GPIO %d (err = %d)\n",
|
||||||
|
dev->name, i, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
U_BOOT_DRIVER(board_gazerbeam) = {
|
||||||
|
.name = "board_gazerbeam",
|
||||||
|
.id = UCLASS_BOARD,
|
||||||
|
.of_match = board_gazerbeam_ids,
|
||||||
|
.ops = &board_gazerbeam_ops,
|
||||||
|
.priv_auto_alloc_size = sizeof(struct board_gazerbeam_priv),
|
||||||
|
.probe = board_gazerbeam_probe,
|
||||||
|
};
|
18
drivers/board/gazerbeam.h
Normal file
18
drivers/board/gazerbeam.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||||
|
/*
|
||||||
|
* (C) Copyright 2017
|
||||||
|
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0+
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BOARD_MULTICHANNEL,
|
||||||
|
BOARD_VARIANT,
|
||||||
|
BOARD_HWVERSION,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
VAR_CON,
|
||||||
|
VAR_CPU,
|
||||||
|
};
|
107
drivers/board/sandbox.c
Normal file
107
drivers/board/sandbox.c
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* (C) Copyright 2018
|
||||||
|
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <dm.h>
|
||||||
|
#include <board.h>
|
||||||
|
|
||||||
|
#include "sandbox.h"
|
||||||
|
|
||||||
|
struct board_sandbox_priv {
|
||||||
|
bool called_detect;
|
||||||
|
int test_i1;
|
||||||
|
int test_i2;
|
||||||
|
};
|
||||||
|
|
||||||
|
char vacation_spots[][64] = {"R'lyeh", "Dreamlands", "Plateau of Leng",
|
||||||
|
"Carcosa", "Yuggoth", "The Nameless City"};
|
||||||
|
|
||||||
|
int board_sandbox_detect(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct board_sandbox_priv *priv = dev_get_priv(dev);
|
||||||
|
|
||||||
|
priv->called_detect = true;
|
||||||
|
priv->test_i2 = 100;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int board_sandbox_get_bool(struct udevice *dev, int id, bool *val)
|
||||||
|
{
|
||||||
|
struct board_sandbox_priv *priv = dev_get_priv(dev);
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case BOOL_CALLED_DETECT:
|
||||||
|
/* Checks if the dectect method has been called */
|
||||||
|
*val = priv->called_detect;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int board_sandbox_get_int(struct udevice *dev, int id, int *val)
|
||||||
|
{
|
||||||
|
struct board_sandbox_priv *priv = dev_get_priv(dev);
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case INT_TEST1:
|
||||||
|
*val = priv->test_i1;
|
||||||
|
/* Increments with every call */
|
||||||
|
priv->test_i1++;
|
||||||
|
return 0;
|
||||||
|
case INT_TEST2:
|
||||||
|
*val = priv->test_i2;
|
||||||
|
/* Decrements with every call */
|
||||||
|
priv->test_i2--;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int board_sandbox_get_str(struct udevice *dev, int id, size_t size, char *val)
|
||||||
|
{
|
||||||
|
struct board_sandbox_priv *priv = dev_get_priv(dev);
|
||||||
|
int i1 = priv->test_i1;
|
||||||
|
int i2 = priv->test_i2;
|
||||||
|
int index = (i1 * i2) % ARRAY_SIZE(vacation_spots);
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case STR_VACATIONSPOT:
|
||||||
|
/* Picks a vacation spot depending on i1 and i2 */
|
||||||
|
snprintf(val, size, vacation_spots[index]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct udevice_id board_sandbox_ids[] = {
|
||||||
|
{ .compatible = "sandbox,board_sandbox" },
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct board_ops board_sandbox_ops = {
|
||||||
|
.detect = board_sandbox_detect,
|
||||||
|
.get_bool = board_sandbox_get_bool,
|
||||||
|
.get_int = board_sandbox_get_int,
|
||||||
|
.get_str = board_sandbox_get_str,
|
||||||
|
};
|
||||||
|
|
||||||
|
int board_sandbox_probe(struct udevice *dev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
U_BOOT_DRIVER(board_sandbox) = {
|
||||||
|
.name = "board_sandbox",
|
||||||
|
.id = UCLASS_BOARD,
|
||||||
|
.of_match = board_sandbox_ids,
|
||||||
|
.ops = &board_sandbox_ops,
|
||||||
|
.priv_auto_alloc_size = sizeof(struct board_sandbox_priv),
|
||||||
|
.probe = board_sandbox_probe,
|
||||||
|
};
|
12
drivers/board/sandbox.h
Normal file
12
drivers/board/sandbox.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||||
|
/*
|
||||||
|
* (C) Copyright 2018
|
||||||
|
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BOOL_CALLED_DETECT,
|
||||||
|
INT_TEST1,
|
||||||
|
INT_TEST2,
|
||||||
|
STR_VACATIONSPOT,
|
||||||
|
};
|
|
@ -516,6 +516,33 @@ static int device_get_device_tail(struct udevice *dev, int ret,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* device_find_by_ofnode() - Return device associated with given ofnode
|
||||||
|
*
|
||||||
|
* The returned device is *not* activated.
|
||||||
|
*
|
||||||
|
* @node: The ofnode for which a associated device should be looked up
|
||||||
|
* @devp: Pointer to structure to hold the found device
|
||||||
|
* Return: 0 if OK, -ve on error
|
||||||
|
*/
|
||||||
|
static int device_find_by_ofnode(ofnode node, struct udevice **devp)
|
||||||
|
{
|
||||||
|
struct uclass *uc;
|
||||||
|
struct udevice *dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
list_for_each_entry(uc, &gd->uclass_root, sibling_node) {
|
||||||
|
ret = uclass_find_device_by_ofnode(uc->uc_drv->id, node,
|
||||||
|
&dev);
|
||||||
|
if (!ret || dev) {
|
||||||
|
*devp = dev;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
int device_get_child(struct udevice *parent, int index, struct udevice **devp)
|
int device_get_child(struct udevice *parent, int index, struct udevice **devp)
|
||||||
{
|
{
|
||||||
struct udevice *dev;
|
struct udevice *dev;
|
||||||
|
@ -739,3 +766,54 @@ bool of_machine_is_compatible(const char *compat)
|
||||||
|
|
||||||
return !fdt_node_check_compatible(fdt, 0, compat);
|
return !fdt_node_check_compatible(fdt, 0, compat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dev_disable_by_path(const char *path)
|
||||||
|
{
|
||||||
|
struct uclass *uc;
|
||||||
|
ofnode node = ofnode_path(path);
|
||||||
|
struct udevice *dev;
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
if (!of_live_active())
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
list_for_each_entry(uc, &gd->uclass_root, sibling_node) {
|
||||||
|
ret = uclass_find_device_by_ofnode(uc->uc_drv->id, node, &dev);
|
||||||
|
if (!ret)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = device_remove(dev, DM_REMOVE_NORMAL);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = device_unbind(dev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return ofnode_set_enabled(node, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dev_enable_by_path(const char *path)
|
||||||
|
{
|
||||||
|
ofnode node = ofnode_path(path);
|
||||||
|
ofnode pnode = ofnode_get_parent(node);
|
||||||
|
struct udevice *parent;
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
if (!of_live_active())
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
ret = device_find_by_ofnode(pnode, &parent);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = ofnode_set_enabled(node, true);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return lists_bind_fdt(parent, node, NULL);
|
||||||
|
}
|
||||||
|
|
|
@ -791,3 +791,73 @@ ofnode ofnode_by_prop_value(ofnode from, const char *propname,
|
||||||
propname, propval, proplen));
|
propname, propval, proplen));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ofnode_write_prop(ofnode node, const char *propname, int len,
|
||||||
|
const void *value)
|
||||||
|
{
|
||||||
|
const struct device_node *np = ofnode_to_np(node);
|
||||||
|
struct property *pp;
|
||||||
|
struct property *pp_last = NULL;
|
||||||
|
struct property *new;
|
||||||
|
|
||||||
|
if (!of_live_active())
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
if (!np)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
for (pp = np->properties; pp; pp = pp->next) {
|
||||||
|
if (strcmp(pp->name, propname) == 0) {
|
||||||
|
/* Property exists -> change value */
|
||||||
|
pp->value = (void *)value;
|
||||||
|
pp->length = len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pp_last = pp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pp_last)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
/* Property does not exist -> append new property */
|
||||||
|
new = malloc(sizeof(struct property));
|
||||||
|
if (!new)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
new->name = strdup(propname);
|
||||||
|
if (!new->name)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
new->value = (void *)value;
|
||||||
|
new->length = len;
|
||||||
|
new->next = NULL;
|
||||||
|
|
||||||
|
pp_last->next = new;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ofnode_write_string(ofnode node, const char *propname, const char *value)
|
||||||
|
{
|
||||||
|
if (!of_live_active())
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
assert(ofnode_valid(node));
|
||||||
|
|
||||||
|
debug("%s: %s = %s", __func__, propname, value);
|
||||||
|
|
||||||
|
return ofnode_write_prop(node, propname, strlen(value) + 1, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ofnode_set_enabled(ofnode node, bool value)
|
||||||
|
{
|
||||||
|
if (!of_live_active())
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
assert(ofnode_valid(node));
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
return ofnode_write_string(node, "status", "okay");
|
||||||
|
else
|
||||||
|
return ofnode_write_string(node, "status", "disable");
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
config FIRMWARE
|
config FIRMWARE
|
||||||
bool
|
bool "Enable Firmware driver support"
|
||||||
|
|
||||||
config ARM_PSCI_FW
|
config ARM_PSCI_FW
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
obj-$(CONFIG_FIRMWARE) += firmware-uclass.o
|
obj-$(CONFIG_FIRMWARE) += firmware-uclass.o
|
||||||
obj-$(CONFIG_ARM_PSCI_FW) += psci.o
|
obj-$(CONFIG_ARM_PSCI_FW) += psci.o
|
||||||
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
|
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
|
||||||
|
obj-$(CONFIG_SANDBOX) += firmware-sandbox.o
|
||||||
|
|
20
drivers/firmware/firmware-sandbox.c
Normal file
20
drivers/firmware/firmware-sandbox.c
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* sandbox firmware driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 Xilinx, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <dm.h>
|
||||||
|
|
||||||
|
static const struct udevice_id generic_sandbox_firmware_ids[] = {
|
||||||
|
{ .compatible = "sandbox,firmware" },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
U_BOOT_DRIVER(sandbox_firmware) = {
|
||||||
|
.name = "sandbox_firmware",
|
||||||
|
.id = UCLASS_FIRMWARE,
|
||||||
|
.of_match = generic_sandbox_firmware_ids,
|
||||||
|
};
|
|
@ -7,7 +7,7 @@
|
||||||
UCLASS_DRIVER(firmware) = {
|
UCLASS_DRIVER(firmware) = {
|
||||||
.id = UCLASS_FIRMWARE,
|
.id = UCLASS_FIRMWARE,
|
||||||
.name = "firmware",
|
.name = "firmware",
|
||||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
.post_bind = dm_scan_fdt_dev,
|
.post_bind = dm_scan_fdt_dev,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
139
include/board.h
Normal file
139
include/board.h
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||||
|
/*
|
||||||
|
* (C) Copyright 2017
|
||||||
|
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This uclass encapsulates hardware methods to gather information about a
|
||||||
|
* board or a specific device such as hard-wired GPIOs on GPIO expanders,
|
||||||
|
* read-only data in flash ICs, or similar.
|
||||||
|
*
|
||||||
|
* The interface offers functions to read the usual standard data types (bool,
|
||||||
|
* int, string) from the device, each of which is identified by a static
|
||||||
|
* numeric ID (which will usually be defined as a enum in a header file).
|
||||||
|
*
|
||||||
|
* If for example the board had a read-only serial number flash IC, we could
|
||||||
|
* call
|
||||||
|
*
|
||||||
|
* ret = board_detect(dev);
|
||||||
|
* if (ret) {
|
||||||
|
* debug("board device not found.");
|
||||||
|
* return ret;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* ret = board_get_int(dev, ID_SERIAL_NUMBER, &serial);
|
||||||
|
* if (ret) {
|
||||||
|
* debug("Error when reading serial number from device.");
|
||||||
|
* return ret;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* to read the serial number.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct board_ops {
|
||||||
|
/**
|
||||||
|
* detect() - Run the hardware info detection procedure for this
|
||||||
|
* device.
|
||||||
|
* @dev: The device containing the information
|
||||||
|
*
|
||||||
|
* This operation might take a long time (e.g. read from EEPROM,
|
||||||
|
* check the presence of a device on a bus etc.), hence this is not
|
||||||
|
* done in the probe() method, but later during operation in this
|
||||||
|
* dedicated method.
|
||||||
|
*
|
||||||
|
* Return: 0 if OK, -ve on error.
|
||||||
|
*/
|
||||||
|
int (*detect)(struct udevice *dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get_bool() - Read a specific bool data value that describes the
|
||||||
|
* hardware setup.
|
||||||
|
* @dev: The board instance to gather the data.
|
||||||
|
* @id: A unique identifier for the bool value to be read.
|
||||||
|
* @val: Pointer to a buffer that receives the value read.
|
||||||
|
*
|
||||||
|
* Return: 0 if OK, -ve on error.
|
||||||
|
*/
|
||||||
|
int (*get_bool)(struct udevice *dev, int id, bool *val);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get_int() - Read a specific int data value that describes the
|
||||||
|
* hardware setup.
|
||||||
|
* @dev: The board instance to gather the data.
|
||||||
|
* @id: A unique identifier for the int value to be read.
|
||||||
|
* @val: Pointer to a buffer that receives the value read.
|
||||||
|
*
|
||||||
|
* Return: 0 if OK, -ve on error.
|
||||||
|
*/
|
||||||
|
int (*get_int)(struct udevice *dev, int id, int *val);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get_str() - Read a specific string data value that describes the
|
||||||
|
* hardware setup.
|
||||||
|
* @dev: The board instance to gather the data.
|
||||||
|
* @id: A unique identifier for the string value to be read.
|
||||||
|
* @size: The size of the buffer to receive the string data.
|
||||||
|
* @val: Pointer to a buffer that receives the value read.
|
||||||
|
*
|
||||||
|
* Return: 0 if OK, -ve on error.
|
||||||
|
*/
|
||||||
|
int (*get_str)(struct udevice *dev, int id, size_t size, char *val);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define board_get_ops(dev) ((struct board_ops *)(dev)->driver->ops)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* board_detect() - Run the hardware info detection procedure for this device.
|
||||||
|
*
|
||||||
|
* @dev: The device containing the information
|
||||||
|
*
|
||||||
|
* Return: 0 if OK, -ve on error.
|
||||||
|
*/
|
||||||
|
int board_detect(struct udevice *dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* board_get_bool() - Read a specific bool data value that describes the
|
||||||
|
* hardware setup.
|
||||||
|
* @dev: The board instance to gather the data.
|
||||||
|
* @id: A unique identifier for the bool value to be read.
|
||||||
|
* @val: Pointer to a buffer that receives the value read.
|
||||||
|
*
|
||||||
|
* Return: 0 if OK, -ve on error.
|
||||||
|
*/
|
||||||
|
int board_get_bool(struct udevice *dev, int id, bool *val);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* board_get_int() - Read a specific int data value that describes the
|
||||||
|
* hardware setup.
|
||||||
|
* @dev: The board instance to gather the data.
|
||||||
|
* @id: A unique identifier for the int value to be read.
|
||||||
|
* @val: Pointer to a buffer that receives the value read.
|
||||||
|
*
|
||||||
|
* Return: 0 if OK, -ve on error.
|
||||||
|
*/
|
||||||
|
int board_get_int(struct udevice *dev, int id, int *val);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* board_get_str() - Read a specific string data value that describes the
|
||||||
|
* hardware setup.
|
||||||
|
* @dev: The board instance to gather the data.
|
||||||
|
* @id: A unique identifier for the string value to be read.
|
||||||
|
* @size: The size of the buffer to receive the string data.
|
||||||
|
* @val: Pointer to a buffer that receives the value read.
|
||||||
|
*
|
||||||
|
* Return: 0 if OK, -ve on error.
|
||||||
|
*/
|
||||||
|
int board_get_str(struct udevice *dev, int id, size_t size, char *val);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* board_get() - Return the board device for the board in question.
|
||||||
|
* @devp: Pointer to structure to receive the board device.
|
||||||
|
*
|
||||||
|
* Since there can only be at most one board instance, the API can supply a
|
||||||
|
* function that returns the unique device. This is especially useful for use
|
||||||
|
* in board files.
|
||||||
|
*
|
||||||
|
* Return: 0 if OK, -ve on error.
|
||||||
|
*/
|
||||||
|
int board_get(struct udevice **devp);
|
|
@ -21,7 +21,7 @@
|
||||||
*
|
*
|
||||||
* A driver that implements UCLASS_CLOCK is a clock provider. A provider will
|
* A driver that implements UCLASS_CLOCK is a clock provider. A provider will
|
||||||
* often implement multiple separate clocks, since the hardware it manages
|
* often implement multiple separate clocks, since the hardware it manages
|
||||||
* often has this capability. clock_uclass.h describes the interface which
|
* often has this capability. clk-uclass.h describes the interface which
|
||||||
* clock providers must implement.
|
* clock providers must implement.
|
||||||
*
|
*
|
||||||
* Clock consumers/clients are the HW modules driven by the clock signals. This
|
* Clock consumers/clients are the HW modules driven by the clock signals. This
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#ifndef _DM_H_
|
#ifndef _DM_H_
|
||||||
#define _DM_H_
|
#define _DM_H_
|
||||||
|
|
||||||
#include <dm/ofnode.h>
|
|
||||||
#include <dm/device.h>
|
#include <dm/device.h>
|
||||||
#include <dm/fdtaddr.h>
|
#include <dm/fdtaddr.h>
|
||||||
#include <dm/ofnode.h>
|
#include <dm/ofnode.h>
|
||||||
|
|
|
@ -600,6 +600,22 @@ bool device_is_compatible(struct udevice *dev, const char *compat);
|
||||||
*/
|
*/
|
||||||
bool of_machine_is_compatible(const char *compat);
|
bool of_machine_is_compatible(const char *compat);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dev_disable_by_path() - Disable a device given its device tree path
|
||||||
|
*
|
||||||
|
* @path: The device tree path identifying the device to be disabled
|
||||||
|
* @return 0 on success, -ve on error
|
||||||
|
*/
|
||||||
|
int dev_disable_by_path(const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dev_enable_by_path() - Enable a device given its device tree path
|
||||||
|
*
|
||||||
|
* @path: The device tree path identifying the device to be enabled
|
||||||
|
* @return 0 on success, -ve on error
|
||||||
|
*/
|
||||||
|
int dev_enable_by_path(const char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* device_is_on_pci_bus - Test if a device is on a PCI bus
|
* device_is_on_pci_bus - Test if a device is on a PCI bus
|
||||||
*
|
*
|
||||||
|
|
|
@ -764,4 +764,50 @@ u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr);
|
||||||
* @return true if OK, false if the compatible is not found
|
* @return true if OK, false if the compatible is not found
|
||||||
*/
|
*/
|
||||||
int ofnode_device_is_compatible(ofnode node, const char *compat);
|
int ofnode_device_is_compatible(ofnode node, const char *compat);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ofnode_write_prop() - Set a property of a ofnode
|
||||||
|
*
|
||||||
|
* Note that the value passed to the function is *not* allocated by the
|
||||||
|
* function itself, but must be allocated by the caller if necessary.
|
||||||
|
*
|
||||||
|
* @node: The node for whose property should be set
|
||||||
|
* @propname: The name of the property to set
|
||||||
|
* @len: The length of the new value of the property
|
||||||
|
* @value: The new value of the property (must be valid prior to calling
|
||||||
|
* the function)
|
||||||
|
* @return 0 if successful, -ve on error
|
||||||
|
*/
|
||||||
|
int ofnode_write_prop(ofnode node, const char *propname, int len,
|
||||||
|
const void *value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ofnode_write_string() - Set a string property of a ofnode
|
||||||
|
*
|
||||||
|
* Note that the value passed to the function is *not* allocated by the
|
||||||
|
* function itself, but must be allocated by the caller if necessary.
|
||||||
|
*
|
||||||
|
* @node: The node for whose string property should be set
|
||||||
|
* @propname: The name of the string property to set
|
||||||
|
* @value: The new value of the string property (must be valid prior to
|
||||||
|
* calling the function)
|
||||||
|
* @return 0 if successful, -ve on error
|
||||||
|
*/
|
||||||
|
int ofnode_write_string(ofnode node, const char *propname, const char *value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ofnode_set_enabled() - Enable or disable a device tree node given by its
|
||||||
|
* ofnode
|
||||||
|
*
|
||||||
|
* This function effectively sets the node's "status" property to either "okay"
|
||||||
|
* or "disable", hence making it available for driver model initialization or
|
||||||
|
* not.
|
||||||
|
*
|
||||||
|
* @node: The node to enable
|
||||||
|
* @value: Flag that tells the function to either disable or enable the
|
||||||
|
* node
|
||||||
|
* @return 0 if successful, -ve on error
|
||||||
|
*/
|
||||||
|
int ofnode_set_enabled(ofnode node, bool value);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,6 +30,7 @@ enum uclass_id {
|
||||||
UCLASS_ADC, /* Analog-to-digital converter */
|
UCLASS_ADC, /* Analog-to-digital converter */
|
||||||
UCLASS_AHCI, /* SATA disk controller */
|
UCLASS_AHCI, /* SATA disk controller */
|
||||||
UCLASS_BLK, /* Block device */
|
UCLASS_BLK, /* Block device */
|
||||||
|
UCLASS_BOARD, /* Device information from hardware */
|
||||||
UCLASS_CLK, /* Clock source, e.g. used by peripherals */
|
UCLASS_CLK, /* Clock source, e.g. used by peripherals */
|
||||||
UCLASS_CPU, /* CPU, typically part of an SoC */
|
UCLASS_CPU, /* CPU, typically part of an SoC */
|
||||||
UCLASS_CROS_EC, /* Chrome OS EC */
|
UCLASS_CROS_EC, /* Chrome OS EC */
|
||||||
|
|
44
lib/fdtdec.c
44
lib/fdtdec.c
|
@ -15,6 +15,7 @@
|
||||||
#include <serial.h>
|
#include <serial.h>
|
||||||
#include <asm/sections.h>
|
#include <asm/sections.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
|
#include <linux/ioport.h>
|
||||||
#include <linux/lzo.h>
|
#include <linux/lzo.h>
|
||||||
|
|
||||||
DECLARE_GLOBAL_DATA_PTR;
|
DECLARE_GLOBAL_DATA_PTR;
|
||||||
|
@ -1181,41 +1182,34 @@ int fdtdec_setup_mem_size_base(void)
|
||||||
|
|
||||||
#if defined(CONFIG_NR_DRAM_BANKS)
|
#if defined(CONFIG_NR_DRAM_BANKS)
|
||||||
|
|
||||||
static int get_next_memory_node(const void *blob, int mem)
|
static ofnode get_next_memory_node(ofnode mem)
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
mem = fdt_node_offset_by_prop_value(gd->fdt_blob, mem,
|
mem = ofnode_by_prop_value(mem, "device_type", "memory", 7);
|
||||||
"device_type", "memory", 7);
|
} while (ofnode_valid(mem) && !ofnode_is_available(mem));
|
||||||
} while (!fdtdec_get_is_enabled(blob, mem));
|
|
||||||
|
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fdtdec_setup_memory_banksize(void)
|
int fdtdec_setup_memory_banksize(void)
|
||||||
{
|
{
|
||||||
int bank, ret, mem, reg = 0;
|
int bank, reg = 0;
|
||||||
struct fdt_resource res;
|
struct resource res;
|
||||||
|
ofnode mem;
|
||||||
|
|
||||||
mem = get_next_memory_node(gd->fdt_blob, -1);
|
mem = get_next_memory_node(ofnode_null());
|
||||||
if (mem < 0) {
|
if (!ofnode_valid(mem))
|
||||||
debug("%s: Missing /memory node\n", __func__);
|
goto missing_node;
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
|
for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
|
||||||
ret = fdt_get_resource(gd->fdt_blob, mem, "reg", reg++, &res);
|
while (ofnode_read_resource(mem, reg++, &res)) {
|
||||||
if (ret == -FDT_ERR_NOTFOUND) {
|
|
||||||
reg = 0;
|
reg = 0;
|
||||||
mem = get_next_memory_node(gd->fdt_blob, mem);
|
mem = get_next_memory_node(mem);
|
||||||
if (mem == -FDT_ERR_NOTFOUND)
|
if (!ofnode_valid(mem)) {
|
||||||
break;
|
if (bank)
|
||||||
|
return 0;
|
||||||
ret = fdt_get_resource(gd->fdt_blob, mem, "reg", reg++, &res);
|
goto missing_node;
|
||||||
if (ret == -FDT_ERR_NOTFOUND)
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (ret != 0) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gd->bd->bi_dram[bank].start = (phys_addr_t)res.start;
|
gd->bd->bi_dram[bank].start = (phys_addr_t)res.start;
|
||||||
|
@ -1229,6 +1223,10 @@ int fdtdec_setup_memory_banksize(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
missing_node:
|
||||||
|
debug("%s: Missing /memory node\n", __func__);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -628,28 +628,50 @@ class Fdt(FdtRo):
|
||||||
return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name,
|
return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name,
|
||||||
val, len(val)), quiet)
|
val, len(val)), quiet)
|
||||||
|
|
||||||
def delprop(self, nodeoffset, prop_name):
|
def delprop(self, nodeoffset, prop_name, quiet=()):
|
||||||
"""Delete a property from a node
|
"""Delete a property from a node
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
nodeoffset: Node offset containing property to delete
|
nodeoffset: Node offset containing property to delete
|
||||||
prop_name: Name of property to delete
|
prop_name: Name of property to delete
|
||||||
|
quiet: Errors to ignore (empty to raise on all errors)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Error code, or 0 if OK
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
FdtError if the property does not exist, or another error occurs
|
FdtError if the property does not exist, or another error occurs
|
||||||
"""
|
"""
|
||||||
return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name))
|
return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name), quiet)
|
||||||
|
|
||||||
def del_node(self, nodeoffset):
|
def add_subnode(self, parentoffset, name, quiet=()):
|
||||||
|
"""Add a new subnode to a node
|
||||||
|
|
||||||
|
Args:
|
||||||
|
parentoffset: Parent offset to add the subnode to
|
||||||
|
name: Name of node to add
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
offset of the node created, or negative error code on failure
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FdtError if there is not enough space, or another error occurs
|
||||||
|
"""
|
||||||
|
return check_err(fdt_add_subnode(self._fdt, parentoffset, name), quiet)
|
||||||
|
|
||||||
|
def del_node(self, nodeoffset, quiet=()):
|
||||||
"""Delete a node
|
"""Delete a node
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
nodeoffset: Node offset containing property to delete
|
nodeoffset: Offset of node to delete
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Error code, or 0 if OK
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
FdtError if the node does not exist, or another error occurs
|
FdtError if an error occurs
|
||||||
"""
|
"""
|
||||||
return check_err(fdt_del_node(self._fdt, nodeoffset))
|
return check_err(fdt_del_node(self._fdt, nodeoffset), quiet)
|
||||||
|
|
||||||
|
|
||||||
class Property(bytearray):
|
class Property(bytearray):
|
||||||
|
|
|
@ -14,8 +14,10 @@ obj-$(CONFIG_UT_DM) += test-uclass.o
|
||||||
obj-$(CONFIG_UT_DM) += core.o
|
obj-$(CONFIG_UT_DM) += core.o
|
||||||
ifneq ($(CONFIG_SANDBOX),)
|
ifneq ($(CONFIG_SANDBOX),)
|
||||||
obj-$(CONFIG_BLK) += blk.o
|
obj-$(CONFIG_BLK) += blk.o
|
||||||
|
obj-$(CONFIG_BOARD) += board.o
|
||||||
obj-$(CONFIG_CLK) += clk.o
|
obj-$(CONFIG_CLK) += clk.o
|
||||||
obj-$(CONFIG_DM_ETH) += eth.o
|
obj-$(CONFIG_DM_ETH) += eth.o
|
||||||
|
obj-$(CONFIG_FIRMWARE) += firmware.o
|
||||||
obj-$(CONFIG_DM_GPIO) += gpio.o
|
obj-$(CONFIG_DM_GPIO) += gpio.o
|
||||||
obj-$(CONFIG_DM_I2C) += i2c.o
|
obj-$(CONFIG_DM_I2C) += i2c.o
|
||||||
obj-$(CONFIG_LED) += led.o
|
obj-$(CONFIG_LED) += led.o
|
||||||
|
|
57
test/dm/board.c
Normal file
57
test/dm/board.c
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* (C) Copyright 2018
|
||||||
|
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <dm.h>
|
||||||
|
#include <dm/test.h>
|
||||||
|
#include <board.h>
|
||||||
|
#include <test/ut.h>
|
||||||
|
|
||||||
|
#include "../../drivers/board/sandbox.h"
|
||||||
|
|
||||||
|
static int dm_test_board(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
struct udevice *board;
|
||||||
|
bool called_detect;
|
||||||
|
char str[64];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
board_get(&board);
|
||||||
|
ut_assert(board);
|
||||||
|
|
||||||
|
board_get_bool(board, BOOL_CALLED_DETECT, &called_detect);
|
||||||
|
ut_assert(!called_detect);
|
||||||
|
|
||||||
|
board_detect(board);
|
||||||
|
|
||||||
|
board_get_bool(board, BOOL_CALLED_DETECT, &called_detect);
|
||||||
|
ut_assert(called_detect);
|
||||||
|
|
||||||
|
board_get_str(board, STR_VACATIONSPOT, sizeof(str), str);
|
||||||
|
ut_assertok(strcmp(str, "R'lyeh"));
|
||||||
|
|
||||||
|
board_get_int(board, INT_TEST1, &i);
|
||||||
|
ut_asserteq(0, i);
|
||||||
|
|
||||||
|
board_get_int(board, INT_TEST2, &i);
|
||||||
|
ut_asserteq(100, i);
|
||||||
|
|
||||||
|
board_get_str(board, STR_VACATIONSPOT, sizeof(str), str);
|
||||||
|
ut_assertok(strcmp(str, "Carcosa"));
|
||||||
|
|
||||||
|
board_get_int(board, INT_TEST1, &i);
|
||||||
|
ut_asserteq(1, i);
|
||||||
|
|
||||||
|
board_get_int(board, INT_TEST2, &i);
|
||||||
|
ut_asserteq(99, i);
|
||||||
|
|
||||||
|
board_get_str(board, STR_VACATIONSPOT, sizeof(str), str);
|
||||||
|
ut_assertok(strcmp(str, "Yuggoth"));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DM_TEST(dm_test_board, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
22
test/dm/firmware.c
Normal file
22
test/dm/firmware.c
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Xilinx, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <dm.h>
|
||||||
|
#include <syscon.h>
|
||||||
|
#include <asm/test.h>
|
||||||
|
#include <dm/test.h>
|
||||||
|
#include <test/ut.h>
|
||||||
|
|
||||||
|
/* Base test of firmware probe */
|
||||||
|
static int dm_test_firmware_probe(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
struct udevice *dev;
|
||||||
|
|
||||||
|
ut_assertok(uclass_get_device_by_name(UCLASS_FIRMWARE,
|
||||||
|
"sandbox-firmware", &dev));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DM_TEST(dm_test_firmware_probe, DM_TESTF_SCAN_FDT);
|
|
@ -14,6 +14,8 @@
|
||||||
#include <dm/device-internal.h>
|
#include <dm/device-internal.h>
|
||||||
#include <dm/uclass-internal.h>
|
#include <dm/uclass-internal.h>
|
||||||
#include <dm/util.h>
|
#include <dm/util.h>
|
||||||
|
#include <dm/lists.h>
|
||||||
|
#include <dm/of_access.h>
|
||||||
#include <test/ut.h>
|
#include <test/ut.h>
|
||||||
|
|
||||||
DECLARE_GLOBAL_DATA_PTR;
|
DECLARE_GLOBAL_DATA_PTR;
|
||||||
|
@ -503,3 +505,83 @@ static int dm_test_fdt_remap_addr_live(struct unit_test_state *uts)
|
||||||
}
|
}
|
||||||
DM_TEST(dm_test_fdt_remap_addr_live,
|
DM_TEST(dm_test_fdt_remap_addr_live,
|
||||||
DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
||||||
|
|
||||||
|
static int dm_test_fdt_livetree_writing(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
struct udevice *dev;
|
||||||
|
ofnode node;
|
||||||
|
|
||||||
|
if (!of_live_active()) {
|
||||||
|
printf("Live tree not active; ignore test\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test enabling devices */
|
||||||
|
|
||||||
|
node = ofnode_path("/usb@2");
|
||||||
|
|
||||||
|
ut_assert(!of_device_is_available(ofnode_to_np(node)));
|
||||||
|
ofnode_set_enabled(node, true);
|
||||||
|
ut_assert(of_device_is_available(ofnode_to_np(node)));
|
||||||
|
|
||||||
|
device_bind_driver_to_node(dm_root(), "usb_sandbox", "usb@2", node,
|
||||||
|
&dev);
|
||||||
|
ut_assertok(uclass_find_device_by_seq(UCLASS_USB, 2, true, &dev));
|
||||||
|
|
||||||
|
/* Test string property setting */
|
||||||
|
|
||||||
|
ut_assert(device_is_compatible(dev, "sandbox,usb"));
|
||||||
|
ofnode_write_string(node, "compatible", "gdsys,super-usb");
|
||||||
|
ut_assert(device_is_compatible(dev, "gdsys,super-usb"));
|
||||||
|
ofnode_write_string(node, "compatible", "sandbox,usb");
|
||||||
|
ut_assert(device_is_compatible(dev, "sandbox,usb"));
|
||||||
|
|
||||||
|
/* Test setting generic properties */
|
||||||
|
|
||||||
|
/* Non-existent in DTB */
|
||||||
|
ut_asserteq(FDT_ADDR_T_NONE, dev_read_addr(dev));
|
||||||
|
/* reg = 0x42, size = 0x100 */
|
||||||
|
ut_assertok(ofnode_write_prop(node, "reg", 8,
|
||||||
|
"\x00\x00\x00\x42\x00\x00\x01\x00"));
|
||||||
|
ut_asserteq(0x42, dev_read_addr(dev));
|
||||||
|
|
||||||
|
/* Test disabling devices */
|
||||||
|
|
||||||
|
device_remove(dev, DM_REMOVE_NORMAL);
|
||||||
|
device_unbind(dev);
|
||||||
|
|
||||||
|
ut_assert(of_device_is_available(ofnode_to_np(node)));
|
||||||
|
ofnode_set_enabled(node, false);
|
||||||
|
ut_assert(!of_device_is_available(ofnode_to_np(node)));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DM_TEST(dm_test_fdt_livetree_writing, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
||||||
|
|
||||||
|
static int dm_test_fdt_disable_enable_by_path(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
ofnode node;
|
||||||
|
|
||||||
|
if (!of_live_active()) {
|
||||||
|
printf("Live tree not active; ignore test\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = ofnode_path("/usb@2");
|
||||||
|
|
||||||
|
/* Test enabling devices */
|
||||||
|
|
||||||
|
ut_assert(!of_device_is_available(ofnode_to_np(node)));
|
||||||
|
dev_enable_by_path("/usb@2");
|
||||||
|
ut_assert(of_device_is_available(ofnode_to_np(node)));
|
||||||
|
|
||||||
|
/* Test disabling devices */
|
||||||
|
|
||||||
|
ut_assert(of_device_is_available(ofnode_to_np(node)));
|
||||||
|
dev_disable_by_path("/usb@2");
|
||||||
|
ut_assert(!of_device_is_available(ofnode_to_np(node)));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DM_TEST(dm_test_fdt_disable_enable_by_path, DM_TESTF_SCAN_PDATA |
|
||||||
|
DM_TESTF_SCAN_FDT);
|
||||||
|
|
|
@ -330,9 +330,13 @@ image-pos:
|
||||||
for each entry. This makes it easy to find out exactly where the entry
|
for each entry. This makes it easy to find out exactly where the entry
|
||||||
ended up in the image, regardless of parent sections, etc.
|
ended up in the image, regardless of parent sections, etc.
|
||||||
|
|
||||||
|
expand-size:
|
||||||
|
Expand the size of this entry to fit available space. This space is only
|
||||||
|
limited by the size of the image/section and the position of the next
|
||||||
|
entry.
|
||||||
|
|
||||||
The attributes supported for images are described below. Several are similar
|
The attributes supported for images and sections are described below. Several
|
||||||
to those for entries.
|
are similar to those for entries.
|
||||||
|
|
||||||
size:
|
size:
|
||||||
Sets the image size in bytes, for example 'size = <0x100000>' for a
|
Sets the image size in bytes, for example 'size = <0x100000>' for a
|
||||||
|
@ -471,15 +475,26 @@ see README.entries. This is generated from the source code using:
|
||||||
binman -E >tools/binman/README.entries
|
binman -E >tools/binman/README.entries
|
||||||
|
|
||||||
|
|
||||||
Special properties
|
Hashing Entries
|
||||||
------------------
|
---------------
|
||||||
|
|
||||||
Some entries support special properties, documented here:
|
It is possible to ask binman to hash the contents of an entry and write that
|
||||||
|
value back to the device-tree node. For example:
|
||||||
|
|
||||||
u-boot-with-ucode-ptr:
|
binman {
|
||||||
optional-ucode: boolean property to make microcode optional. If the
|
u-boot {
|
||||||
u-boot.bin image does not include microcode, no error will
|
hash {
|
||||||
be generated.
|
algo = "sha256";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Here, a new 'value' property will be written to the 'hash' node containing
|
||||||
|
the hash of the 'u-boot' entry. Only SHA256 is supported at present. Whole
|
||||||
|
sections can be hased if desired, by adding the 'hash' node to the section.
|
||||||
|
|
||||||
|
The has value can be chcked at runtime by hashing the data actually read and
|
||||||
|
comparing this has to the value in the device tree.
|
||||||
|
|
||||||
|
|
||||||
Order of image creation
|
Order of image creation
|
||||||
|
@ -613,6 +628,22 @@ the device tree. These can be used by U-Boot at run-time to find the location
|
||||||
of each entry.
|
of each entry.
|
||||||
|
|
||||||
|
|
||||||
|
Compression
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Binman support compression for 'blob' entries (those of type 'blob' and
|
||||||
|
derivatives). To enable this for an entry, add a 'compression' property:
|
||||||
|
|
||||||
|
blob {
|
||||||
|
filename = "datafile";
|
||||||
|
compression = "lz4";
|
||||||
|
};
|
||||||
|
|
||||||
|
The entry will then contain the compressed data, using the 'lz4' compression
|
||||||
|
algorithm. Currently this is the only one that is supported.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Map files
|
Map files
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,27 @@ class by other entry types.
|
||||||
|
|
||||||
Properties / Entry arguments:
|
Properties / Entry arguments:
|
||||||
- filename: Filename of file to read into entry
|
- filename: Filename of file to read into entry
|
||||||
|
- compress: Compression algorithm to use:
|
||||||
|
none: No compression
|
||||||
|
lz4: Use lz4 compression (via 'lz4' command-line utility)
|
||||||
|
|
||||||
This entry reads data from a file and places it in the entry. The
|
This entry reads data from a file and places it in the entry. The
|
||||||
default filename is often specified specified by the subclass. See for
|
default filename is often specified specified by the subclass. See for
|
||||||
example the 'u_boot' entry which provides the filename 'u-boot.bin'.
|
example the 'u_boot' entry which provides the filename 'u-boot.bin'.
|
||||||
|
|
||||||
|
If compression is enabled, an extra 'uncomp-size' property is written to
|
||||||
|
the node (if enabled with -u) which provides the uncompressed size of the
|
||||||
|
data.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Entry: blob-dtb: A blob that holds a device tree
|
||||||
|
------------------------------------------------
|
||||||
|
|
||||||
|
This is a blob containing a device tree. The contents of the blob are
|
||||||
|
obtained from the list of available device-tree files, managed by the
|
||||||
|
'state' module.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Entry: blob-named-by-arg: A blob entry which gets its filename property from its subclass
|
Entry: blob-named-by-arg: A blob entry which gets its filename property from its subclass
|
||||||
|
@ -55,6 +71,21 @@ updating the EC on startup via software sync.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Entry: files: Entry containing a set of files
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
Properties / Entry arguments:
|
||||||
|
- pattern: Filename pattern to match the files to include
|
||||||
|
- compress: Compression algorithm to use:
|
||||||
|
none: No compression
|
||||||
|
lz4: Use lz4 compression (via 'lz4' command-line utility)
|
||||||
|
|
||||||
|
This entry reads a number of files and places each in a separate sub-entry
|
||||||
|
within this entry. To access these you need to enable device-tree updates
|
||||||
|
at run-time so you can obtain the file positions.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Entry: fill: An entry which is filled to a particular byte value
|
Entry: fill: An entry which is filled to a particular byte value
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -321,6 +352,9 @@ This is the U-Boot device tree, containing configuration information for
|
||||||
U-Boot. U-Boot needs this to know what devices are present and which drivers
|
U-Boot. U-Boot needs this to know what devices are present and which drivers
|
||||||
to activate.
|
to activate.
|
||||||
|
|
||||||
|
Note: This is mostly an internal entry type, used by others. This allows
|
||||||
|
binman to know which entries contain a device tree.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Entry: u-boot-dtb-with-ucode: A U-Boot device tree file, with the microcode removed
|
Entry: u-boot-dtb-with-ucode: A U-Boot device tree file, with the microcode removed
|
||||||
|
@ -339,6 +373,17 @@ it available to u_boot_ucode.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Entry: u-boot-elf: U-Boot ELF image
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
Properties / Entry arguments:
|
||||||
|
- filename: Filename of u-boot (default 'u-boot')
|
||||||
|
|
||||||
|
This is the U-Boot ELF image. It does not include a device tree but can be
|
||||||
|
relocated to any address for execution.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Entry: u-boot-img: U-Boot legacy image
|
Entry: u-boot-img: U-Boot legacy image
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
|
|
||||||
|
@ -422,6 +467,17 @@ to activate.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Entry: u-boot-spl-elf: U-Boot SPL ELF image
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
Properties / Entry arguments:
|
||||||
|
- filename: Filename of SPL u-boot (default 'spl/u-boot')
|
||||||
|
|
||||||
|
This is the U-Boot SPL ELF image. It does not include a device tree but can
|
||||||
|
be relocated to any address for execution.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Entry: u-boot-spl-nodtb: SPL binary without device tree appended
|
Entry: u-boot-spl-nodtb: SPL binary without device tree appended
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -440,6 +496,8 @@ both SPL and the device tree).
|
||||||
Entry: u-boot-spl-with-ucode-ptr: U-Boot SPL with embedded microcode pointer
|
Entry: u-boot-spl-with-ucode-ptr: U-Boot SPL with embedded microcode pointer
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
This is used when SPL must set up the microcode for U-Boot.
|
||||||
|
|
||||||
See Entry_u_boot_ucode for full details of the entries involved in this
|
See Entry_u_boot_ucode for full details of the entries involved in this
|
||||||
process.
|
process.
|
||||||
|
|
||||||
|
@ -481,6 +539,24 @@ to activate.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Entry: u-boot-tpl-dtb-with-ucode: U-Boot TPL with embedded microcode pointer
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
This is used when TPL must set up the microcode for U-Boot.
|
||||||
|
|
||||||
|
See Entry_u_boot_ucode for full details of the entries involved in this
|
||||||
|
process.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Entry: u-boot-tpl-with-ucode-ptr: U-Boot TPL with embedded microcode pointer
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
See Entry_u_boot_ucode for full details of the entries involved in this
|
||||||
|
process.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Entry: u-boot-ucode: U-Boot microcode block
|
Entry: u-boot-ucode: U-Boot microcode block
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
|
@ -536,6 +612,9 @@ Entry: u-boot-with-ucode-ptr: U-Boot with embedded microcode pointer
|
||||||
|
|
||||||
Properties / Entry arguments:
|
Properties / Entry arguments:
|
||||||
- filename: Filename of u-boot-nodtb.dtb (default 'u-boot-nodtb.dtb')
|
- filename: Filename of u-boot-nodtb.dtb (default 'u-boot-nodtb.dtb')
|
||||||
|
- optional-ucode: boolean property to make microcode optional. If the
|
||||||
|
u-boot.bin image does not include microcode, no error will
|
||||||
|
be generated.
|
||||||
|
|
||||||
See Entry_u_boot_ucode for full details of the three entries involved in
|
See Entry_u_boot_ucode for full details of the three entries involved in
|
||||||
this process. This entry updates U-Boot with the offset and size of the
|
this process. This entry updates U-Boot with the offset and size of the
|
||||||
|
@ -555,6 +634,11 @@ Properties / Entry arguments:
|
||||||
- kernelkey: Name of the kernel key to use (inside keydir)
|
- kernelkey: Name of the kernel key to use (inside keydir)
|
||||||
- preamble-flags: Value of the vboot preamble flags (typically 0)
|
- preamble-flags: Value of the vboot preamble flags (typically 0)
|
||||||
|
|
||||||
|
Output files:
|
||||||
|
- input.<unique_name> - input file passed to futility
|
||||||
|
- vblock.<unique_name> - output file generated by futility (which is
|
||||||
|
used as the entry contents)
|
||||||
|
|
||||||
Chromium OS signs the read-write firmware and kernel, writing the signature
|
Chromium OS signs the read-write firmware and kernel, writing the signature
|
||||||
in this block. This allows U-Boot to verify that the next firmware stage
|
in this block. This allows U-Boot to verify that the next firmware stage
|
||||||
and kernel are genuine.
|
and kernel are genuine.
|
||||||
|
@ -595,3 +679,20 @@ For 32-bit U-Boot, the 'x86_start16' entry type is used instead.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Entry: x86-start16-tpl: x86 16-bit start-up code for TPL
|
||||||
|
--------------------------------------------------------
|
||||||
|
|
||||||
|
Properties / Entry arguments:
|
||||||
|
- filename: Filename of tpl/u-boot-x86-16bit-tpl.bin (default
|
||||||
|
'tpl/u-boot-x86-16bit-tpl.bin')
|
||||||
|
|
||||||
|
x86 CPUs start up in 16-bit mode, even if they are 64-bit CPUs. This code
|
||||||
|
must be placed at a particular address. This entry holds that code. It is
|
||||||
|
typically placed at offset CONFIG_SYS_X86_START16. The code is responsible
|
||||||
|
for changing to 32-bit mode and starting TPL, which in turn jumps to SPL.
|
||||||
|
|
||||||
|
If TPL is not being used, the 'x86_start16_spl or 'x86_start16' entry types
|
||||||
|
may be used instead.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,12 @@
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
from sets import Set
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import fdt_util
|
import fdt_util
|
||||||
import re
|
import re
|
||||||
|
import state
|
||||||
import tools
|
import tools
|
||||||
|
|
||||||
class Section(object):
|
class Section(object):
|
||||||
|
@ -22,6 +24,7 @@ class Section(object):
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
_node: Node object that contains the section definition in device tree
|
_node: Node object that contains the section definition in device tree
|
||||||
|
_parent_section: Parent Section object which created this Section
|
||||||
_size: Section size in bytes, or None if not known yet
|
_size: Section size in bytes, or None if not known yet
|
||||||
_align_size: Section size alignment, or None
|
_align_size: Section size alignment, or None
|
||||||
_pad_before: Number of bytes before the first entry starts. This
|
_pad_before: Number of bytes before the first entry starts. This
|
||||||
|
@ -44,14 +47,16 @@ class Section(object):
|
||||||
section
|
section
|
||||||
_entries: OrderedDict() of entries
|
_entries: OrderedDict() of entries
|
||||||
"""
|
"""
|
||||||
def __init__(self, name, node, test=False):
|
def __init__(self, name, parent_section, node, image, test=False):
|
||||||
global entry
|
global entry
|
||||||
global Entry
|
global Entry
|
||||||
import entry
|
import entry
|
||||||
from entry import Entry
|
from entry import Entry
|
||||||
|
|
||||||
|
self._parent_section = parent_section
|
||||||
self._name = name
|
self._name = name
|
||||||
self._node = node
|
self._node = node
|
||||||
|
self._image = image
|
||||||
self._offset = 0
|
self._offset = 0
|
||||||
self._size = None
|
self._size = None
|
||||||
self._align_size = None
|
self._align_size = None
|
||||||
|
@ -63,6 +68,7 @@ class Section(object):
|
||||||
self._end_4gb = False
|
self._end_4gb = False
|
||||||
self._name_prefix = ''
|
self._name_prefix = ''
|
||||||
self._entries = OrderedDict()
|
self._entries = OrderedDict()
|
||||||
|
self._image_pos = None
|
||||||
if not test:
|
if not test:
|
||||||
self._ReadNode()
|
self._ReadNode()
|
||||||
self._ReadEntries()
|
self._ReadEntries()
|
||||||
|
@ -94,25 +100,42 @@ class Section(object):
|
||||||
|
|
||||||
def _ReadEntries(self):
|
def _ReadEntries(self):
|
||||||
for node in self._node.subnodes:
|
for node in self._node.subnodes:
|
||||||
|
if node.name == 'hash':
|
||||||
|
continue
|
||||||
entry = Entry.Create(self, node)
|
entry = Entry.Create(self, node)
|
||||||
entry.SetPrefix(self._name_prefix)
|
entry.SetPrefix(self._name_prefix)
|
||||||
self._entries[node.name] = entry
|
self._entries[node.name] = entry
|
||||||
|
|
||||||
|
def GetFdtSet(self):
|
||||||
|
"""Get the set of device tree files used by this image"""
|
||||||
|
fdt_set = Set()
|
||||||
|
for entry in self._entries.values():
|
||||||
|
fdt_set.update(entry.GetFdtSet())
|
||||||
|
return fdt_set
|
||||||
|
|
||||||
def SetOffset(self, offset):
|
def SetOffset(self, offset):
|
||||||
self._offset = offset
|
self._offset = offset
|
||||||
|
|
||||||
|
def ExpandEntries(self):
|
||||||
|
for entry in self._entries.values():
|
||||||
|
entry.ExpandEntries()
|
||||||
|
|
||||||
def AddMissingProperties(self):
|
def AddMissingProperties(self):
|
||||||
"""Add new properties to the device tree as needed for this entry"""
|
"""Add new properties to the device tree as needed for this entry"""
|
||||||
for prop in ['offset', 'size', 'image-pos']:
|
for prop in ['offset', 'size', 'image-pos']:
|
||||||
if not prop in self._node.props:
|
if not prop in self._node.props:
|
||||||
self._node.AddZeroProp(prop)
|
state.AddZeroProp(self._node, prop)
|
||||||
|
state.CheckAddHashProp(self._node)
|
||||||
for entry in self._entries.values():
|
for entry in self._entries.values():
|
||||||
entry.AddMissingProperties()
|
entry.AddMissingProperties()
|
||||||
|
|
||||||
def SetCalculatedProperties(self):
|
def SetCalculatedProperties(self):
|
||||||
self._node.SetInt('offset', self._offset)
|
state.SetInt(self._node, 'offset', self._offset)
|
||||||
self._node.SetInt('size', self._size)
|
state.SetInt(self._node, 'size', self._size)
|
||||||
self._node.SetInt('image-pos', self._image_pos)
|
image_pos = self._image_pos
|
||||||
|
if self._parent_section:
|
||||||
|
image_pos -= self._parent_section.GetRootSkipAtStart()
|
||||||
|
state.SetInt(self._node, 'image-pos', image_pos)
|
||||||
for entry in self._entries.values():
|
for entry in self._entries.values():
|
||||||
entry.SetCalculatedProperties()
|
entry.SetCalculatedProperties()
|
||||||
|
|
||||||
|
@ -247,16 +270,32 @@ class Section(object):
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
self._entries[entry._node.name] = entry
|
self._entries[entry._node.name] = entry
|
||||||
|
|
||||||
|
def _ExpandEntries(self):
|
||||||
|
"""Expand any entries that are permitted to"""
|
||||||
|
exp_entry = None
|
||||||
|
for entry in self._entries.values():
|
||||||
|
if exp_entry:
|
||||||
|
exp_entry.ExpandToLimit(entry.offset)
|
||||||
|
exp_entry = None
|
||||||
|
if entry.expand_size:
|
||||||
|
exp_entry = entry
|
||||||
|
if exp_entry:
|
||||||
|
exp_entry.ExpandToLimit(self._size)
|
||||||
|
|
||||||
def CheckEntries(self):
|
def CheckEntries(self):
|
||||||
"""Check that entries do not overlap or extend outside the section"""
|
"""Check that entries do not overlap or extend outside the section
|
||||||
|
|
||||||
|
This also sorts entries, if needed and expands
|
||||||
|
"""
|
||||||
if self._sort:
|
if self._sort:
|
||||||
self._SortEntries()
|
self._SortEntries()
|
||||||
|
self._ExpandEntries()
|
||||||
offset = 0
|
offset = 0
|
||||||
prev_name = 'None'
|
prev_name = 'None'
|
||||||
for entry in self._entries.values():
|
for entry in self._entries.values():
|
||||||
entry.CheckOffset()
|
entry.CheckOffset()
|
||||||
if (entry.offset < self._skip_at_start or
|
if (entry.offset < self._skip_at_start or
|
||||||
entry.offset >= self._skip_at_start + self._size):
|
entry.offset + entry.size > self._skip_at_start + self._size):
|
||||||
entry.Raise("Offset %#x (%d) is outside the section starting "
|
entry.Raise("Offset %#x (%d) is outside the section starting "
|
||||||
"at %#x (%d)" %
|
"at %#x (%d)" %
|
||||||
(entry.offset, entry.offset, self._skip_at_start,
|
(entry.offset, entry.offset, self._skip_at_start,
|
||||||
|
@ -409,7 +448,17 @@ class Section(object):
|
||||||
source_entry.Raise("Cannot find node for phandle %d" % phandle)
|
source_entry.Raise("Cannot find node for phandle %d" % phandle)
|
||||||
for entry in self._entries.values():
|
for entry in self._entries.values():
|
||||||
if entry._node == node:
|
if entry._node == node:
|
||||||
if entry.data is None:
|
return entry.GetData()
|
||||||
return None
|
|
||||||
return entry.data
|
|
||||||
source_entry.Raise("Cannot find entry for node '%s'" % node.name)
|
source_entry.Raise("Cannot find entry for node '%s'" % node.name)
|
||||||
|
|
||||||
|
def ExpandSize(self, size):
|
||||||
|
if size != self._size:
|
||||||
|
self._size = size
|
||||||
|
|
||||||
|
def GetRootSkipAtStart(self):
|
||||||
|
if self._parent_section:
|
||||||
|
return self._parent_section.GetRootSkipAtStart()
|
||||||
|
return self._skip_at_start
|
||||||
|
|
||||||
|
def GetImageSize(self):
|
||||||
|
return self._image._size
|
||||||
|
|
|
@ -30,6 +30,10 @@ def ParseArgs(argv):
|
||||||
help='Enabling debugging (provides a full traceback on error)')
|
help='Enabling debugging (provides a full traceback on error)')
|
||||||
parser.add_option('-E', '--entry-docs', action='store_true',
|
parser.add_option('-E', '--entry-docs', action='store_true',
|
||||||
help='Write out entry documentation (see README.entries)')
|
help='Write out entry documentation (see README.entries)')
|
||||||
|
parser.add_option('--fake-dtb', action='store_true',
|
||||||
|
help='Use fake device tree contents (for testing only)')
|
||||||
|
parser.add_option('-i', '--image', type='string', action='append',
|
||||||
|
help='Image filename to build (if not specified, build all)')
|
||||||
parser.add_option('-I', '--indir', action='append',
|
parser.add_option('-I', '--indir', action='append',
|
||||||
help='Add a path to a directory to use for input files')
|
help='Add a path to a directory to use for input files')
|
||||||
parser.add_option('-H', '--full-help', action='store_true',
|
parser.add_option('-H', '--full-help', action='store_true',
|
||||||
|
|
|
@ -7,27 +7,19 @@
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
import sys
|
import sys
|
||||||
import tools
|
import tools
|
||||||
|
|
||||||
import command
|
import command
|
||||||
import elf
|
import elf
|
||||||
from image import Image
|
from image import Image
|
||||||
|
import state
|
||||||
import tout
|
import tout
|
||||||
|
|
||||||
# List of images we plan to create
|
# List of images we plan to create
|
||||||
# Make this global so that it can be referenced from tests
|
# Make this global so that it can be referenced from tests
|
||||||
images = OrderedDict()
|
images = OrderedDict()
|
||||||
|
|
||||||
# Records the device-tree files known to binman, keyed by filename (e.g.
|
|
||||||
# 'u-boot-spl.dtb')
|
|
||||||
fdt_files = {}
|
|
||||||
|
|
||||||
# Arguments passed to binman to provide arguments to entries
|
|
||||||
entry_args = {}
|
|
||||||
|
|
||||||
|
|
||||||
def _ReadImageDesc(binman_node):
|
def _ReadImageDesc(binman_node):
|
||||||
"""Read the image descriptions from the /binman node
|
"""Read the image descriptions from the /binman node
|
||||||
|
|
||||||
|
@ -60,39 +52,15 @@ def _FindBinmanNode(dtb):
|
||||||
return node
|
return node
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def GetFdt(fname):
|
def WriteEntryDocs(modules, test_missing=None):
|
||||||
"""Get the Fdt object for a particular device-tree filename
|
"""Write out documentation for all entries
|
||||||
|
|
||||||
Binman keeps track of at least one device-tree file called u-boot.dtb but
|
|
||||||
can also have others (e.g. for SPL). This function looks up the given
|
|
||||||
filename and returns the associated Fdt object.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
fname: Filename to look up (e.g. 'u-boot.dtb').
|
modules: List of Module objects to get docs for
|
||||||
|
test_missing: Used for testing only, to force an entry's documeentation
|
||||||
Returns:
|
to show as missing even if it is present. Should be set to None in
|
||||||
Fdt object associated with the filename
|
normal use.
|
||||||
"""
|
"""
|
||||||
return fdt_files[fname]
|
|
||||||
|
|
||||||
def GetFdtPath(fname):
|
|
||||||
return fdt_files[fname]._fname
|
|
||||||
|
|
||||||
def SetEntryArgs(args):
|
|
||||||
global entry_args
|
|
||||||
|
|
||||||
entry_args = {}
|
|
||||||
if args:
|
|
||||||
for arg in args:
|
|
||||||
m = re.match('([^=]*)=(.*)', arg)
|
|
||||||
if not m:
|
|
||||||
raise ValueError("Invalid entry arguemnt '%s'" % arg)
|
|
||||||
entry_args[m.group(1)] = m.group(2)
|
|
||||||
|
|
||||||
def GetEntryArg(name):
|
|
||||||
return entry_args.get(name)
|
|
||||||
|
|
||||||
def WriteEntryDocs(modules, test_missing=None):
|
|
||||||
from entry import Entry
|
from entry import Entry
|
||||||
Entry.WriteDocs(modules, test_missing)
|
Entry.WriteDocs(modules, test_missing)
|
||||||
|
|
||||||
|
@ -138,23 +106,20 @@ def Binman(options, args):
|
||||||
|
|
||||||
tout.Init(options.verbosity)
|
tout.Init(options.verbosity)
|
||||||
elf.debug = options.debug
|
elf.debug = options.debug
|
||||||
|
state.use_fake_dtb = options.fake_dtb
|
||||||
try:
|
try:
|
||||||
tools.SetInputDirs(options.indir)
|
tools.SetInputDirs(options.indir)
|
||||||
tools.PrepareOutputDir(options.outdir, options.preserve)
|
tools.PrepareOutputDir(options.outdir, options.preserve)
|
||||||
SetEntryArgs(options.entry_arg)
|
state.SetEntryArgs(options.entry_arg)
|
||||||
|
|
||||||
# Get the device tree ready by compiling it and copying the compiled
|
# Get the device tree ready by compiling it and copying the compiled
|
||||||
# output into a file in our output directly. Then scan it for use
|
# output into a file in our output directly. Then scan it for use
|
||||||
# in binman.
|
# in binman.
|
||||||
dtb_fname = fdt_util.EnsureCompiled(dtb_fname)
|
dtb_fname = fdt_util.EnsureCompiled(dtb_fname)
|
||||||
fname = tools.GetOutputFilename('u-boot-out.dtb')
|
fname = tools.GetOutputFilename('u-boot.dtb.out')
|
||||||
with open(dtb_fname) as infd:
|
tools.WriteFile(fname, tools.ReadFile(dtb_fname))
|
||||||
with open(fname, 'wb') as outfd:
|
|
||||||
outfd.write(infd.read())
|
|
||||||
dtb = fdt.FdtScan(fname)
|
dtb = fdt.FdtScan(fname)
|
||||||
|
|
||||||
# Note the file so that GetFdt() can find it
|
|
||||||
fdt_files['u-boot.dtb'] = dtb
|
|
||||||
node = _FindBinmanNode(dtb)
|
node = _FindBinmanNode(dtb)
|
||||||
if not node:
|
if not node:
|
||||||
raise ValueError("Device tree '%s' does not have a 'binman' "
|
raise ValueError("Device tree '%s' does not have a 'binman' "
|
||||||
|
@ -162,6 +127,17 @@ def Binman(options, args):
|
||||||
|
|
||||||
images = _ReadImageDesc(node)
|
images = _ReadImageDesc(node)
|
||||||
|
|
||||||
|
if options.image:
|
||||||
|
skip = []
|
||||||
|
for name, image in images.iteritems():
|
||||||
|
if name not in options.image:
|
||||||
|
del images[name]
|
||||||
|
skip.append(name)
|
||||||
|
if skip:
|
||||||
|
print 'Skipping images: %s\n' % ', '.join(skip)
|
||||||
|
|
||||||
|
state.Prepare(images, dtb)
|
||||||
|
|
||||||
# Prepare the device tree by making sure that any missing
|
# Prepare the device tree by making sure that any missing
|
||||||
# properties are added (e.g. 'pos' and 'size'). The values of these
|
# properties are added (e.g. 'pos' and 'size'). The values of these
|
||||||
# may not be correct yet, but we add placeholders so that the
|
# may not be correct yet, but we add placeholders so that the
|
||||||
|
@ -170,12 +146,15 @@ def Binman(options, args):
|
||||||
# without changing the device-tree size, thus ensuring that our
|
# without changing the device-tree size, thus ensuring that our
|
||||||
# entry offsets remain the same.
|
# entry offsets remain the same.
|
||||||
for image in images.values():
|
for image in images.values():
|
||||||
|
image.ExpandEntries()
|
||||||
if options.update_fdt:
|
if options.update_fdt:
|
||||||
image.AddMissingProperties()
|
image.AddMissingProperties()
|
||||||
image.ProcessFdt(dtb)
|
image.ProcessFdt(dtb)
|
||||||
|
|
||||||
dtb.Pack()
|
for dtb_item in state.GetFdts():
|
||||||
dtb.Flush()
|
dtb_item.Sync(auto_resize=True)
|
||||||
|
dtb_item.Pack()
|
||||||
|
dtb_item.Flush()
|
||||||
|
|
||||||
for image in images.values():
|
for image in images.values():
|
||||||
# Perform all steps for this image, including checking and
|
# Perform all steps for this image, including checking and
|
||||||
|
@ -184,19 +163,30 @@ def Binman(options, args):
|
||||||
# completed and written, but that does not seem important.
|
# completed and written, but that does not seem important.
|
||||||
image.GetEntryContents()
|
image.GetEntryContents()
|
||||||
image.GetEntryOffsets()
|
image.GetEntryOffsets()
|
||||||
image.PackEntries()
|
try:
|
||||||
image.CheckSize()
|
image.PackEntries()
|
||||||
image.CheckEntries()
|
image.CheckSize()
|
||||||
|
image.CheckEntries()
|
||||||
|
except Exception as e:
|
||||||
|
if options.map:
|
||||||
|
fname = image.WriteMap()
|
||||||
|
print "Wrote map file '%s' to show errors" % fname
|
||||||
|
raise
|
||||||
image.SetImagePos()
|
image.SetImagePos()
|
||||||
if options.update_fdt:
|
if options.update_fdt:
|
||||||
image.SetCalculatedProperties()
|
image.SetCalculatedProperties()
|
||||||
|
for dtb_item in state.GetFdts():
|
||||||
|
dtb_item.Sync()
|
||||||
image.ProcessEntryContents()
|
image.ProcessEntryContents()
|
||||||
image.WriteSymbols()
|
image.WriteSymbols()
|
||||||
image.BuildImage()
|
image.BuildImage()
|
||||||
if options.map:
|
if options.map:
|
||||||
image.WriteMap()
|
image.WriteMap()
|
||||||
with open(fname, 'wb') as outfd:
|
|
||||||
outfd.write(dtb.GetContents())
|
# Write the updated FDTs to our output files
|
||||||
|
for dtb_item in state.GetFdts():
|
||||||
|
tools.WriteFile(dtb_item._fname, dtb_item.GetContents())
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
tools.FinaliseOutputDir()
|
tools.FinaliseOutputDir()
|
||||||
finally:
|
finally:
|
||||||
|
|
|
@ -17,10 +17,12 @@ try:
|
||||||
except:
|
except:
|
||||||
have_importlib = False
|
have_importlib = False
|
||||||
|
|
||||||
import fdt_util
|
|
||||||
import control
|
|
||||||
import os
|
import os
|
||||||
|
from sets import Set
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import fdt_util
|
||||||
|
import state
|
||||||
import tools
|
import tools
|
||||||
|
|
||||||
modules = {}
|
modules = {}
|
||||||
|
@ -74,6 +76,7 @@ class Entry(object):
|
||||||
self.pad_after = 0
|
self.pad_after = 0
|
||||||
self.offset_unset = False
|
self.offset_unset = False
|
||||||
self.image_pos = None
|
self.image_pos = None
|
||||||
|
self._expand_size = False
|
||||||
if read_node:
|
if read_node:
|
||||||
self.ReadNode()
|
self.ReadNode()
|
||||||
|
|
||||||
|
@ -159,20 +162,57 @@ class Entry(object):
|
||||||
"of two" % (self._node.path, self.align_size))
|
"of two" % (self._node.path, self.align_size))
|
||||||
self.align_end = fdt_util.GetInt(self._node, 'align-end')
|
self.align_end = fdt_util.GetInt(self._node, 'align-end')
|
||||||
self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
|
self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
|
||||||
|
self.expand_size = fdt_util.GetBool(self._node, 'expand-size')
|
||||||
|
|
||||||
|
def GetDefaultFilename(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def GetFdtSet(self):
|
||||||
|
"""Get the set of device trees used by this entry
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Set containing the filename from this entry, if it is a .dtb, else
|
||||||
|
an empty set
|
||||||
|
"""
|
||||||
|
fname = self.GetDefaultFilename()
|
||||||
|
# It would be better to use isinstance(self, Entry_blob_dtb) here but
|
||||||
|
# we cannot access Entry_blob_dtb
|
||||||
|
if fname and fname.endswith('.dtb'):
|
||||||
|
return Set([fname])
|
||||||
|
return Set()
|
||||||
|
|
||||||
|
def ExpandEntries(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def AddMissingProperties(self):
|
def AddMissingProperties(self):
|
||||||
"""Add new properties to the device tree as needed for this entry"""
|
"""Add new properties to the device tree as needed for this entry"""
|
||||||
for prop in ['offset', 'size', 'image-pos']:
|
for prop in ['offset', 'size', 'image-pos']:
|
||||||
if not prop in self._node.props:
|
if not prop in self._node.props:
|
||||||
self._node.AddZeroProp(prop)
|
state.AddZeroProp(self._node, prop)
|
||||||
|
err = state.CheckAddHashProp(self._node)
|
||||||
|
if err:
|
||||||
|
self.Raise(err)
|
||||||
|
|
||||||
def SetCalculatedProperties(self):
|
def SetCalculatedProperties(self):
|
||||||
"""Set the value of device-tree properties calculated by binman"""
|
"""Set the value of device-tree properties calculated by binman"""
|
||||||
self._node.SetInt('offset', self.offset)
|
state.SetInt(self._node, 'offset', self.offset)
|
||||||
self._node.SetInt('size', self.size)
|
state.SetInt(self._node, 'size', self.size)
|
||||||
self._node.SetInt('image-pos', self.image_pos)
|
state.SetInt(self._node, 'image-pos',
|
||||||
|
self.image_pos - self.section.GetRootSkipAtStart())
|
||||||
|
state.CheckSetHashValue(self._node, self.GetData)
|
||||||
|
|
||||||
def ProcessFdt(self, fdt):
|
def ProcessFdt(self, fdt):
|
||||||
|
"""Allow entries to adjust the device tree
|
||||||
|
|
||||||
|
Some entries need to adjust the device tree for their purposes. This
|
||||||
|
may involve adding or deleting properties.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if processing is complete
|
||||||
|
False if processing could not be completed due to a dependency.
|
||||||
|
This will cause the entry to be retried after others have been
|
||||||
|
called
|
||||||
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def SetPrefix(self, prefix):
|
def SetPrefix(self, prefix):
|
||||||
|
@ -350,10 +390,17 @@ class Entry(object):
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def GetStr(value):
|
||||||
|
if value is None:
|
||||||
|
return '<none> '
|
||||||
|
return '%08x' % value
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def WriteMapLine(fd, indent, name, offset, size, image_pos):
|
def WriteMapLine(fd, indent, name, offset, size, image_pos):
|
||||||
print('%08x %s%08x %08x %s' % (image_pos, ' ' * indent, offset,
|
print('%s %s%s %s %s' % (Entry.GetStr(image_pos), ' ' * indent,
|
||||||
size, name), file=fd)
|
Entry.GetStr(offset), Entry.GetStr(size),
|
||||||
|
name), file=fd)
|
||||||
|
|
||||||
def WriteMap(self, fd, indent):
|
def WriteMap(self, fd, indent):
|
||||||
"""Write a map of the entry to a .map file
|
"""Write a map of the entry to a .map file
|
||||||
|
@ -390,7 +437,7 @@ class Entry(object):
|
||||||
Raises:
|
Raises:
|
||||||
ValueError if the argument cannot be converted to in
|
ValueError if the argument cannot be converted to in
|
||||||
"""
|
"""
|
||||||
value = control.GetEntryArg(name)
|
value = state.GetEntryArg(name)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
if datatype == int:
|
if datatype == int:
|
||||||
try:
|
try:
|
||||||
|
@ -456,3 +503,30 @@ features to produce new behaviours.
|
||||||
if missing:
|
if missing:
|
||||||
raise ValueError('Documentation is missing for modules: %s' %
|
raise ValueError('Documentation is missing for modules: %s' %
|
||||||
', '.join(missing))
|
', '.join(missing))
|
||||||
|
|
||||||
|
def GetUniqueName(self):
|
||||||
|
"""Get a unique name for a node
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
String containing a unique name for a node, consisting of the name
|
||||||
|
of all ancestors (starting from within the 'binman' node) separated
|
||||||
|
by a dot ('.'). This can be useful for generating unique filesnames
|
||||||
|
in the output directory.
|
||||||
|
"""
|
||||||
|
name = self.name
|
||||||
|
node = self._node
|
||||||
|
while node.parent:
|
||||||
|
node = node.parent
|
||||||
|
if node.name == 'binman':
|
||||||
|
break
|
||||||
|
name = '%s.%s' % (node.name, name)
|
||||||
|
return name
|
||||||
|
|
||||||
|
def ExpandToLimit(self, limit):
|
||||||
|
"""Expand an entry so that it ends at the given offset limit"""
|
||||||
|
if self.offset + self.size < limit:
|
||||||
|
self.size = limit - self.offset
|
||||||
|
# Request the contents again, since changing the size requires that
|
||||||
|
# the data grows. This should not fail, but check it to be sure.
|
||||||
|
if not self.ObtainContents():
|
||||||
|
self.Raise('Cannot obtain contents when expanding entry')
|
||||||
|
|
|
@ -54,6 +54,22 @@ class TestEntry(unittest.TestCase):
|
||||||
self.assertIn("Unknown entry type 'invalid-name' in node "
|
self.assertIn("Unknown entry type 'invalid-name' in node "
|
||||||
"'invalid-path'", str(e.exception))
|
"'invalid-path'", str(e.exception))
|
||||||
|
|
||||||
|
def testUniqueName(self):
|
||||||
|
"""Test Entry.GetUniqueName"""
|
||||||
|
import entry
|
||||||
|
Node = collections.namedtuple('Node', ['name', 'parent'])
|
||||||
|
base_node = Node('root', None)
|
||||||
|
base_entry = entry.Entry(None, None, base_node, read_node=False)
|
||||||
|
self.assertEqual('root', base_entry.GetUniqueName())
|
||||||
|
sub_node = Node('subnode', base_node)
|
||||||
|
sub_entry = entry.Entry(None, None, sub_node, read_node=False)
|
||||||
|
self.assertEqual('root.subnode', sub_entry.GetUniqueName())
|
||||||
|
|
||||||
|
def testGetDefaultFilename(self):
|
||||||
|
"""Trivial test for this base class function"""
|
||||||
|
import entry
|
||||||
|
base_entry = entry.Entry(None, None, None, read_node=False)
|
||||||
|
self.assertIsNone(base_entry.GetDefaultFilename())
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -48,6 +48,8 @@ class Entry__testing(Entry):
|
||||||
'return-unknown-contents')
|
'return-unknown-contents')
|
||||||
self.bad_update_contents = fdt_util.GetBool(self._node,
|
self.bad_update_contents = fdt_util.GetBool(self._node,
|
||||||
'bad-update-contents')
|
'bad-update-contents')
|
||||||
|
self.return_contents_once = fdt_util.GetBool(self._node,
|
||||||
|
'return-contents-once')
|
||||||
|
|
||||||
# Set to True when the entry is ready to process the FDT.
|
# Set to True when the entry is ready to process the FDT.
|
||||||
self.process_fdt_ready = False
|
self.process_fdt_ready = False
|
||||||
|
@ -68,12 +70,15 @@ class Entry__testing(Entry):
|
||||||
EntryArg('test-existing-prop', str)], self.require_args)
|
EntryArg('test-existing-prop', str)], self.require_args)
|
||||||
if self.force_bad_datatype:
|
if self.force_bad_datatype:
|
||||||
self.GetEntryArgsOrProps([EntryArg('test-bad-datatype-arg', bool)])
|
self.GetEntryArgsOrProps([EntryArg('test-bad-datatype-arg', bool)])
|
||||||
|
self.return_contents = True
|
||||||
|
|
||||||
def ObtainContents(self):
|
def ObtainContents(self):
|
||||||
if self.return_unknown_contents:
|
if self.return_unknown_contents or not self.return_contents:
|
||||||
return False
|
return False
|
||||||
self.data = 'a'
|
self.data = 'a'
|
||||||
self.contents_size = len(self.data)
|
self.contents_size = len(self.data)
|
||||||
|
if self.return_contents_once:
|
||||||
|
self.return_contents = False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def GetOffsets(self):
|
def GetOffsets(self):
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
from entry import Entry
|
from entry import Entry
|
||||||
import fdt_util
|
import fdt_util
|
||||||
|
import state
|
||||||
import tools
|
import tools
|
||||||
|
|
||||||
class Entry_blob(Entry):
|
class Entry_blob(Entry):
|
||||||
|
@ -17,14 +18,23 @@ class Entry_blob(Entry):
|
||||||
|
|
||||||
Properties / Entry arguments:
|
Properties / Entry arguments:
|
||||||
- filename: Filename of file to read into entry
|
- filename: Filename of file to read into entry
|
||||||
|
- compress: Compression algorithm to use:
|
||||||
|
none: No compression
|
||||||
|
lz4: Use lz4 compression (via 'lz4' command-line utility)
|
||||||
|
|
||||||
This entry reads data from a file and places it in the entry. The
|
This entry reads data from a file and places it in the entry. The
|
||||||
default filename is often specified specified by the subclass. See for
|
default filename is often specified specified by the subclass. See for
|
||||||
example the 'u_boot' entry which provides the filename 'u-boot.bin'.
|
example the 'u_boot' entry which provides the filename 'u-boot.bin'.
|
||||||
|
|
||||||
|
If compression is enabled, an extra 'uncomp-size' property is written to
|
||||||
|
the node (if enabled with -u) which provides the uncompressed size of the
|
||||||
|
data.
|
||||||
"""
|
"""
|
||||||
def __init__(self, section, etype, node):
|
def __init__(self, section, etype, node):
|
||||||
Entry.__init__(self, section, etype, node)
|
Entry.__init__(self, section, etype, node)
|
||||||
self._filename = fdt_util.GetString(self._node, "filename", self.etype)
|
self._filename = fdt_util.GetString(self._node, 'filename', self.etype)
|
||||||
|
self._compress = fdt_util.GetString(self._node, 'compress', 'none')
|
||||||
|
self._uncompressed_size = None
|
||||||
|
|
||||||
def ObtainContents(self):
|
def ObtainContents(self):
|
||||||
self._filename = self.GetDefaultFilename()
|
self._filename = self.GetDefaultFilename()
|
||||||
|
@ -33,15 +43,36 @@ class Entry_blob(Entry):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def ReadBlobContents(self):
|
def ReadBlobContents(self):
|
||||||
with open(self._pathname) as fd:
|
# We assume the data is small enough to fit into memory. If this
|
||||||
# We assume the data is small enough to fit into memory. If this
|
# is used for large filesystem image that might not be true.
|
||||||
# is used for large filesystem image that might not be true.
|
# In that case, Image.BuildImage() could be adjusted to use a
|
||||||
# In that case, Image.BuildImage() could be adjusted to use a
|
# new Entry method which can read in chunks. Then we could copy
|
||||||
# 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
|
||||||
# the data in chunks and avoid reading it all at once. For now
|
# this seems like an unnecessary complication.
|
||||||
# this seems like an unnecessary complication.
|
data = tools.ReadFile(self._pathname)
|
||||||
self.SetContents(fd.read())
|
if self._compress == 'lz4':
|
||||||
|
self._uncompressed_size = len(data)
|
||||||
|
'''
|
||||||
|
import lz4 # Import this only if needed (python-lz4 dependency)
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = lz4.frame.compress(data)
|
||||||
|
except AttributeError:
|
||||||
|
data = lz4.compress(data)
|
||||||
|
'''
|
||||||
|
data = tools.Run('lz4', '-c', self._pathname, )
|
||||||
|
self.SetContents(data)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def GetDefaultFilename(self):
|
def GetDefaultFilename(self):
|
||||||
return self._filename
|
return self._filename
|
||||||
|
|
||||||
|
def AddMissingProperties(self):
|
||||||
|
Entry.AddMissingProperties(self)
|
||||||
|
if self._compress != 'none':
|
||||||
|
state.AddZeroProp(self._node, 'uncomp-size')
|
||||||
|
|
||||||
|
def SetCalculatedProperties(self):
|
||||||
|
Entry.SetCalculatedProperties(self)
|
||||||
|
if self._uncompressed_size is not None:
|
||||||
|
state.SetInt(self._node, 'uncomp-size', self._uncompressed_size)
|
||||||
|
|
33
tools/binman/etype/blob_dtb.py
Normal file
33
tools/binman/etype/blob_dtb.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
# Copyright (c) 2018 Google, Inc
|
||||||
|
# Written by Simon Glass <sjg@chromium.org>
|
||||||
|
#
|
||||||
|
# Entry-type module for U-Boot device tree files
|
||||||
|
#
|
||||||
|
|
||||||
|
import state
|
||||||
|
|
||||||
|
from entry import Entry
|
||||||
|
from blob import Entry_blob
|
||||||
|
|
||||||
|
class Entry_blob_dtb(Entry_blob):
|
||||||
|
"""A blob that holds a device tree
|
||||||
|
|
||||||
|
This is a blob containing a device tree. The contents of the blob are
|
||||||
|
obtained from the list of available device-tree files, managed by the
|
||||||
|
'state' module.
|
||||||
|
"""
|
||||||
|
def __init__(self, section, etype, node):
|
||||||
|
Entry_blob.__init__(self, section, etype, node)
|
||||||
|
|
||||||
|
def ObtainContents(self):
|
||||||
|
"""Get the device-tree from the list held by the 'state' module"""
|
||||||
|
self._filename = self.GetDefaultFilename()
|
||||||
|
self._pathname, data = state.GetFdtContents(self._filename)
|
||||||
|
self.SetContents(data)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def ProcessContents(self):
|
||||||
|
"""Re-read the DTB contents so that we get any calculated properties"""
|
||||||
|
_, data = state.GetFdtContents(self._filename)
|
||||||
|
self.SetContents(data)
|
57
tools/binman/etype/files.py
Normal file
57
tools/binman/etype/files.py
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
# Copyright (c) 2018 Google, Inc
|
||||||
|
# Written by Simon Glass <sjg@chromium.org>
|
||||||
|
#
|
||||||
|
# Entry-type module for a set of files which are placed in individual
|
||||||
|
# sub-entries
|
||||||
|
#
|
||||||
|
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
|
||||||
|
from section import Entry_section
|
||||||
|
import fdt_util
|
||||||
|
import state
|
||||||
|
import tools
|
||||||
|
|
||||||
|
import bsection
|
||||||
|
|
||||||
|
class Entry_files(Entry_section):
|
||||||
|
"""Entry containing a set of files
|
||||||
|
|
||||||
|
Properties / Entry arguments:
|
||||||
|
- pattern: Filename pattern to match the files to include
|
||||||
|
- compress: Compression algorithm to use:
|
||||||
|
none: No compression
|
||||||
|
lz4: Use lz4 compression (via 'lz4' command-line utility)
|
||||||
|
|
||||||
|
This entry reads a number of files and places each in a separate sub-entry
|
||||||
|
within this entry. To access these you need to enable device-tree updates
|
||||||
|
at run-time so you can obtain the file positions.
|
||||||
|
"""
|
||||||
|
def __init__(self, section, etype, node):
|
||||||
|
Entry_section.__init__(self, section, etype, node)
|
||||||
|
self._pattern = fdt_util.GetString(self._node, 'pattern')
|
||||||
|
if not self._pattern:
|
||||||
|
self.Raise("Missing 'pattern' property")
|
||||||
|
self._compress = fdt_util.GetString(self._node, 'compress', 'none')
|
||||||
|
self._require_matches = fdt_util.GetBool(self._node,
|
||||||
|
'require-matches')
|
||||||
|
|
||||||
|
def ExpandEntries(self):
|
||||||
|
files = tools.GetInputFilenameGlob(self._pattern)
|
||||||
|
if self._require_matches and not files:
|
||||||
|
self.Raise("Pattern '%s' matched no files" % self._pattern)
|
||||||
|
for fname in files:
|
||||||
|
if not os.path.isfile(fname):
|
||||||
|
continue
|
||||||
|
name = os.path.basename(fname)
|
||||||
|
subnode = self._node.FindNode(name)
|
||||||
|
if not subnode:
|
||||||
|
subnode = state.AddSubnode(self._node, name)
|
||||||
|
state.AddString(subnode, 'type', 'blob')
|
||||||
|
state.AddString(subnode, 'filename', fname)
|
||||||
|
state.AddString(subnode, 'compress', self._compress)
|
||||||
|
|
||||||
|
# Read entries again, now that we have some
|
||||||
|
self._section._ReadEntries()
|
|
@ -23,7 +23,7 @@ class Entry_fill(Entry):
|
||||||
"""
|
"""
|
||||||
def __init__(self, section, etype, node):
|
def __init__(self, section, etype, node):
|
||||||
Entry.__init__(self, section, etype, node)
|
Entry.__init__(self, section, etype, node)
|
||||||
if not self.size:
|
if self.size is None:
|
||||||
self.Raise("'fill' entry must have a size property")
|
self.Raise("'fill' entry must have a size property")
|
||||||
self.fill_value = fdt_util.GetByte(self._node, 'fill-byte', 0)
|
self.fill_value = fdt_util.GetByte(self._node, 'fill-byte', 0)
|
||||||
|
|
||||||
|
|
|
@ -42,14 +42,17 @@ class Entry_fmap(Entry):
|
||||||
for subentry in entries.values():
|
for subentry in entries.values():
|
||||||
_AddEntries(areas, subentry)
|
_AddEntries(areas, subentry)
|
||||||
else:
|
else:
|
||||||
areas.append(fmap_util.FmapArea(entry.image_pos or 0,
|
pos = entry.image_pos
|
||||||
entry.size or 0, entry.name, 0))
|
if pos is not None:
|
||||||
|
pos -= entry.section.GetRootSkipAtStart()
|
||||||
|
areas.append(fmap_util.FmapArea(pos or 0, entry.size or 0,
|
||||||
|
entry.name, 0))
|
||||||
|
|
||||||
entries = self.section.GetEntries()
|
entries = self.section._image.GetEntries()
|
||||||
areas = []
|
areas = []
|
||||||
for entry in entries.values():
|
for entry in entries.values():
|
||||||
_AddEntries(areas, entry)
|
_AddEntries(areas, entry)
|
||||||
return fmap_util.EncodeFmap(self.section.GetSize() or 0, self.name,
|
return fmap_util.EncodeFmap(self.section.GetImageSize() or 0, self.name,
|
||||||
areas)
|
areas)
|
||||||
|
|
||||||
def ObtainContents(self):
|
def ObtainContents(self):
|
||||||
|
|
|
@ -32,11 +32,19 @@ class Entry_section(Entry):
|
||||||
"""
|
"""
|
||||||
def __init__(self, section, etype, node):
|
def __init__(self, section, etype, node):
|
||||||
Entry.__init__(self, section, etype, node)
|
Entry.__init__(self, section, etype, node)
|
||||||
self._section = bsection.Section(node.name, node)
|
self._section = bsection.Section(node.name, section, node,
|
||||||
|
section._image)
|
||||||
|
|
||||||
|
def GetFdtSet(self):
|
||||||
|
return self._section.GetFdtSet()
|
||||||
|
|
||||||
def ProcessFdt(self, fdt):
|
def ProcessFdt(self, fdt):
|
||||||
return self._section.ProcessFdt(fdt)
|
return self._section.ProcessFdt(fdt)
|
||||||
|
|
||||||
|
def ExpandEntries(self):
|
||||||
|
Entry.ExpandEntries(self)
|
||||||
|
self._section.ExpandEntries()
|
||||||
|
|
||||||
def AddMissingProperties(self):
|
def AddMissingProperties(self):
|
||||||
Entry.AddMissingProperties(self)
|
Entry.AddMissingProperties(self)
|
||||||
self._section.AddMissingProperties()
|
self._section.AddMissingProperties()
|
||||||
|
@ -92,3 +100,7 @@ class Entry_section(Entry):
|
||||||
|
|
||||||
def GetEntries(self):
|
def GetEntries(self):
|
||||||
return self._section.GetEntries()
|
return self._section.GetEntries()
|
||||||
|
|
||||||
|
def ExpandToLimit(self, limit):
|
||||||
|
super(Entry_section, self).ExpandToLimit(limit)
|
||||||
|
self._section.ExpandSize(self.size)
|
||||||
|
|
|
@ -51,6 +51,9 @@ class Entry_text(Entry):
|
||||||
self.text_label, = self.GetEntryArgsOrProps(
|
self.text_label, = self.GetEntryArgsOrProps(
|
||||||
[EntryArg('text-label', str)])
|
[EntryArg('text-label', str)])
|
||||||
self.value, = self.GetEntryArgsOrProps([EntryArg(self.text_label, str)])
|
self.value, = self.GetEntryArgsOrProps([EntryArg(self.text_label, str)])
|
||||||
|
if not self.value:
|
||||||
|
self.Raise("No value provided for text label '%s'" %
|
||||||
|
self.text_label)
|
||||||
|
|
||||||
def ObtainContents(self):
|
def ObtainContents(self):
|
||||||
self.SetContents(self.value)
|
self.SetContents(self.value)
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
from entry import Entry
|
from entry import Entry
|
||||||
from blob import Entry_blob
|
from blob_dtb import Entry_blob_dtb
|
||||||
|
|
||||||
class Entry_u_boot_dtb(Entry_blob):
|
class Entry_u_boot_dtb(Entry_blob_dtb):
|
||||||
"""U-Boot device tree
|
"""U-Boot device tree
|
||||||
|
|
||||||
Properties / Entry arguments:
|
Properties / Entry arguments:
|
||||||
|
@ -17,9 +17,12 @@ class Entry_u_boot_dtb(Entry_blob):
|
||||||
This is the U-Boot device tree, containing configuration information for
|
This is the U-Boot device tree, containing configuration information for
|
||||||
U-Boot. U-Boot needs this to know what devices are present and which drivers
|
U-Boot. U-Boot needs this to know what devices are present and which drivers
|
||||||
to activate.
|
to activate.
|
||||||
|
|
||||||
|
Note: This is mostly an internal entry type, used by others. This allows
|
||||||
|
binman to know which entries contain a device tree.
|
||||||
"""
|
"""
|
||||||
def __init__(self, section, etype, node):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__init__(self, section, etype, node)
|
Entry_blob_dtb.__init__(self, section, etype, node)
|
||||||
|
|
||||||
def GetDefaultFilename(self):
|
def GetDefaultFilename(self):
|
||||||
return 'u-boot.dtb'
|
return 'u-boot.dtb'
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
# Entry-type module for U-Boot device tree with the microcode removed
|
# Entry-type module for U-Boot device tree with the microcode removed
|
||||||
#
|
#
|
||||||
|
|
||||||
import control
|
|
||||||
from entry import Entry
|
from entry import Entry
|
||||||
from blob import Entry_blob
|
from blob_dtb import Entry_blob_dtb
|
||||||
|
import state
|
||||||
import tools
|
import tools
|
||||||
|
|
||||||
class Entry_u_boot_dtb_with_ucode(Entry_blob):
|
class Entry_u_boot_dtb_with_ucode(Entry_blob_dtb):
|
||||||
"""A U-Boot device tree file, with the microcode removed
|
"""A U-Boot device tree file, with the microcode removed
|
||||||
|
|
||||||
Properties / Entry arguments:
|
Properties / Entry arguments:
|
||||||
|
@ -25,7 +25,7 @@ class Entry_u_boot_dtb_with_ucode(Entry_blob):
|
||||||
it available to u_boot_ucode.
|
it available to u_boot_ucode.
|
||||||
"""
|
"""
|
||||||
def __init__(self, section, etype, node):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__init__(self, section, etype, node)
|
Entry_blob_dtb.__init__(self, section, etype, node)
|
||||||
self.ucode_data = ''
|
self.ucode_data = ''
|
||||||
self.collate = False
|
self.collate = False
|
||||||
self.ucode_offset = None
|
self.ucode_offset = None
|
||||||
|
@ -43,6 +43,9 @@ class Entry_u_boot_dtb_with_ucode(Entry_blob):
|
||||||
# If the section does not need microcode, there is nothing to do
|
# If the section does not need microcode, there is nothing to do
|
||||||
ucode_dest_entry = self.section.FindEntryType(
|
ucode_dest_entry = self.section.FindEntryType(
|
||||||
'u-boot-spl-with-ucode-ptr')
|
'u-boot-spl-with-ucode-ptr')
|
||||||
|
if not ucode_dest_entry or not ucode_dest_entry.target_offset:
|
||||||
|
ucode_dest_entry = self.section.FindEntryType(
|
||||||
|
'u-boot-tpl-with-ucode-ptr')
|
||||||
if not ucode_dest_entry or not ucode_dest_entry.target_offset:
|
if not ucode_dest_entry or not ucode_dest_entry.target_offset:
|
||||||
ucode_dest_entry = self.section.FindEntryType(
|
ucode_dest_entry = self.section.FindEntryType(
|
||||||
'u-boot-with-ucode-ptr')
|
'u-boot-with-ucode-ptr')
|
||||||
|
@ -51,7 +54,7 @@ class Entry_u_boot_dtb_with_ucode(Entry_blob):
|
||||||
|
|
||||||
# Remove the microcode
|
# Remove the microcode
|
||||||
fname = self.GetDefaultFilename()
|
fname = self.GetDefaultFilename()
|
||||||
fdt = control.GetFdt(fname)
|
fdt = state.GetFdt(fname)
|
||||||
self.ucode = fdt.GetNode('/microcode')
|
self.ucode = fdt.GetNode('/microcode')
|
||||||
if not self.ucode:
|
if not self.ucode:
|
||||||
raise self.Raise("No /microcode node found in '%s'" % fname)
|
raise self.Raise("No /microcode node found in '%s'" % fname)
|
||||||
|
@ -69,15 +72,15 @@ class Entry_u_boot_dtb_with_ucode(Entry_blob):
|
||||||
|
|
||||||
def ObtainContents(self):
|
def ObtainContents(self):
|
||||||
# Call the base class just in case it does something important.
|
# Call the base class just in case it does something important.
|
||||||
Entry_blob.ObtainContents(self)
|
Entry_blob_dtb.ObtainContents(self)
|
||||||
self._pathname = control.GetFdtPath(self._filename)
|
if self.ucode and not self.collate:
|
||||||
self.ReadBlobContents()
|
|
||||||
if self.ucode:
|
|
||||||
for node in self.ucode.subnodes:
|
for node in self.ucode.subnodes:
|
||||||
data_prop = node.props.get('data')
|
data_prop = node.props.get('data')
|
||||||
if data_prop and not self.collate:
|
if data_prop:
|
||||||
# Find the offset in the device tree of the ucode data
|
# Find the offset in the device tree of the ucode data
|
||||||
self.ucode_offset = data_prop.GetOffset() + 12
|
self.ucode_offset = data_prop.GetOffset() + 12
|
||||||
self.ucode_size = len(data_prop.bytes)
|
self.ucode_size = len(data_prop.bytes)
|
||||||
self.ready = True
|
self.ready = True
|
||||||
return True
|
else:
|
||||||
|
self.ready = True
|
||||||
|
return self.ready
|
||||||
|
|
39
tools/binman/etype/u_boot_elf.py
Normal file
39
tools/binman/etype/u_boot_elf.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
# Copyright (c) 2018 Google, Inc
|
||||||
|
# Written by Simon Glass <sjg@chromium.org>
|
||||||
|
#
|
||||||
|
# Entry-type module for U-Boot ELF image
|
||||||
|
#
|
||||||
|
|
||||||
|
from entry import Entry
|
||||||
|
from blob import Entry_blob
|
||||||
|
|
||||||
|
import fdt_util
|
||||||
|
import tools
|
||||||
|
|
||||||
|
class Entry_u_boot_elf(Entry_blob):
|
||||||
|
"""U-Boot ELF image
|
||||||
|
|
||||||
|
Properties / Entry arguments:
|
||||||
|
- filename: Filename of u-boot (default 'u-boot')
|
||||||
|
|
||||||
|
This is the U-Boot ELF image. It does not include a device tree but can be
|
||||||
|
relocated to any address for execution.
|
||||||
|
"""
|
||||||
|
def __init__(self, section, etype, node):
|
||||||
|
Entry_blob.__init__(self, section, etype, node)
|
||||||
|
self._strip = fdt_util.GetBool(self._node, 'strip')
|
||||||
|
|
||||||
|
def ReadBlobContents(self):
|
||||||
|
if self._strip:
|
||||||
|
uniq = self.GetUniqueName()
|
||||||
|
out_fname = tools.GetOutputFilename('%s.stripped' % uniq)
|
||||||
|
tools.WriteFile(out_fname, tools.ReadFile(self._pathname))
|
||||||
|
tools.Run('strip', out_fname)
|
||||||
|
self.SetContents(tools.ReadFile(out_fname))
|
||||||
|
else:
|
||||||
|
self.SetContents(tools.ReadFile(self._pathname))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def GetDefaultFilename(self):
|
||||||
|
return 'u-boot'
|
|
@ -6,9 +6,9 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
from entry import Entry
|
from entry import Entry
|
||||||
from blob import Entry_blob
|
from blob_dtb import Entry_blob_dtb
|
||||||
|
|
||||||
class Entry_u_boot_spl_dtb(Entry_blob):
|
class Entry_u_boot_spl_dtb(Entry_blob_dtb):
|
||||||
"""U-Boot SPL device tree
|
"""U-Boot SPL device tree
|
||||||
|
|
||||||
Properties / Entry arguments:
|
Properties / Entry arguments:
|
||||||
|
@ -19,7 +19,7 @@ class Entry_u_boot_spl_dtb(Entry_blob):
|
||||||
to activate.
|
to activate.
|
||||||
"""
|
"""
|
||||||
def __init__(self, section, etype, node):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__init__(self, section, etype, node)
|
Entry_blob_dtb.__init__(self, section, etype, node)
|
||||||
|
|
||||||
def GetDefaultFilename(self):
|
def GetDefaultFilename(self):
|
||||||
return 'spl/u-boot-spl.dtb'
|
return 'spl/u-boot-spl.dtb'
|
||||||
|
|
24
tools/binman/etype/u_boot_spl_elf.py
Normal file
24
tools/binman/etype/u_boot_spl_elf.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
# Copyright (c) 2018 Google, Inc
|
||||||
|
# Written by Simon Glass <sjg@chromium.org>
|
||||||
|
#
|
||||||
|
# Entry-type module for U-Boot SPL ELF image
|
||||||
|
#
|
||||||
|
|
||||||
|
from entry import Entry
|
||||||
|
from blob import Entry_blob
|
||||||
|
|
||||||
|
class Entry_u_boot_spl_elf(Entry_blob):
|
||||||
|
"""U-Boot SPL ELF image
|
||||||
|
|
||||||
|
Properties / Entry arguments:
|
||||||
|
- filename: Filename of SPL u-boot (default 'spl/u-boot')
|
||||||
|
|
||||||
|
This is the U-Boot SPL ELF image. It does not include a device tree but can
|
||||||
|
be relocated to any address for execution.
|
||||||
|
"""
|
||||||
|
def __init__(self, section, etype, node):
|
||||||
|
Entry_blob.__init__(self, section, etype, node)
|
||||||
|
|
||||||
|
def GetDefaultFilename(self):
|
||||||
|
return 'spl/u-boot-spl'
|
|
@ -16,6 +16,8 @@ import tools
|
||||||
class Entry_u_boot_spl_with_ucode_ptr(Entry_u_boot_with_ucode_ptr):
|
class Entry_u_boot_spl_with_ucode_ptr(Entry_u_boot_with_ucode_ptr):
|
||||||
"""U-Boot SPL with embedded microcode pointer
|
"""U-Boot SPL with embedded microcode pointer
|
||||||
|
|
||||||
|
This is used when SPL must set up the microcode for U-Boot.
|
||||||
|
|
||||||
See Entry_u_boot_ucode for full details of the entries involved in this
|
See Entry_u_boot_ucode for full details of the entries involved in this
|
||||||
process.
|
process.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
from entry import Entry
|
from entry import Entry
|
||||||
from blob import Entry_blob
|
from blob_dtb import Entry_blob_dtb
|
||||||
|
|
||||||
class Entry_u_boot_tpl_dtb(Entry_blob):
|
class Entry_u_boot_tpl_dtb(Entry_blob_dtb):
|
||||||
"""U-Boot TPL device tree
|
"""U-Boot TPL device tree
|
||||||
|
|
||||||
Properties / Entry arguments:
|
Properties / Entry arguments:
|
||||||
|
@ -19,7 +19,7 @@ class Entry_u_boot_tpl_dtb(Entry_blob):
|
||||||
to activate.
|
to activate.
|
||||||
"""
|
"""
|
||||||
def __init__(self, section, etype, node):
|
def __init__(self, section, etype, node):
|
||||||
Entry_blob.__init__(self, section, etype, node)
|
Entry_blob_dtb.__init__(self, section, etype, node)
|
||||||
|
|
||||||
def GetDefaultFilename(self):
|
def GetDefaultFilename(self):
|
||||||
return 'tpl/u-boot-tpl.dtb'
|
return 'tpl/u-boot-tpl.dtb'
|
||||||
|
|
25
tools/binman/etype/u_boot_tpl_dtb_with_ucode.py
Normal file
25
tools/binman/etype/u_boot_tpl_dtb_with_ucode.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
# Copyright (c) 2016 Google, Inc
|
||||||
|
# Written by Simon Glass <sjg@chromium.org>
|
||||||
|
#
|
||||||
|
# Entry-type module for U-Boot device tree with the microcode removed
|
||||||
|
#
|
||||||
|
|
||||||
|
import control
|
||||||
|
from entry import Entry
|
||||||
|
from u_boot_dtb_with_ucode import Entry_u_boot_dtb_with_ucode
|
||||||
|
import tools
|
||||||
|
|
||||||
|
class Entry_u_boot_tpl_dtb_with_ucode(Entry_u_boot_dtb_with_ucode):
|
||||||
|
"""U-Boot TPL with embedded microcode pointer
|
||||||
|
|
||||||
|
This is used when TPL must set up the microcode for U-Boot.
|
||||||
|
|
||||||
|
See Entry_u_boot_ucode for full details of the entries involved in this
|
||||||
|
process.
|
||||||
|
"""
|
||||||
|
def __init__(self, section, etype, node):
|
||||||
|
Entry_u_boot_dtb_with_ucode.__init__(self, section, etype, node)
|
||||||
|
|
||||||
|
def GetDefaultFilename(self):
|
||||||
|
return 'tpl/u-boot-tpl.dtb'
|
27
tools/binman/etype/u_boot_tpl_with_ucode_ptr.py
Normal file
27
tools/binman/etype/u_boot_tpl_with_ucode_ptr.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
# Copyright (c) 2016 Google, Inc
|
||||||
|
# Written by Simon Glass <sjg@chromium.org>
|
||||||
|
#
|
||||||
|
# Entry-type module for an TPL 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_tpl_with_ucode_ptr(Entry_u_boot_with_ucode_ptr):
|
||||||
|
"""U-Boot TPL with embedded microcode pointer
|
||||||
|
|
||||||
|
See Entry_u_boot_ucode for full details of the entries involved in this
|
||||||
|
process.
|
||||||
|
"""
|
||||||
|
def __init__(self, section, etype, node):
|
||||||
|
Entry_u_boot_with_ucode_ptr.__init__(self, section, etype, node)
|
||||||
|
self.elf_fname = 'tpl/u-boot-tpl'
|
||||||
|
|
||||||
|
def GetDefaultFilename(self):
|
||||||
|
return 'tpl/u-boot-tpl-nodtb.bin'
|
|
@ -62,19 +62,24 @@ class Entry_u_boot_ucode(Entry_blob):
|
||||||
|
|
||||||
def ObtainContents(self):
|
def ObtainContents(self):
|
||||||
# If the section does not need microcode, there is nothing to do
|
# If the section does not need microcode, there is nothing to do
|
||||||
ucode_dest_entry = self.section.FindEntryType('u-boot-with-ucode-ptr')
|
found = False
|
||||||
ucode_dest_entry_spl = self.section.FindEntryType(
|
for suffix in ['', '-spl', '-tpl']:
|
||||||
'u-boot-spl-with-ucode-ptr')
|
name = 'u-boot%s-with-ucode-ptr' % suffix
|
||||||
if ((not ucode_dest_entry or not ucode_dest_entry.target_offset) and
|
entry = self.section.FindEntryType(name)
|
||||||
(not ucode_dest_entry_spl or not ucode_dest_entry_spl.target_offset)):
|
if entry and entry.target_offset:
|
||||||
|
found = True
|
||||||
|
if not found:
|
||||||
self.data = ''
|
self.data = ''
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Get the microcode from the device tree entry. If it is not available
|
# Get the microcode from the device tree entry. If it is not available
|
||||||
# yet, return False so we will be called later. If the section simply
|
# yet, return False so we will be called later. If the section simply
|
||||||
# doesn't exist, then we may as well return True, since we are going to
|
# doesn't exist, then we may as well return True, since we are going to
|
||||||
# get an error anyway.
|
# get an error anyway.
|
||||||
fdt_entry = self.section.FindEntryType('u-boot-dtb-with-ucode')
|
for suffix in ['', '-spl', '-tpl']:
|
||||||
|
name = 'u-boot%s-dtb-with-ucode' % suffix
|
||||||
|
fdt_entry = self.section.FindEntryType(name)
|
||||||
|
if fdt_entry:
|
||||||
|
break
|
||||||
if not fdt_entry:
|
if not fdt_entry:
|
||||||
return True
|
return True
|
||||||
if not fdt_entry.ready:
|
if not fdt_entry.ready:
|
||||||
|
@ -86,12 +91,9 @@ class Entry_u_boot_ucode(Entry_blob):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Write it out to a file
|
# Write it out to a file
|
||||||
dtb_name = 'u-boot-ucode.bin'
|
self._pathname = tools.GetOutputFilename('u-boot-ucode.bin')
|
||||||
fname = tools.GetOutputFilename(dtb_name)
|
tools.WriteFile(self._pathname, fdt_entry.ucode_data)
|
||||||
with open(fname, 'wb') as fd:
|
|
||||||
fd.write(fdt_entry.ucode_data)
|
|
||||||
|
|
||||||
self._pathname = fname
|
|
||||||
self.ReadBlobContents()
|
self.ReadBlobContents()
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -19,6 +19,9 @@ class Entry_u_boot_with_ucode_ptr(Entry_blob):
|
||||||
|
|
||||||
Properties / Entry arguments:
|
Properties / Entry arguments:
|
||||||
- filename: Filename of u-boot-nodtb.dtb (default 'u-boot-nodtb.dtb')
|
- filename: Filename of u-boot-nodtb.dtb (default 'u-boot-nodtb.dtb')
|
||||||
|
- optional-ucode: boolean property to make microcode optional. If the
|
||||||
|
u-boot.bin image does not include microcode, no error will
|
||||||
|
be generated.
|
||||||
|
|
||||||
See Entry_u_boot_ucode for full details of the three entries involved in
|
See Entry_u_boot_ucode for full details of the three entries involved in
|
||||||
this process. This entry updates U-Boot with the offset and size of the
|
this process. This entry updates U-Boot with the offset and size of the
|
||||||
|
@ -63,28 +66,31 @@ class Entry_u_boot_with_ucode_ptr(Entry_blob):
|
||||||
# the U-Boot region must start at offset 7MB in the section. In this
|
# the U-Boot region must start at offset 7MB in the section. In this
|
||||||
# case the ROM starts at 0xff800000, so the offset of the first
|
# case the ROM starts at 0xff800000, so the offset of the first
|
||||||
# entry in the section corresponds to that.
|
# entry in the section corresponds to that.
|
||||||
if (self.target_offset < self.offset or
|
if (self.target_offset < self.image_pos or
|
||||||
self.target_offset >= self.offset + self.size):
|
self.target_offset >= self.image_pos + self.size):
|
||||||
self.Raise('Microcode pointer _dt_ucode_base_size at %08x is '
|
self.Raise('Microcode pointer _dt_ucode_base_size at %08x is outside the section ranging from %08x to %08x' %
|
||||||
'outside the section ranging from %08x to %08x' %
|
(self.target_offset, self.image_pos,
|
||||||
(self.target_offset, self.offset, self.offset + self.size))
|
self.image_pos + self.size))
|
||||||
|
|
||||||
# Get the microcode, either from u-boot-ucode or u-boot-dtb-with-ucode.
|
# Get the microcode, either from u-boot-ucode or u-boot-dtb-with-ucode.
|
||||||
# If we have left the microcode in the device tree, then it will be
|
# If we have left the microcode in the device tree, then it will be
|
||||||
# in the former. If we extracted the microcode from the device tree
|
# in the latter. If we extracted the microcode from the device tree
|
||||||
# and collated it in one place, it will be in the latter.
|
# and collated it in one place, it will be in the former.
|
||||||
if ucode_entry.size:
|
if ucode_entry.size:
|
||||||
offset, size = ucode_entry.offset, ucode_entry.size
|
offset, size = ucode_entry.offset, ucode_entry.size
|
||||||
else:
|
else:
|
||||||
dtb_entry = self.section.FindEntryType('u-boot-dtb-with-ucode')
|
dtb_entry = self.section.FindEntryType('u-boot-dtb-with-ucode')
|
||||||
if not dtb_entry or not dtb_entry.ready:
|
if not dtb_entry:
|
||||||
|
dtb_entry = self.section.FindEntryType(
|
||||||
|
'u-boot-tpl-dtb-with-ucode')
|
||||||
|
if not dtb_entry:
|
||||||
self.Raise('Cannot find microcode region u-boot-dtb-with-ucode')
|
self.Raise('Cannot find microcode region u-boot-dtb-with-ucode')
|
||||||
offset = dtb_entry.offset + dtb_entry.ucode_offset
|
offset = dtb_entry.offset + dtb_entry.ucode_offset
|
||||||
size = dtb_entry.ucode_size
|
size = dtb_entry.ucode_size
|
||||||
|
|
||||||
# Write the microcode offset and size into the entry
|
# Write the microcode offset and size into the entry
|
||||||
offset_and_size = struct.pack('<2L', offset, size)
|
offset_and_size = struct.pack('<2L', offset, size)
|
||||||
self.target_offset -= self.offset
|
self.target_offset -= self.image_pos
|
||||||
self.ProcessContentsUpdate(self.data[:self.target_offset] +
|
self.ProcessContentsUpdate(self.data[:self.target_offset] +
|
||||||
offset_and_size +
|
offset_and_size +
|
||||||
self.data[self.target_offset + 8:])
|
self.data[self.target_offset + 8:])
|
||||||
|
|
|
@ -25,6 +25,11 @@ class Entry_vblock(Entry):
|
||||||
- kernelkey: Name of the kernel key to use (inside keydir)
|
- kernelkey: Name of the kernel key to use (inside keydir)
|
||||||
- preamble-flags: Value of the vboot preamble flags (typically 0)
|
- preamble-flags: Value of the vboot preamble flags (typically 0)
|
||||||
|
|
||||||
|
Output files:
|
||||||
|
- input.<unique_name> - input file passed to futility
|
||||||
|
- vblock.<unique_name> - output file generated by futility (which is
|
||||||
|
used as the entry contents)
|
||||||
|
|
||||||
Chromium OS signs the read-write firmware and kernel, writing the signature
|
Chromium OS signs the read-write firmware and kernel, writing the signature
|
||||||
in this block. This allows U-Boot to verify that the next firmware stage
|
in this block. This allows U-Boot to verify that the next firmware stage
|
||||||
and kernel are genuine.
|
and kernel are genuine.
|
||||||
|
@ -53,8 +58,9 @@ class Entry_vblock(Entry):
|
||||||
return False
|
return False
|
||||||
input_data += data
|
input_data += data
|
||||||
|
|
||||||
output_fname = tools.GetOutputFilename('vblock.%s' % self.name)
|
uniq = self.GetUniqueName()
|
||||||
input_fname = tools.GetOutputFilename('input.%s' % self.name)
|
output_fname = tools.GetOutputFilename('vblock.%s' % uniq)
|
||||||
|
input_fname = tools.GetOutputFilename('input.%s' % uniq)
|
||||||
tools.WriteFile(input_fname, input_data)
|
tools.WriteFile(input_fname, input_data)
|
||||||
prefix = self.keydir + '/'
|
prefix = self.keydir + '/'
|
||||||
args = [
|
args = [
|
||||||
|
@ -69,6 +75,5 @@ class Entry_vblock(Entry):
|
||||||
]
|
]
|
||||||
#out.Notice("Sign '%s' into %s" % (', '.join(self.value), self.label))
|
#out.Notice("Sign '%s' into %s" % (', '.join(self.value), self.label))
|
||||||
stdout = tools.Run('futility', *args)
|
stdout = tools.Run('futility', *args)
|
||||||
#out.Debug(stdout)
|
|
||||||
self.SetContents(tools.ReadFile(output_fname))
|
self.SetContents(tools.ReadFile(output_fname))
|
||||||
return True
|
return True
|
||||||
|
|
30
tools/binman/etype/x86_start16_tpl.py
Normal file
30
tools/binman/etype/x86_start16_tpl.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
# Copyright (c) 2018 Google, Inc
|
||||||
|
# Written by Simon Glass <sjg@chromium.org>
|
||||||
|
#
|
||||||
|
# Entry-type module for the 16-bit x86 start-up code for U-Boot TPL
|
||||||
|
#
|
||||||
|
|
||||||
|
from entry import Entry
|
||||||
|
from blob import Entry_blob
|
||||||
|
|
||||||
|
class Entry_x86_start16_tpl(Entry_blob):
|
||||||
|
"""x86 16-bit start-up code for TPL
|
||||||
|
|
||||||
|
Properties / Entry arguments:
|
||||||
|
- filename: Filename of tpl/u-boot-x86-16bit-tpl.bin (default
|
||||||
|
'tpl/u-boot-x86-16bit-tpl.bin')
|
||||||
|
|
||||||
|
x86 CPUs start up in 16-bit mode, even if they are 64-bit CPUs. This code
|
||||||
|
must be placed at a particular address. This entry holds that code. It is
|
||||||
|
typically placed at offset CONFIG_SYS_X86_START16. The code is responsible
|
||||||
|
for changing to 32-bit mode and starting TPL, which in turn jumps to SPL.
|
||||||
|
|
||||||
|
If TPL is not being used, the 'x86_start16_spl or 'x86_start16' entry types
|
||||||
|
may be used instead.
|
||||||
|
"""
|
||||||
|
def __init__(self, section, etype, node):
|
||||||
|
Entry_blob.__init__(self, section, etype, node)
|
||||||
|
|
||||||
|
def GetDefaultFilename(self):
|
||||||
|
return 'tpl/u-boot-x86-16bit-tpl.bin'
|
|
@ -49,6 +49,9 @@ FmapHeader = collections.namedtuple('FmapHeader', FMAP_HEADER_NAMES)
|
||||||
FmapArea = collections.namedtuple('FmapArea', FMAP_AREA_NAMES)
|
FmapArea = collections.namedtuple('FmapArea', FMAP_AREA_NAMES)
|
||||||
|
|
||||||
|
|
||||||
|
def NameToFmap(name):
|
||||||
|
return name.replace('\0', '').replace('-', '_').upper()
|
||||||
|
|
||||||
def ConvertName(field_names, fields):
|
def ConvertName(field_names, fields):
|
||||||
"""Convert a name to something flashrom likes
|
"""Convert a name to something flashrom likes
|
||||||
|
|
||||||
|
@ -62,7 +65,7 @@ def ConvertName(field_names, fields):
|
||||||
value: value of that field (string for the ones we support)
|
value: value of that field (string for the ones we support)
|
||||||
"""
|
"""
|
||||||
name_index = field_names.index('name')
|
name_index = field_names.index('name')
|
||||||
fields[name_index] = fields[name_index].replace('\0', '').replace('-', '_').upper()
|
fields[name_index] = NameToFmap(fields[name_index])
|
||||||
|
|
||||||
def DecodeFmap(data):
|
def DecodeFmap(data):
|
||||||
"""Decode a flashmap into a header and list of areas
|
"""Decode a flashmap into a header and list of areas
|
||||||
|
@ -100,6 +103,7 @@ def EncodeFmap(image_size, name, areas):
|
||||||
"""
|
"""
|
||||||
def _FormatBlob(fmt, names, obj):
|
def _FormatBlob(fmt, names, obj):
|
||||||
params = [getattr(obj, name) for name in names]
|
params = [getattr(obj, name) for name in names]
|
||||||
|
ConvertName(names, params)
|
||||||
return struct.pack(fmt, *params)
|
return struct.pack(fmt, *params)
|
||||||
|
|
||||||
values = FmapHeader(FMAP_SIGNATURE, 1, 0, 0, image_size, name, len(areas))
|
values = FmapHeader(FMAP_SIGNATURE, 1, 0, 0, image_size, name, len(areas))
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#
|
#
|
||||||
# python -m unittest func_test.TestFunctional.testHelp
|
# python -m unittest func_test.TestFunctional.testHelp
|
||||||
|
|
||||||
|
import hashlib
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
@ -23,6 +24,7 @@ import fdt
|
||||||
import fdt_util
|
import fdt_util
|
||||||
import fmap_util
|
import fmap_util
|
||||||
import test_util
|
import test_util
|
||||||
|
import state
|
||||||
import tools
|
import tools
|
||||||
import tout
|
import tout
|
||||||
|
|
||||||
|
@ -39,9 +41,11 @@ U_BOOT_SPL_DTB_DATA = 'spldtb'
|
||||||
U_BOOT_TPL_DTB_DATA = 'tpldtb'
|
U_BOOT_TPL_DTB_DATA = 'tpldtb'
|
||||||
X86_START16_DATA = 'start16'
|
X86_START16_DATA = 'start16'
|
||||||
X86_START16_SPL_DATA = 'start16spl'
|
X86_START16_SPL_DATA = 'start16spl'
|
||||||
|
X86_START16_TPL_DATA = 'start16tpl'
|
||||||
PPC_MPC85XX_BR_DATA = 'ppcmpc85xxbr'
|
PPC_MPC85XX_BR_DATA = 'ppcmpc85xxbr'
|
||||||
U_BOOT_NODTB_DATA = 'nodtb with microcode pointer somewhere in here'
|
U_BOOT_NODTB_DATA = 'nodtb with microcode pointer somewhere in here'
|
||||||
U_BOOT_SPL_NODTB_DATA = 'splnodtb with microcode pointer somewhere in here'
|
U_BOOT_SPL_NODTB_DATA = 'splnodtb with microcode pointer somewhere in here'
|
||||||
|
U_BOOT_TPL_NODTB_DATA = 'tplnodtb with microcode pointer somewhere in here'
|
||||||
FSP_DATA = 'fsp'
|
FSP_DATA = 'fsp'
|
||||||
CMC_DATA = 'cmc'
|
CMC_DATA = 'cmc'
|
||||||
VBT_DATA = 'vbt'
|
VBT_DATA = 'vbt'
|
||||||
|
@ -53,6 +57,9 @@ CROS_EC_RW_DATA = 'ecrw'
|
||||||
GBB_DATA = 'gbbd'
|
GBB_DATA = 'gbbd'
|
||||||
BMPBLK_DATA = 'bmp'
|
BMPBLK_DATA = 'bmp'
|
||||||
VBLOCK_DATA = 'vblk'
|
VBLOCK_DATA = 'vblk'
|
||||||
|
FILES_DATA = ("sorry I'm late\nOh, don't bother apologising, I'm " +
|
||||||
|
"sorry you're alive\n")
|
||||||
|
COMPRESS_DATA = 'data to compress'
|
||||||
|
|
||||||
|
|
||||||
class TestFunctional(unittest.TestCase):
|
class TestFunctional(unittest.TestCase):
|
||||||
|
@ -94,9 +101,13 @@ class TestFunctional(unittest.TestCase):
|
||||||
TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
|
TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
|
||||||
TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
|
TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
|
||||||
X86_START16_SPL_DATA)
|
X86_START16_SPL_DATA)
|
||||||
|
TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
|
||||||
|
X86_START16_TPL_DATA)
|
||||||
TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
|
TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
|
||||||
TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
|
TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
|
||||||
U_BOOT_SPL_NODTB_DATA)
|
U_BOOT_SPL_NODTB_DATA)
|
||||||
|
TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
|
||||||
|
U_BOOT_TPL_NODTB_DATA)
|
||||||
TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
|
TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
|
||||||
TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
|
TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
|
||||||
TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
|
TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
|
||||||
|
@ -114,6 +125,11 @@ class TestFunctional(unittest.TestCase):
|
||||||
with open(self.TestFile('descriptor.bin')) as fd:
|
with open(self.TestFile('descriptor.bin')) as fd:
|
||||||
TestFunctional._MakeInputFile('descriptor.bin', fd.read())
|
TestFunctional._MakeInputFile('descriptor.bin', fd.read())
|
||||||
|
|
||||||
|
shutil.copytree(self.TestFile('files'),
|
||||||
|
os.path.join(self._indir, 'files'))
|
||||||
|
|
||||||
|
TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def tearDownClass(self):
|
def tearDownClass(self):
|
||||||
"""Remove the temporary input directory and its contents"""
|
"""Remove the temporary input directory and its contents"""
|
||||||
|
@ -170,7 +186,7 @@ class TestFunctional(unittest.TestCase):
|
||||||
return control.Binman(options, args)
|
return control.Binman(options, args)
|
||||||
|
|
||||||
def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
|
def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
|
||||||
entry_args=None):
|
entry_args=None, images=None, use_real_dtb=False):
|
||||||
"""Run binman with a given test file
|
"""Run binman with a given test file
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -179,6 +195,10 @@ class TestFunctional(unittest.TestCase):
|
||||||
map: True to output map files for the images
|
map: True to output map files for the images
|
||||||
update_dtb: Update the offset and size of each entry in the device
|
update_dtb: Update the offset and size of each entry in the device
|
||||||
tree before packing it into the image
|
tree before packing it into the image
|
||||||
|
entry_args: Dict of entry args to supply to binman
|
||||||
|
key: arg name
|
||||||
|
value: value of that arg
|
||||||
|
images: List of image names to build
|
||||||
"""
|
"""
|
||||||
args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
|
args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
|
||||||
if debug:
|
if debug:
|
||||||
|
@ -187,9 +207,14 @@ class TestFunctional(unittest.TestCase):
|
||||||
args.append('-m')
|
args.append('-m')
|
||||||
if update_dtb:
|
if update_dtb:
|
||||||
args.append('-up')
|
args.append('-up')
|
||||||
|
if not use_real_dtb:
|
||||||
|
args.append('--fake-dtb')
|
||||||
if entry_args:
|
if entry_args:
|
||||||
for arg, value in entry_args.iteritems():
|
for arg, value in entry_args.iteritems():
|
||||||
args.append('-a%s=%s' % (arg, value))
|
args.append('-a%s=%s' % (arg, value))
|
||||||
|
if images:
|
||||||
|
for image in images:
|
||||||
|
args += ['-i', image]
|
||||||
return self._DoBinman(*args)
|
return self._DoBinman(*args)
|
||||||
|
|
||||||
def _SetupDtb(self, fname, outfile='u-boot.dtb'):
|
def _SetupDtb(self, fname, outfile='u-boot.dtb'):
|
||||||
|
@ -214,8 +239,26 @@ class TestFunctional(unittest.TestCase):
|
||||||
TestFunctional._MakeInputFile(outfile, data)
|
TestFunctional._MakeInputFile(outfile, data)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
def _GetDtbContentsForSplTpl(self, dtb_data, name):
|
||||||
|
"""Create a version of the main DTB for SPL or SPL
|
||||||
|
|
||||||
|
For testing we don't actually have different versions of the DTB. With
|
||||||
|
U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
|
||||||
|
we don't normally have any unwanted nodes.
|
||||||
|
|
||||||
|
We still want the DTBs for SPL and TPL to be different though, since
|
||||||
|
otherwise it is confusing to know which one we are looking at. So add
|
||||||
|
an 'spl' or 'tpl' property to the top-level node.
|
||||||
|
"""
|
||||||
|
dtb = fdt.Fdt.FromData(dtb_data)
|
||||||
|
dtb.Scan()
|
||||||
|
dtb.GetNode('/binman').AddZeroProp(name)
|
||||||
|
dtb.Sync(auto_resize=True)
|
||||||
|
dtb.Pack()
|
||||||
|
return dtb.GetContents()
|
||||||
|
|
||||||
def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
|
def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
|
||||||
update_dtb=False, entry_args=None):
|
update_dtb=False, entry_args=None, reset_dtbs=True):
|
||||||
"""Run binman and return the resulting image
|
"""Run binman and return the resulting image
|
||||||
|
|
||||||
This runs binman with a given test file and then reads the resulting
|
This runs binman with a given test file and then reads the resulting
|
||||||
|
@ -245,12 +288,21 @@ class TestFunctional(unittest.TestCase):
|
||||||
# Use the compiled test file as the u-boot-dtb input
|
# Use the compiled test file as the u-boot-dtb input
|
||||||
if use_real_dtb:
|
if use_real_dtb:
|
||||||
dtb_data = self._SetupDtb(fname)
|
dtb_data = self._SetupDtb(fname)
|
||||||
|
infile = os.path.join(self._indir, 'u-boot.dtb')
|
||||||
|
|
||||||
|
# For testing purposes, make a copy of the DT for SPL and TPL. Add
|
||||||
|
# a node indicating which it is, so aid verification.
|
||||||
|
for name in ['spl', 'tpl']:
|
||||||
|
dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
|
||||||
|
outfile = os.path.join(self._indir, dtb_fname)
|
||||||
|
TestFunctional._MakeInputFile(dtb_fname,
|
||||||
|
self._GetDtbContentsForSplTpl(dtb_data, name))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
|
retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
|
||||||
entry_args=entry_args)
|
entry_args=entry_args, use_real_dtb=use_real_dtb)
|
||||||
self.assertEqual(0, retcode)
|
self.assertEqual(0, retcode)
|
||||||
out_dtb_fname = control.GetFdtPath('u-boot.dtb')
|
out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
|
||||||
|
|
||||||
# Find the (only) image, read it and return its contents
|
# Find the (only) image, read it and return its contents
|
||||||
image = control.images['image']
|
image = control.images['image']
|
||||||
|
@ -266,7 +318,7 @@ class TestFunctional(unittest.TestCase):
|
||||||
return fd.read(), dtb_data, map_data, out_dtb_fname
|
return fd.read(), dtb_data, map_data, out_dtb_fname
|
||||||
finally:
|
finally:
|
||||||
# Put the test file back
|
# Put the test file back
|
||||||
if use_real_dtb:
|
if reset_dtbs and use_real_dtb:
|
||||||
self._ResetDtbs()
|
self._ResetDtbs()
|
||||||
|
|
||||||
def _DoReadFile(self, fname, use_real_dtb=False):
|
def _DoReadFile(self, fname, use_real_dtb=False):
|
||||||
|
@ -980,7 +1032,7 @@ class TestFunctional(unittest.TestCase):
|
||||||
str(e.exception))
|
str(e.exception))
|
||||||
|
|
||||||
def testPackStart16Spl(self):
|
def testPackStart16Spl(self):
|
||||||
"""Test that an image with an x86 start16 region can be created"""
|
"""Test that an image with an x86 start16 SPL region can be created"""
|
||||||
data = self._DoReadFile('48_x86-start16-spl.dts')
|
data = self._DoReadFile('48_x86-start16-spl.dts')
|
||||||
self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
|
self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
|
||||||
|
|
||||||
|
@ -1329,7 +1381,7 @@ class TestFunctional(unittest.TestCase):
|
||||||
"""Fake calls to the futility utility"""
|
"""Fake calls to the futility utility"""
|
||||||
if pipe_list[0][0] == 'futility':
|
if pipe_list[0][0] == 'futility':
|
||||||
fname = pipe_list[0][3]
|
fname = pipe_list[0][3]
|
||||||
with open(fname, 'w') as fd:
|
with open(fname, 'wb') as fd:
|
||||||
fd.write(VBLOCK_DATA)
|
fd.write(VBLOCK_DATA)
|
||||||
return command.CommandResult()
|
return command.CommandResult()
|
||||||
|
|
||||||
|
@ -1380,6 +1432,334 @@ class TestFunctional(unittest.TestCase):
|
||||||
self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
|
self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
|
||||||
"'pos'", str(e.exception))
|
"'pos'", str(e.exception))
|
||||||
|
|
||||||
|
def testFillZero(self):
|
||||||
|
"""Test for an fill entry type with a size of 0"""
|
||||||
|
data = self._DoReadFile('80_fill_empty.dts')
|
||||||
|
self.assertEqual(chr(0) * 16, data)
|
||||||
|
|
||||||
|
def testTextMissing(self):
|
||||||
|
"""Test for a text entry type where there is no text"""
|
||||||
|
with self.assertRaises(ValueError) as e:
|
||||||
|
self._DoReadFileDtb('66_text.dts',)
|
||||||
|
self.assertIn("Node '/binman/text': No value provided for text label "
|
||||||
|
"'test-id'", str(e.exception))
|
||||||
|
|
||||||
|
def testPackStart16Tpl(self):
|
||||||
|
"""Test that an image with an x86 start16 TPL region can be created"""
|
||||||
|
data = self._DoReadFile('81_x86-start16-tpl.dts')
|
||||||
|
self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
|
||||||
|
|
||||||
|
def testSelectImage(self):
|
||||||
|
"""Test that we can select which images to build"""
|
||||||
|
with test_util.capture_sys_output() as (stdout, stderr):
|
||||||
|
retcode = self._DoTestFile('06_dual_image.dts', images=['image2'])
|
||||||
|
self.assertEqual(0, retcode)
|
||||||
|
self.assertIn('Skipping images: image1', stdout.getvalue())
|
||||||
|
|
||||||
|
self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
|
||||||
|
self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
|
||||||
|
|
||||||
|
def testUpdateFdtAll(self):
|
||||||
|
"""Test that all device trees are updated with offset/size info"""
|
||||||
|
data, _, _, _ = self._DoReadFileDtb('82_fdt_update_all.dts',
|
||||||
|
use_real_dtb=True, update_dtb=True)
|
||||||
|
|
||||||
|
base_expected = {
|
||||||
|
'section:image-pos': 0,
|
||||||
|
'u-boot-tpl-dtb:size': 513,
|
||||||
|
'u-boot-spl-dtb:size': 513,
|
||||||
|
'u-boot-spl-dtb:offset': 493,
|
||||||
|
'image-pos': 0,
|
||||||
|
'section/u-boot-dtb:image-pos': 0,
|
||||||
|
'u-boot-spl-dtb:image-pos': 493,
|
||||||
|
'section/u-boot-dtb:size': 493,
|
||||||
|
'u-boot-tpl-dtb:image-pos': 1006,
|
||||||
|
'section/u-boot-dtb:offset': 0,
|
||||||
|
'section:size': 493,
|
||||||
|
'offset': 0,
|
||||||
|
'section:offset': 0,
|
||||||
|
'u-boot-tpl-dtb:offset': 1006,
|
||||||
|
'size': 1519
|
||||||
|
}
|
||||||
|
|
||||||
|
# We expect three device-tree files in the output, one after the other.
|
||||||
|
# Read them in sequence. We look for an 'spl' property in the SPL tree,
|
||||||
|
# and 'tpl' in the TPL tree, to make sure they are distinct from the
|
||||||
|
# main U-Boot tree. All three should have the same postions and offset.
|
||||||
|
start = 0
|
||||||
|
for item in ['', 'spl', 'tpl']:
|
||||||
|
dtb = fdt.Fdt.FromData(data[start:])
|
||||||
|
dtb.Scan()
|
||||||
|
props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
|
||||||
|
'spl', 'tpl'])
|
||||||
|
expected = dict(base_expected)
|
||||||
|
if item:
|
||||||
|
expected[item] = 0
|
||||||
|
self.assertEqual(expected, props)
|
||||||
|
start += dtb._fdt_obj.totalsize()
|
||||||
|
|
||||||
|
def testUpdateFdtOutput(self):
|
||||||
|
"""Test that output DTB files are updated"""
|
||||||
|
try:
|
||||||
|
data, dtb_data, _, _ = self._DoReadFileDtb('82_fdt_update_all.dts',
|
||||||
|
use_real_dtb=True, update_dtb=True, reset_dtbs=False)
|
||||||
|
|
||||||
|
# Unfortunately, compiling a source file always results in a file
|
||||||
|
# called source.dtb (see fdt_util.EnsureCompiled()). The test
|
||||||
|
# source file (e.g. test/75_fdt_update_all.dts) thus does not enter
|
||||||
|
# binman as a file called u-boot.dtb. To fix this, copy the file
|
||||||
|
# over to the expected place.
|
||||||
|
#tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
|
||||||
|
#tools.ReadFile(tools.GetOutputFilename('source.dtb')))
|
||||||
|
start = 0
|
||||||
|
for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
|
||||||
|
'tpl/u-boot-tpl.dtb.out']:
|
||||||
|
dtb = fdt.Fdt.FromData(data[start:])
|
||||||
|
size = dtb._fdt_obj.totalsize()
|
||||||
|
pathname = tools.GetOutputFilename(os.path.split(fname)[1])
|
||||||
|
outdata = tools.ReadFile(pathname)
|
||||||
|
name = os.path.split(fname)[0]
|
||||||
|
|
||||||
|
if name:
|
||||||
|
orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
|
||||||
|
else:
|
||||||
|
orig_indata = dtb_data
|
||||||
|
self.assertNotEqual(outdata, orig_indata,
|
||||||
|
"Expected output file '%s' be updated" % pathname)
|
||||||
|
self.assertEqual(outdata, data[start:start + size],
|
||||||
|
"Expected output file '%s' to match output image" %
|
||||||
|
pathname)
|
||||||
|
start += size
|
||||||
|
finally:
|
||||||
|
self._ResetDtbs()
|
||||||
|
|
||||||
|
def _decompress(self, data):
|
||||||
|
out = os.path.join(self._indir, 'lz4.tmp')
|
||||||
|
with open(out, 'wb') as fd:
|
||||||
|
fd.write(data)
|
||||||
|
return tools.Run('lz4', '-dc', out)
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
orig = lz4.frame.decompress(data)
|
||||||
|
except AttributeError:
|
||||||
|
orig = lz4.decompress(data)
|
||||||
|
'''
|
||||||
|
|
||||||
|
def testCompress(self):
|
||||||
|
"""Test compression of blobs"""
|
||||||
|
data, _, _, out_dtb_fname = self._DoReadFileDtb('83_compress.dts',
|
||||||
|
use_real_dtb=True, update_dtb=True)
|
||||||
|
dtb = fdt.Fdt(out_dtb_fname)
|
||||||
|
dtb.Scan()
|
||||||
|
props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
|
||||||
|
orig = self._decompress(data)
|
||||||
|
self.assertEquals(COMPRESS_DATA, orig)
|
||||||
|
expected = {
|
||||||
|
'blob:uncomp-size': len(COMPRESS_DATA),
|
||||||
|
'blob:size': len(data),
|
||||||
|
'size': len(data),
|
||||||
|
}
|
||||||
|
self.assertEqual(expected, props)
|
||||||
|
|
||||||
|
def testFiles(self):
|
||||||
|
"""Test bringing in multiple files"""
|
||||||
|
data = self._DoReadFile('84_files.dts')
|
||||||
|
self.assertEqual(FILES_DATA, data)
|
||||||
|
|
||||||
|
def testFilesCompress(self):
|
||||||
|
"""Test bringing in multiple files and compressing them"""
|
||||||
|
data = self._DoReadFile('85_files_compress.dts')
|
||||||
|
|
||||||
|
image = control.images['image']
|
||||||
|
entries = image.GetEntries()
|
||||||
|
files = entries['files']
|
||||||
|
entries = files._section._entries
|
||||||
|
|
||||||
|
orig = ''
|
||||||
|
for i in range(1, 3):
|
||||||
|
key = '%d.dat' % i
|
||||||
|
start = entries[key].image_pos
|
||||||
|
len = entries[key].size
|
||||||
|
chunk = data[start:start + len]
|
||||||
|
orig += self._decompress(chunk)
|
||||||
|
|
||||||
|
self.assertEqual(FILES_DATA, orig)
|
||||||
|
|
||||||
|
def testFilesMissing(self):
|
||||||
|
"""Test missing files"""
|
||||||
|
with self.assertRaises(ValueError) as e:
|
||||||
|
data = self._DoReadFile('86_files_none.dts')
|
||||||
|
self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
|
||||||
|
'no files', str(e.exception))
|
||||||
|
|
||||||
|
def testFilesNoPattern(self):
|
||||||
|
"""Test missing files"""
|
||||||
|
with self.assertRaises(ValueError) as e:
|
||||||
|
data = self._DoReadFile('87_files_no_pattern.dts')
|
||||||
|
self.assertIn("Node '/binman/files': Missing 'pattern' property",
|
||||||
|
str(e.exception))
|
||||||
|
|
||||||
|
def testExpandSize(self):
|
||||||
|
"""Test an expanding entry"""
|
||||||
|
data, _, map_data, _ = self._DoReadFileDtb('88_expand_size.dts',
|
||||||
|
map=True)
|
||||||
|
expect = ('a' * 8 + U_BOOT_DATA +
|
||||||
|
MRC_DATA + 'b' * 1 + U_BOOT_DATA +
|
||||||
|
'c' * 8 + U_BOOT_DATA +
|
||||||
|
'd' * 8)
|
||||||
|
self.assertEqual(expect, data)
|
||||||
|
self.assertEqual('''ImagePos Offset Size Name
|
||||||
|
00000000 00000000 00000028 main-section
|
||||||
|
00000000 00000000 00000008 fill
|
||||||
|
00000008 00000008 00000004 u-boot
|
||||||
|
0000000c 0000000c 00000004 section
|
||||||
|
0000000c 00000000 00000003 intel-mrc
|
||||||
|
00000010 00000010 00000004 u-boot2
|
||||||
|
00000014 00000014 0000000c section2
|
||||||
|
00000014 00000000 00000008 fill
|
||||||
|
0000001c 00000008 00000004 u-boot
|
||||||
|
00000020 00000020 00000008 fill2
|
||||||
|
''', map_data)
|
||||||
|
|
||||||
|
def testExpandSizeBad(self):
|
||||||
|
"""Test an expanding entry which fails to provide contents"""
|
||||||
|
with test_util.capture_sys_output() as (stdout, stderr):
|
||||||
|
with self.assertRaises(ValueError) as e:
|
||||||
|
self._DoReadFileDtb('89_expand_size_bad.dts', map=True)
|
||||||
|
self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
|
||||||
|
'expanding entry', str(e.exception))
|
||||||
|
|
||||||
|
def testHash(self):
|
||||||
|
"""Test hashing of the contents of an entry"""
|
||||||
|
_, _, _, out_dtb_fname = self._DoReadFileDtb('90_hash.dts',
|
||||||
|
use_real_dtb=True, update_dtb=True)
|
||||||
|
dtb = fdt.Fdt(out_dtb_fname)
|
||||||
|
dtb.Scan()
|
||||||
|
hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
|
||||||
|
m = hashlib.sha256()
|
||||||
|
m.update(U_BOOT_DATA)
|
||||||
|
self.assertEqual(m.digest(), ''.join(hash_node.value))
|
||||||
|
|
||||||
|
def testHashNoAlgo(self):
|
||||||
|
with self.assertRaises(ValueError) as e:
|
||||||
|
self._DoReadFileDtb('91_hash_no_algo.dts', update_dtb=True)
|
||||||
|
self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
|
||||||
|
'hash node', str(e.exception))
|
||||||
|
|
||||||
|
def testHashBadAlgo(self):
|
||||||
|
with self.assertRaises(ValueError) as e:
|
||||||
|
self._DoReadFileDtb('92_hash_bad_algo.dts', update_dtb=True)
|
||||||
|
self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
|
||||||
|
str(e.exception))
|
||||||
|
|
||||||
|
def testHashSection(self):
|
||||||
|
"""Test hashing of the contents of an entry"""
|
||||||
|
_, _, _, out_dtb_fname = self._DoReadFileDtb('99_hash_section.dts',
|
||||||
|
use_real_dtb=True, update_dtb=True)
|
||||||
|
dtb = fdt.Fdt(out_dtb_fname)
|
||||||
|
dtb.Scan()
|
||||||
|
hash_node = dtb.GetNode('/binman/section/hash').props['value']
|
||||||
|
m = hashlib.sha256()
|
||||||
|
m.update(U_BOOT_DATA)
|
||||||
|
m.update(16 * 'a')
|
||||||
|
self.assertEqual(m.digest(), ''.join(hash_node.value))
|
||||||
|
|
||||||
|
def testPackUBootTplMicrocode(self):
|
||||||
|
"""Test that x86 microcode can be handled correctly in TPL
|
||||||
|
|
||||||
|
We expect to see the following in the image, in order:
|
||||||
|
u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
|
||||||
|
place
|
||||||
|
u-boot-tpl.dtb with the microcode removed
|
||||||
|
the microcode
|
||||||
|
"""
|
||||||
|
with open(self.TestFile('u_boot_ucode_ptr')) as fd:
|
||||||
|
TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
|
||||||
|
first, pos_and_size = self._RunMicrocodeTest('93_x86_tpl_ucode.dts',
|
||||||
|
U_BOOT_TPL_NODTB_DATA)
|
||||||
|
self.assertEqual('tplnodtb with microc' + pos_and_size +
|
||||||
|
'ter somewhere in here', first)
|
||||||
|
|
||||||
|
def testFmapX86(self):
|
||||||
|
"""Basic test of generation of a flashrom fmap"""
|
||||||
|
data = self._DoReadFile('94_fmap_x86.dts')
|
||||||
|
fhdr, fentries = fmap_util.DecodeFmap(data[32:])
|
||||||
|
expected = U_BOOT_DATA + MRC_DATA + 'a' * (32 - 7)
|
||||||
|
self.assertEqual(expected, data[:32])
|
||||||
|
fhdr, fentries = fmap_util.DecodeFmap(data[32:])
|
||||||
|
|
||||||
|
self.assertEqual(0x100, fhdr.image_size)
|
||||||
|
|
||||||
|
self.assertEqual(0, fentries[0].offset)
|
||||||
|
self.assertEqual(4, fentries[0].size)
|
||||||
|
self.assertEqual('U_BOOT', fentries[0].name)
|
||||||
|
|
||||||
|
self.assertEqual(4, fentries[1].offset)
|
||||||
|
self.assertEqual(3, fentries[1].size)
|
||||||
|
self.assertEqual('INTEL_MRC', fentries[1].name)
|
||||||
|
|
||||||
|
self.assertEqual(32, fentries[2].offset)
|
||||||
|
self.assertEqual(fmap_util.FMAP_HEADER_LEN +
|
||||||
|
fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
|
||||||
|
self.assertEqual('FMAP', fentries[2].name)
|
||||||
|
|
||||||
|
def testFmapX86Section(self):
|
||||||
|
"""Basic test of generation of a flashrom fmap"""
|
||||||
|
data = self._DoReadFile('95_fmap_x86_section.dts')
|
||||||
|
expected = U_BOOT_DATA + MRC_DATA + 'b' * (32 - 7)
|
||||||
|
self.assertEqual(expected, data[:32])
|
||||||
|
fhdr, fentries = fmap_util.DecodeFmap(data[36:])
|
||||||
|
|
||||||
|
self.assertEqual(0x100, fhdr.image_size)
|
||||||
|
|
||||||
|
self.assertEqual(0, fentries[0].offset)
|
||||||
|
self.assertEqual(4, fentries[0].size)
|
||||||
|
self.assertEqual('U_BOOT', fentries[0].name)
|
||||||
|
|
||||||
|
self.assertEqual(4, fentries[1].offset)
|
||||||
|
self.assertEqual(3, fentries[1].size)
|
||||||
|
self.assertEqual('INTEL_MRC', fentries[1].name)
|
||||||
|
|
||||||
|
self.assertEqual(36, fentries[2].offset)
|
||||||
|
self.assertEqual(fmap_util.FMAP_HEADER_LEN +
|
||||||
|
fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
|
||||||
|
self.assertEqual('FMAP', fentries[2].name)
|
||||||
|
|
||||||
|
def testElf(self):
|
||||||
|
"""Basic test of ELF entries"""
|
||||||
|
with open(self.TestFile('bss_data')) as fd:
|
||||||
|
TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
|
||||||
|
with open(self.TestFile('bss_data')) as fd:
|
||||||
|
TestFunctional._MakeInputFile('-boot', fd.read())
|
||||||
|
data = self._DoReadFile('96_elf.dts')
|
||||||
|
|
||||||
|
def testElfStripg(self):
|
||||||
|
"""Basic test of ELF entries"""
|
||||||
|
with open(self.TestFile('bss_data')) as fd:
|
||||||
|
TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
|
||||||
|
with open(self.TestFile('bss_data')) as fd:
|
||||||
|
TestFunctional._MakeInputFile('-boot', fd.read())
|
||||||
|
data = self._DoReadFile('97_elf_strip.dts')
|
||||||
|
|
||||||
|
def testPackOverlapMap(self):
|
||||||
|
"""Test that overlapping regions are detected"""
|
||||||
|
with test_util.capture_sys_output() as (stdout, stderr):
|
||||||
|
with self.assertRaises(ValueError) as e:
|
||||||
|
self._DoTestFile('14_pack_overlap.dts', map=True)
|
||||||
|
map_fname = tools.GetOutputFilename('image.map')
|
||||||
|
self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
|
||||||
|
stdout.getvalue())
|
||||||
|
|
||||||
|
# We should not get an inmage, but there should be a map file
|
||||||
|
self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
|
||||||
|
self.assertTrue(os.path.exists(map_fname))
|
||||||
|
map_data = tools.ReadFile(map_fname)
|
||||||
|
self.assertEqual('''ImagePos Offset Size Name
|
||||||
|
<none> 00000000 00000007 main-section
|
||||||
|
<none> 00000000 00000004 u-boot
|
||||||
|
<none> 00000003 00000004 u-boot-align
|
||||||
|
''', map_data)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -42,7 +42,8 @@ class Image:
|
||||||
self._size = None
|
self._size = None
|
||||||
self._filename = '%s.bin' % self._name
|
self._filename = '%s.bin' % self._name
|
||||||
if test:
|
if test:
|
||||||
self._section = bsection.Section('main-section', self._node, True)
|
self._section = bsection.Section('main-section', None, self._node,
|
||||||
|
self, True)
|
||||||
else:
|
else:
|
||||||
self._ReadNode()
|
self._ReadNode()
|
||||||
|
|
||||||
|
@ -52,7 +53,20 @@ class Image:
|
||||||
filename = fdt_util.GetString(self._node, 'filename')
|
filename = fdt_util.GetString(self._node, 'filename')
|
||||||
if filename:
|
if filename:
|
||||||
self._filename = filename
|
self._filename = filename
|
||||||
self._section = bsection.Section('main-section', self._node)
|
self._section = bsection.Section('main-section', None, self._node, self)
|
||||||
|
|
||||||
|
def GetFdtSet(self):
|
||||||
|
"""Get the set of device tree files used by this image"""
|
||||||
|
return self._section.GetFdtSet()
|
||||||
|
|
||||||
|
def ExpandEntries(self):
|
||||||
|
"""Expand out any entries which have calculated sub-entries
|
||||||
|
|
||||||
|
Some entries are expanded out at runtime, e.g. 'files', which produces
|
||||||
|
a section containing a list of files. Process these entries so that
|
||||||
|
this information is added to the device tree.
|
||||||
|
"""
|
||||||
|
self._section.ExpandEntries()
|
||||||
|
|
||||||
def AddMissingProperties(self):
|
def AddMissingProperties(self):
|
||||||
"""Add properties that are not present in the device tree
|
"""Add properties that are not present in the device tree
|
||||||
|
@ -66,6 +80,11 @@ class Image:
|
||||||
self._section.AddMissingProperties()
|
self._section.AddMissingProperties()
|
||||||
|
|
||||||
def ProcessFdt(self, fdt):
|
def ProcessFdt(self, fdt):
|
||||||
|
"""Allow entries to adjust the device tree
|
||||||
|
|
||||||
|
Some entries need to adjust the device tree for their purposes. This
|
||||||
|
may involve adding or deleting properties.
|
||||||
|
"""
|
||||||
return self._section.ProcessFdt(fdt)
|
return self._section.ProcessFdt(fdt)
|
||||||
|
|
||||||
def GetEntryContents(self):
|
def GetEntryContents(self):
|
||||||
|
@ -120,10 +139,15 @@ class Image:
|
||||||
return self._section.GetEntries()
|
return self._section.GetEntries()
|
||||||
|
|
||||||
def WriteMap(self):
|
def WriteMap(self):
|
||||||
"""Write a map of the image to a .map file"""
|
"""Write a map of the image to a .map file
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Filename of map file written
|
||||||
|
"""
|
||||||
filename = '%s.map' % self._name
|
filename = '%s.map' % self._name
|
||||||
fname = tools.GetOutputFilename(filename)
|
fname = tools.GetOutputFilename(filename)
|
||||||
with open(fname, 'w') as fd:
|
with open(fname, 'w') as fd:
|
||||||
print('%8s %8s %8s %s' % ('ImagePos', 'Offset', 'Size', 'Name'),
|
print('%8s %8s %8s %s' % ('ImagePos', 'Offset', 'Size', 'Name'),
|
||||||
file=fd)
|
file=fd)
|
||||||
self._section.WriteMap(fd, 0)
|
self._section.WriteMap(fd, 0)
|
||||||
|
return fname
|
||||||
|
|
253
tools/binman/state.py
Normal file
253
tools/binman/state.py
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
# Copyright 2018 Google, Inc
|
||||||
|
# Written by Simon Glass <sjg@chromium.org>
|
||||||
|
#
|
||||||
|
# Holds and modifies the state information held by binman
|
||||||
|
#
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
import re
|
||||||
|
from sets import Set
|
||||||
|
|
||||||
|
import os
|
||||||
|
import tools
|
||||||
|
|
||||||
|
# Records the device-tree files known to binman, keyed by filename (e.g.
|
||||||
|
# 'u-boot-spl.dtb')
|
||||||
|
fdt_files = {}
|
||||||
|
|
||||||
|
# Arguments passed to binman to provide arguments to entries
|
||||||
|
entry_args = {}
|
||||||
|
|
||||||
|
# True to use fake device-tree files for testing (see U_BOOT_DTB_DATA in
|
||||||
|
# ftest.py)
|
||||||
|
use_fake_dtb = False
|
||||||
|
|
||||||
|
# Set of all device tree files references by images
|
||||||
|
fdt_set = Set()
|
||||||
|
|
||||||
|
# Same as above, but excluding the main one
|
||||||
|
fdt_subset = Set()
|
||||||
|
|
||||||
|
# The DTB which contains the full image information
|
||||||
|
main_dtb = None
|
||||||
|
|
||||||
|
def GetFdt(fname):
|
||||||
|
"""Get the Fdt object for a particular device-tree filename
|
||||||
|
|
||||||
|
Binman keeps track of at least one device-tree file called u-boot.dtb but
|
||||||
|
can also have others (e.g. for SPL). This function looks up the given
|
||||||
|
filename and returns the associated Fdt object.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fname: Filename to look up (e.g. 'u-boot.dtb').
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Fdt object associated with the filename
|
||||||
|
"""
|
||||||
|
return fdt_files[fname]
|
||||||
|
|
||||||
|
def GetFdtPath(fname):
|
||||||
|
"""Get the full pathname of a particular Fdt object
|
||||||
|
|
||||||
|
Similar to GetFdt() but returns the pathname associated with the Fdt.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fname: Filename to look up (e.g. 'u-boot.dtb').
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Full path name to the associated Fdt
|
||||||
|
"""
|
||||||
|
return fdt_files[fname]._fname
|
||||||
|
|
||||||
|
def GetFdtContents(fname):
|
||||||
|
"""Looks up the FDT pathname and contents
|
||||||
|
|
||||||
|
This is used to obtain the Fdt pathname and contents when needed by an
|
||||||
|
entry. It supports a 'fake' dtb, allowing tests to substitute test data for
|
||||||
|
the real dtb.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fname: Filename to look up (e.g. 'u-boot.dtb').
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple:
|
||||||
|
pathname to Fdt
|
||||||
|
Fdt data (as bytes)
|
||||||
|
"""
|
||||||
|
if fname in fdt_files and not use_fake_dtb:
|
||||||
|
pathname = GetFdtPath(fname)
|
||||||
|
data = GetFdt(fname).GetContents()
|
||||||
|
else:
|
||||||
|
pathname = tools.GetInputFilename(fname)
|
||||||
|
data = tools.ReadFile(pathname)
|
||||||
|
return pathname, data
|
||||||
|
|
||||||
|
def SetEntryArgs(args):
|
||||||
|
"""Set the value of the entry args
|
||||||
|
|
||||||
|
This sets up the entry_args dict which is used to supply entry arguments to
|
||||||
|
entries.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
args: List of entry arguments, each in the format "name=value"
|
||||||
|
"""
|
||||||
|
global entry_args
|
||||||
|
|
||||||
|
entry_args = {}
|
||||||
|
if args:
|
||||||
|
for arg in args:
|
||||||
|
m = re.match('([^=]*)=(.*)', arg)
|
||||||
|
if not m:
|
||||||
|
raise ValueError("Invalid entry arguemnt '%s'" % arg)
|
||||||
|
entry_args[m.group(1)] = m.group(2)
|
||||||
|
|
||||||
|
def GetEntryArg(name):
|
||||||
|
"""Get the value of an entry argument
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: Name of argument to retrieve
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
String value of argument
|
||||||
|
"""
|
||||||
|
return entry_args.get(name)
|
||||||
|
|
||||||
|
def Prepare(images, dtb):
|
||||||
|
"""Get device tree files ready for use
|
||||||
|
|
||||||
|
This sets up a set of device tree files that can be retrieved by GetFdts().
|
||||||
|
At present there is only one, that for U-Boot proper.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
images: List of images being used
|
||||||
|
dtb: Main dtb
|
||||||
|
"""
|
||||||
|
global fdt_set, fdt_subset, fdt_files, main_dtb
|
||||||
|
# Import these here in case libfdt.py is not available, in which case
|
||||||
|
# the above help option still works.
|
||||||
|
import fdt
|
||||||
|
import fdt_util
|
||||||
|
|
||||||
|
# If we are updating the DTBs we need to put these updated versions
|
||||||
|
# where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb'
|
||||||
|
# since it is assumed to be the one passed in with options.dt, and
|
||||||
|
# was handled just above.
|
||||||
|
main_dtb = dtb
|
||||||
|
fdt_files.clear()
|
||||||
|
fdt_files['u-boot.dtb'] = dtb
|
||||||
|
fdt_subset = Set()
|
||||||
|
if not use_fake_dtb:
|
||||||
|
for image in images.values():
|
||||||
|
fdt_subset.update(image.GetFdtSet())
|
||||||
|
fdt_subset.discard('u-boot.dtb')
|
||||||
|
for other_fname in fdt_subset:
|
||||||
|
infile = tools.GetInputFilename(other_fname)
|
||||||
|
other_fname_dtb = fdt_util.EnsureCompiled(infile)
|
||||||
|
out_fname = tools.GetOutputFilename('%s.out' %
|
||||||
|
os.path.split(other_fname)[1])
|
||||||
|
tools.WriteFile(out_fname, tools.ReadFile(other_fname_dtb))
|
||||||
|
other_dtb = fdt.FdtScan(out_fname)
|
||||||
|
fdt_files[other_fname] = other_dtb
|
||||||
|
|
||||||
|
def GetFdts():
|
||||||
|
"""Yield all device tree files being used by binman
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
Device trees being used (U-Boot proper, SPL, TPL)
|
||||||
|
"""
|
||||||
|
yield main_dtb
|
||||||
|
for other_fname in fdt_subset:
|
||||||
|
yield fdt_files[other_fname]
|
||||||
|
|
||||||
|
def GetUpdateNodes(node):
|
||||||
|
"""Yield all the nodes that need to be updated in all device trees
|
||||||
|
|
||||||
|
The property referenced by this node is added to any device trees which
|
||||||
|
have the given node. Due to removable of unwanted notes, SPL and TPL may
|
||||||
|
not have this node.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
node: Node object in the main device tree to look up
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
Node objects in each device tree that is in use (U-Boot proper, which
|
||||||
|
is node, SPL and TPL)
|
||||||
|
"""
|
||||||
|
yield node
|
||||||
|
for dtb in fdt_files.values():
|
||||||
|
if dtb != node.GetFdt():
|
||||||
|
other_node = dtb.GetNode(node.path)
|
||||||
|
if other_node:
|
||||||
|
yield other_node
|
||||||
|
|
||||||
|
def AddZeroProp(node, prop):
|
||||||
|
"""Add a new property to affected device trees with an integer value of 0.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prop_name: Name of property
|
||||||
|
"""
|
||||||
|
for n in GetUpdateNodes(node):
|
||||||
|
n.AddZeroProp(prop)
|
||||||
|
|
||||||
|
def AddSubnode(node, name):
|
||||||
|
"""Add a new subnode to a node in affected device trees
|
||||||
|
|
||||||
|
Args:
|
||||||
|
node: Node to add to
|
||||||
|
name: name of node to add
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
New subnode that was created in main tree
|
||||||
|
"""
|
||||||
|
first = None
|
||||||
|
for n in GetUpdateNodes(node):
|
||||||
|
subnode = n.AddSubnode(name)
|
||||||
|
if not first:
|
||||||
|
first = subnode
|
||||||
|
return first
|
||||||
|
|
||||||
|
def AddString(node, prop, value):
|
||||||
|
"""Add a new string property to affected device trees
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prop_name: Name of property
|
||||||
|
value: String value (which will be \0-terminated in the DT)
|
||||||
|
"""
|
||||||
|
for n in GetUpdateNodes(node):
|
||||||
|
n.AddString(prop, value)
|
||||||
|
|
||||||
|
def SetInt(node, prop, value):
|
||||||
|
"""Update an integer property in affected device trees with an integer value
|
||||||
|
|
||||||
|
This is not allowed to change the size of the FDT.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prop_name: Name of property
|
||||||
|
"""
|
||||||
|
for n in GetUpdateNodes(node):
|
||||||
|
n.SetInt(prop, value)
|
||||||
|
|
||||||
|
def CheckAddHashProp(node):
|
||||||
|
hash_node = node.FindNode('hash')
|
||||||
|
if hash_node:
|
||||||
|
algo = hash_node.props.get('algo')
|
||||||
|
if not algo:
|
||||||
|
return "Missing 'algo' property for hash node"
|
||||||
|
if algo.value == 'sha256':
|
||||||
|
size = 32
|
||||||
|
else:
|
||||||
|
return "Unknown hash algorithm '%s'" % algo
|
||||||
|
for n in GetUpdateNodes(hash_node):
|
||||||
|
n.AddEmptyProp('value', size)
|
||||||
|
|
||||||
|
def CheckSetHashValue(node, get_data_func):
|
||||||
|
hash_node = node.FindNode('hash')
|
||||||
|
if hash_node:
|
||||||
|
algo = hash_node.props.get('algo').value
|
||||||
|
if algo == 'sha256':
|
||||||
|
m = hashlib.sha256()
|
||||||
|
m.update(get_data_func())
|
||||||
|
data = m.digest()
|
||||||
|
for n in GetUpdateNodes(hash_node):
|
||||||
|
n.SetData('value', data)
|
15
tools/binman/test/80_fill_empty.dts
Normal file
15
tools/binman/test/80_fill_empty.dts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
size = <16>;
|
||||||
|
fill {
|
||||||
|
size = <0>;
|
||||||
|
fill-byte = [ff];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
14
tools/binman/test/81_x86-start16-tpl.dts
Normal file
14
tools/binman/test/81_x86-start16-tpl.dts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
size = <16>;
|
||||||
|
|
||||||
|
x86-start16-tpl {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
18
tools/binman/test/82_fdt_update_all.dts
Normal file
18
tools/binman/test/82_fdt_update_all.dts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
section {
|
||||||
|
u-boot-dtb {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
u-boot-spl-dtb {
|
||||||
|
};
|
||||||
|
u-boot-tpl-dtb {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
11
tools/binman/test/83_compress.dts
Normal file
11
tools/binman/test/83_compress.dts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
binman {
|
||||||
|
blob {
|
||||||
|
filename = "compress";
|
||||||
|
compress = "lz4";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
11
tools/binman/test/84_files.dts
Normal file
11
tools/binman/test/84_files.dts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
binman {
|
||||||
|
files {
|
||||||
|
pattern = "files/*.dat";
|
||||||
|
compress = "none";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
11
tools/binman/test/85_files_compress.dts
Normal file
11
tools/binman/test/85_files_compress.dts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
binman {
|
||||||
|
files {
|
||||||
|
pattern = "files/*.dat";
|
||||||
|
compress = "lz4";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
12
tools/binman/test/86_files_none.dts
Normal file
12
tools/binman/test/86_files_none.dts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
binman {
|
||||||
|
files {
|
||||||
|
pattern = "files/*.none";
|
||||||
|
compress = "none";
|
||||||
|
require-matches;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
11
tools/binman/test/87_files_no_pattern.dts
Normal file
11
tools/binman/test/87_files_no_pattern.dts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
binman {
|
||||||
|
files {
|
||||||
|
compress = "none";
|
||||||
|
require-matches;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
43
tools/binman/test/88_expand_size.dts
Normal file
43
tools/binman/test/88_expand_size.dts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
binman {
|
||||||
|
size = <40>;
|
||||||
|
fill {
|
||||||
|
expand-size;
|
||||||
|
fill-byte = [61];
|
||||||
|
size = <0>;
|
||||||
|
};
|
||||||
|
u-boot {
|
||||||
|
offset = <8>;
|
||||||
|
};
|
||||||
|
section {
|
||||||
|
expand-size;
|
||||||
|
pad-byte = <0x62>;
|
||||||
|
intel-mrc {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
u-boot2 {
|
||||||
|
type = "u-boot";
|
||||||
|
offset = <16>;
|
||||||
|
};
|
||||||
|
section2 {
|
||||||
|
type = "section";
|
||||||
|
fill {
|
||||||
|
expand-size;
|
||||||
|
fill-byte = [63];
|
||||||
|
size = <0>;
|
||||||
|
};
|
||||||
|
u-boot {
|
||||||
|
offset = <8>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
fill2 {
|
||||||
|
type = "fill";
|
||||||
|
expand-size;
|
||||||
|
fill-byte = [64];
|
||||||
|
size = <0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
14
tools/binman/test/89_expand_size_bad.dts
Normal file
14
tools/binman/test/89_expand_size_bad.dts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
binman {
|
||||||
|
_testing {
|
||||||
|
expand-size;
|
||||||
|
return-contents-once;
|
||||||
|
};
|
||||||
|
u-boot {
|
||||||
|
offset = <8>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
12
tools/binman/test/90_hash.dts
Normal file
12
tools/binman/test/90_hash.dts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
binman {
|
||||||
|
u-boot {
|
||||||
|
hash {
|
||||||
|
algo = "sha256";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
11
tools/binman/test/91_hash_no_algo.dts
Normal file
11
tools/binman/test/91_hash_no_algo.dts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
binman {
|
||||||
|
u-boot {
|
||||||
|
hash {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
12
tools/binman/test/92_hash_bad_algo.dts
Normal file
12
tools/binman/test/92_hash_bad_algo.dts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
binman {
|
||||||
|
u-boot {
|
||||||
|
hash {
|
||||||
|
algo = "invalid";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
29
tools/binman/test/93_x86_tpl_ucode.dts
Normal file
29
tools/binman/test/93_x86_tpl_ucode.dts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
sort-by-offset;
|
||||||
|
end-at-4gb;
|
||||||
|
size = <0x200>;
|
||||||
|
u-boot-tpl-with-ucode-ptr {
|
||||||
|
};
|
||||||
|
|
||||||
|
u-boot-tpl-dtb-with-ucode {
|
||||||
|
};
|
||||||
|
|
||||||
|
u-boot-ucode {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
microcode {
|
||||||
|
update@0 {
|
||||||
|
data = <0x12345678 0x12345679>;
|
||||||
|
};
|
||||||
|
update@1 {
|
||||||
|
data = <0xabcd0000 0x78235609>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
20
tools/binman/test/94_fmap_x86.dts
Normal file
20
tools/binman/test/94_fmap_x86.dts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
end-at-4gb;
|
||||||
|
size = <0x100>;
|
||||||
|
pad-byte = <0x61>;
|
||||||
|
u-boot {
|
||||||
|
};
|
||||||
|
intel-mrc {
|
||||||
|
};
|
||||||
|
fmap {
|
||||||
|
offset = <0xffffff20>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
22
tools/binman/test/95_fmap_x86_section.dts
Normal file
22
tools/binman/test/95_fmap_x86_section.dts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
end-at-4gb;
|
||||||
|
size = <0x100>;
|
||||||
|
u-boot {
|
||||||
|
};
|
||||||
|
section {
|
||||||
|
pad-byte = <0x62>;
|
||||||
|
intel-mrc {
|
||||||
|
};
|
||||||
|
fmap {
|
||||||
|
offset = <0x20>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
14
tools/binman/test/96_elf.dts
Normal file
14
tools/binman/test/96_elf.dts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
u-boot-elf {
|
||||||
|
};
|
||||||
|
u-boot-spl-elf {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
15
tools/binman/test/97_elf_strip.dts
Normal file
15
tools/binman/test/97_elf_strip.dts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
u-boot-elf {
|
||||||
|
strip;
|
||||||
|
};
|
||||||
|
u-boot-spl-elf {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
18
tools/binman/test/99_hash_section.dts
Normal file
18
tools/binman/test/99_hash_section.dts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
binman {
|
||||||
|
section {
|
||||||
|
u-boot {
|
||||||
|
};
|
||||||
|
fill {
|
||||||
|
size = <0x10>;
|
||||||
|
fill-byte = [61];
|
||||||
|
};
|
||||||
|
hash {
|
||||||
|
algo = "sha256";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
1
tools/binman/test/files/1.dat
Normal file
1
tools/binman/test/files/1.dat
Normal file
|
@ -0,0 +1 @@
|
||||||
|
sorry I'm late
|
1
tools/binman/test/files/2.dat
Normal file
1
tools/binman/test/files/2.dat
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Oh, don't bother apologising, I'm sorry you're alive
|
0
tools/binman/test/files/ignored_dir.dat/ignore
Normal file
0
tools/binman/test/files/ignored_dir.dat/ignore
Normal file
1
tools/binman/test/files/not-this-one
Normal file
1
tools/binman/test/files/not-this-one
Normal file
|
@ -0,0 +1 @@
|
||||||
|
this does not have a .dat extenion
|
|
@ -408,7 +408,7 @@ class Builder:
|
||||||
"""
|
"""
|
||||||
cmd = [self.gnu_make] + list(args)
|
cmd = [self.gnu_make] + list(args)
|
||||||
result = command.RunPipe([cmd], capture=True, capture_stderr=True,
|
result = command.RunPipe([cmd], capture=True, capture_stderr=True,
|
||||||
cwd=cwd, raise_on_error=False, **kwargs)
|
cwd=cwd, raise_on_error=False, infile='/dev/null', **kwargs)
|
||||||
if self.verbose_build:
|
if self.verbose_build:
|
||||||
result.stdout = '%s\n' % (' '.join(cmd)) + result.stdout
|
result.stdout = '%s\n' % (' '.join(cmd)) + result.stdout
|
||||||
result.combined = '%s\n' % (' '.join(cmd)) + result.combined
|
result.combined = '%s\n' % (' '.join(cmd)) + result.combined
|
||||||
|
|
|
@ -43,6 +43,7 @@ class Prop:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.value = None
|
self.value = None
|
||||||
self.bytes = str(bytes)
|
self.bytes = str(bytes)
|
||||||
|
self.dirty = False
|
||||||
if not bytes:
|
if not bytes:
|
||||||
self.type = TYPE_BOOL
|
self.type = TYPE_BOOL
|
||||||
self.value = True
|
self.value = True
|
||||||
|
@ -145,7 +146,7 @@ class Prop:
|
||||||
if type == TYPE_BYTE:
|
if type == TYPE_BYTE:
|
||||||
return chr(0)
|
return chr(0)
|
||||||
elif type == TYPE_INT:
|
elif type == TYPE_INT:
|
||||||
return struct.pack('<I', 0);
|
return struct.pack('>I', 0);
|
||||||
elif type == TYPE_STRING:
|
elif type == TYPE_STRING:
|
||||||
return ''
|
return ''
|
||||||
else:
|
else:
|
||||||
|
@ -160,6 +161,55 @@ class Prop:
|
||||||
self._node._fdt.CheckCache()
|
self._node._fdt.CheckCache()
|
||||||
return self._node._fdt.GetStructOffset(self._offset)
|
return self._node._fdt.GetStructOffset(self._offset)
|
||||||
|
|
||||||
|
def SetInt(self, val):
|
||||||
|
"""Set the integer value of the property
|
||||||
|
|
||||||
|
The device tree is marked dirty so that the value will be written to
|
||||||
|
the block on the next sync.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
val: Integer value (32-bit, single cell)
|
||||||
|
"""
|
||||||
|
self.bytes = struct.pack('>I', val);
|
||||||
|
self.value = val
|
||||||
|
self.type = TYPE_INT
|
||||||
|
self.dirty = True
|
||||||
|
|
||||||
|
def SetData(self, bytes):
|
||||||
|
"""Set the value of a property as bytes
|
||||||
|
|
||||||
|
Args:
|
||||||
|
bytes: New property value to set
|
||||||
|
"""
|
||||||
|
self.bytes = str(bytes)
|
||||||
|
self.type, self.value = self.BytesToValue(bytes)
|
||||||
|
self.dirty = True
|
||||||
|
|
||||||
|
def Sync(self, auto_resize=False):
|
||||||
|
"""Sync property changes back to the device tree
|
||||||
|
|
||||||
|
This updates the device tree blob with any changes to this property
|
||||||
|
since the last sync.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
auto_resize: Resize the device tree automatically if it does not
|
||||||
|
have enough space for the update
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FdtException if auto_resize is False and there is not enough space
|
||||||
|
"""
|
||||||
|
if self._offset is None or self.dirty:
|
||||||
|
node = self._node
|
||||||
|
fdt_obj = node._fdt._fdt_obj
|
||||||
|
if auto_resize:
|
||||||
|
while fdt_obj.setprop(node.Offset(), self.name, self.bytes,
|
||||||
|
(libfdt.NOSPACE,)) == -libfdt.NOSPACE:
|
||||||
|
fdt_obj.resize(fdt_obj.totalsize() + 1024)
|
||||||
|
fdt_obj.setprop(node.Offset(), self.name, self.bytes)
|
||||||
|
else:
|
||||||
|
fdt_obj.setprop(node.Offset(), self.name, self.bytes)
|
||||||
|
|
||||||
|
|
||||||
class Node:
|
class Node:
|
||||||
"""A device tree node
|
"""A device tree node
|
||||||
|
|
||||||
|
@ -284,25 +334,125 @@ class Node:
|
||||||
Args:
|
Args:
|
||||||
prop_name: Name of property
|
prop_name: Name of property
|
||||||
"""
|
"""
|
||||||
fdt_obj = self._fdt._fdt_obj
|
self.props[prop_name] = Prop(self, None, prop_name, '\0' * 4)
|
||||||
if fdt_obj.setprop_u32(self.Offset(), prop_name, 0,
|
|
||||||
(libfdt.NOSPACE,)) == -libfdt.NOSPACE:
|
def AddEmptyProp(self, prop_name, len):
|
||||||
fdt_obj.resize(fdt_obj.totalsize() + 1024)
|
"""Add a property with a fixed data size, for filling in later
|
||||||
fdt_obj.setprop_u32(self.Offset(), prop_name, 0)
|
|
||||||
self.props[prop_name] = Prop(self, -1, prop_name, '\0' * 4)
|
The device tree is marked dirty so that the value will be written to
|
||||||
self._fdt.Invalidate()
|
the blob on the next sync.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prop_name: Name of property
|
||||||
|
len: Length of data in property
|
||||||
|
"""
|
||||||
|
value = chr(0) * len
|
||||||
|
self.props[prop_name] = Prop(self, None, prop_name, value)
|
||||||
|
|
||||||
def SetInt(self, prop_name, val):
|
def SetInt(self, prop_name, val):
|
||||||
"""Update an integer property int the device tree.
|
"""Update an integer property int the device tree.
|
||||||
|
|
||||||
This is not allowed to change the size of the FDT.
|
This is not allowed to change the size of the FDT.
|
||||||
|
|
||||||
|
The device tree is marked dirty so that the value will be written to
|
||||||
|
the blob on the next sync.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
prop_name: Name of property
|
prop_name: Name of property
|
||||||
val: Value to set
|
val: Value to set
|
||||||
"""
|
"""
|
||||||
fdt_obj = self._fdt._fdt_obj
|
self.props[prop_name].SetInt(val)
|
||||||
fdt_obj.setprop_u32(self.Offset(), prop_name, val)
|
|
||||||
|
def SetData(self, prop_name, val):
|
||||||
|
"""Set the data value of a property
|
||||||
|
|
||||||
|
The device tree is marked dirty so that the value will be written to
|
||||||
|
the blob on the next sync.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prop_name: Name of property to set
|
||||||
|
val: Data value to set
|
||||||
|
"""
|
||||||
|
self.props[prop_name].SetData(val)
|
||||||
|
|
||||||
|
def SetString(self, prop_name, val):
|
||||||
|
"""Set the string value of a property
|
||||||
|
|
||||||
|
The device tree is marked dirty so that the value will be written to
|
||||||
|
the blob on the next sync.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prop_name: Name of property to set
|
||||||
|
val: String value to set (will be \0-terminated in DT)
|
||||||
|
"""
|
||||||
|
self.props[prop_name].SetData(val + chr(0))
|
||||||
|
|
||||||
|
def AddString(self, prop_name, val):
|
||||||
|
"""Add a new string property to a node
|
||||||
|
|
||||||
|
The device tree is marked dirty so that the value will be written to
|
||||||
|
the blob on the next sync.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prop_name: Name of property to add
|
||||||
|
val: String value of property
|
||||||
|
"""
|
||||||
|
self.props[prop_name] = Prop(self, None, prop_name, val + chr(0))
|
||||||
|
|
||||||
|
def AddSubnode(self, name):
|
||||||
|
"""Add a new subnode to the node
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: name of node to add
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
New subnode that was created
|
||||||
|
"""
|
||||||
|
path = self.path + '/' + name
|
||||||
|
subnode = Node(self._fdt, self, None, name, path)
|
||||||
|
self.subnodes.append(subnode)
|
||||||
|
return subnode
|
||||||
|
|
||||||
|
def Sync(self, auto_resize=False):
|
||||||
|
"""Sync node changes back to the device tree
|
||||||
|
|
||||||
|
This updates the device tree blob with any changes to this node and its
|
||||||
|
subnodes since the last sync.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
auto_resize: Resize the device tree automatically if it does not
|
||||||
|
have enough space for the update
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FdtException if auto_resize is False and there is not enough space
|
||||||
|
"""
|
||||||
|
if self._offset is None:
|
||||||
|
# The subnode doesn't exist yet, so add it
|
||||||
|
fdt_obj = self._fdt._fdt_obj
|
||||||
|
if auto_resize:
|
||||||
|
while True:
|
||||||
|
offset = fdt_obj.add_subnode(self.parent._offset, self.name,
|
||||||
|
(libfdt.NOSPACE,))
|
||||||
|
if offset != -libfdt.NOSPACE:
|
||||||
|
break
|
||||||
|
fdt_obj.resize(fdt_obj.totalsize() + 1024)
|
||||||
|
else:
|
||||||
|
offset = fdt_obj.add_subnode(self.parent._offset, self.name)
|
||||||
|
self._offset = offset
|
||||||
|
|
||||||
|
# Sync subnodes in reverse so that we don't disturb node offsets for
|
||||||
|
# nodes that are earlier in the DT. This avoids an O(n^2) rescan of
|
||||||
|
# node offsets.
|
||||||
|
for node in reversed(self.subnodes):
|
||||||
|
node.Sync(auto_resize)
|
||||||
|
|
||||||
|
# Sync properties now, whose offsets should not have been disturbed.
|
||||||
|
# We do this after subnodes, since this disturbs the offsets of these
|
||||||
|
# properties.
|
||||||
|
prop_list = sorted(self.props.values(), key=lambda prop: prop._offset,
|
||||||
|
reverse=True)
|
||||||
|
for prop in prop_list:
|
||||||
|
prop.Sync(auto_resize)
|
||||||
|
|
||||||
|
|
||||||
class Fdt:
|
class Fdt:
|
||||||
|
@ -322,6 +472,20 @@ class Fdt:
|
||||||
with open(self._fname) as fd:
|
with open(self._fname) as fd:
|
||||||
self._fdt_obj = libfdt.Fdt(fd.read())
|
self._fdt_obj = libfdt.Fdt(fd.read())
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def FromData(data):
|
||||||
|
"""Create a new Fdt object from the given data
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data: Device-tree data blob
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Fdt object containing the data
|
||||||
|
"""
|
||||||
|
fdt = Fdt(None)
|
||||||
|
fdt._fdt_obj = libfdt.Fdt(bytearray(data))
|
||||||
|
return fdt
|
||||||
|
|
||||||
def LookupPhandle(self, phandle):
|
def LookupPhandle(self, phandle):
|
||||||
"""Look up a phandle
|
"""Look up a phandle
|
||||||
|
|
||||||
|
@ -381,6 +545,19 @@ class Fdt:
|
||||||
with open(self._fname, 'wb') as fd:
|
with open(self._fname, 'wb') as fd:
|
||||||
fd.write(self._fdt_obj.as_bytearray())
|
fd.write(self._fdt_obj.as_bytearray())
|
||||||
|
|
||||||
|
def Sync(self, auto_resize=False):
|
||||||
|
"""Make sure any DT changes are written to the blob
|
||||||
|
|
||||||
|
Args:
|
||||||
|
auto_resize: Resize the device tree automatically if it does not
|
||||||
|
have enough space for the update
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
FdtException if auto_resize is False and there is not enough space
|
||||||
|
"""
|
||||||
|
self._root.Sync(auto_resize)
|
||||||
|
self.Invalidate()
|
||||||
|
|
||||||
def Pack(self):
|
def Pack(self):
|
||||||
"""Pack the device tree down to its minimum size
|
"""Pack the device tree down to its minimum size
|
||||||
|
|
||||||
|
|
|
@ -337,6 +337,7 @@ class TestProp(unittest.TestCase):
|
||||||
self.node.AddZeroProp('one')
|
self.node.AddZeroProp('one')
|
||||||
self.node.AddZeroProp('two')
|
self.node.AddZeroProp('two')
|
||||||
self.node.AddZeroProp('three')
|
self.node.AddZeroProp('three')
|
||||||
|
self.dtb.Sync(auto_resize=True)
|
||||||
|
|
||||||
# Updating existing properties should be OK, since the device-tree size
|
# Updating existing properties should be OK, since the device-tree size
|
||||||
# does not change
|
# does not change
|
||||||
|
@ -344,11 +345,75 @@ class TestProp(unittest.TestCase):
|
||||||
self.node.SetInt('one', 1)
|
self.node.SetInt('one', 1)
|
||||||
self.node.SetInt('two', 2)
|
self.node.SetInt('two', 2)
|
||||||
self.node.SetInt('three', 3)
|
self.node.SetInt('three', 3)
|
||||||
|
self.dtb.Sync(auto_resize=False)
|
||||||
|
|
||||||
# This should fail since it would need to increase the device-tree size
|
# This should fail since it would need to increase the device-tree size
|
||||||
|
self.node.AddZeroProp('four')
|
||||||
with self.assertRaises(libfdt.FdtException) as e:
|
with self.assertRaises(libfdt.FdtException) as e:
|
||||||
self.node.SetInt('four', 4)
|
self.dtb.Sync(auto_resize=False)
|
||||||
self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
|
self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
|
||||||
|
self.dtb.Sync(auto_resize=True)
|
||||||
|
|
||||||
|
def testAddNode(self):
|
||||||
|
self.fdt.pack()
|
||||||
|
self.node.AddSubnode('subnode')
|
||||||
|
with self.assertRaises(libfdt.FdtException) as e:
|
||||||
|
self.dtb.Sync(auto_resize=False)
|
||||||
|
self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
|
||||||
|
|
||||||
|
self.dtb.Sync(auto_resize=True)
|
||||||
|
offset = self.fdt.path_offset('/spl-test/subnode')
|
||||||
|
self.assertTrue(offset > 0)
|
||||||
|
|
||||||
|
def testAddMore(self):
|
||||||
|
"""Test various other methods for adding and setting properties"""
|
||||||
|
self.node.AddZeroProp('one')
|
||||||
|
self.dtb.Sync(auto_resize=True)
|
||||||
|
data = self.fdt.getprop(self.node.Offset(), 'one')
|
||||||
|
self.assertEqual(0, fdt32_to_cpu(data))
|
||||||
|
|
||||||
|
self.node.SetInt('one', 1)
|
||||||
|
self.dtb.Sync(auto_resize=False)
|
||||||
|
data = self.fdt.getprop(self.node.Offset(), 'one')
|
||||||
|
self.assertEqual(1, fdt32_to_cpu(data))
|
||||||
|
|
||||||
|
val = '123' + chr(0) + '456'
|
||||||
|
self.node.AddString('string', val)
|
||||||
|
self.dtb.Sync(auto_resize=True)
|
||||||
|
data = self.fdt.getprop(self.node.Offset(), 'string')
|
||||||
|
self.assertEqual(val + '\0', data)
|
||||||
|
|
||||||
|
self.fdt.pack()
|
||||||
|
self.node.SetString('string', val + 'x')
|
||||||
|
with self.assertRaises(libfdt.FdtException) as e:
|
||||||
|
self.dtb.Sync(auto_resize=False)
|
||||||
|
self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
|
||||||
|
self.node.SetString('string', val[:-1])
|
||||||
|
|
||||||
|
prop = self.node.props['string']
|
||||||
|
prop.SetData(val)
|
||||||
|
self.dtb.Sync(auto_resize=False)
|
||||||
|
data = self.fdt.getprop(self.node.Offset(), 'string')
|
||||||
|
self.assertEqual(val, data)
|
||||||
|
|
||||||
|
self.node.AddEmptyProp('empty', 5)
|
||||||
|
self.dtb.Sync(auto_resize=True)
|
||||||
|
prop = self.node.props['empty']
|
||||||
|
prop.SetData(val)
|
||||||
|
self.dtb.Sync(auto_resize=False)
|
||||||
|
data = self.fdt.getprop(self.node.Offset(), 'empty')
|
||||||
|
self.assertEqual(val, data)
|
||||||
|
|
||||||
|
self.node.SetData('empty', '123')
|
||||||
|
self.assertEqual('123', prop.bytes)
|
||||||
|
|
||||||
|
def testFromData(self):
|
||||||
|
dtb2 = fdt.Fdt.FromData(self.dtb.GetContents())
|
||||||
|
self.assertEqual(dtb2.GetContents(), self.dtb.GetContents())
|
||||||
|
|
||||||
|
self.node.AddEmptyProp('empty', 5)
|
||||||
|
self.dtb.Sync(auto_resize=True)
|
||||||
|
self.assertTrue(dtb2.GetContents() != self.dtb.GetContents())
|
||||||
|
|
||||||
|
|
||||||
class TestFdtUtil(unittest.TestCase):
|
class TestFdtUtil(unittest.TestCase):
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import command
|
import command
|
||||||
|
import glob
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
|
@ -22,6 +23,10 @@ chroot_path = None
|
||||||
# Search paths to use for Filename(), used to find files
|
# Search paths to use for Filename(), used to find files
|
||||||
search_paths = []
|
search_paths = []
|
||||||
|
|
||||||
|
# Tools and the packages that contain them, on debian
|
||||||
|
packages = {
|
||||||
|
'lz4': 'liblz4-tool',
|
||||||
|
}
|
||||||
|
|
||||||
def PrepareOutputDir(dirname, preserve=False):
|
def PrepareOutputDir(dirname, preserve=False):
|
||||||
"""Select an output directory, ensuring it exists.
|
"""Select an output directory, ensuring it exists.
|
||||||
|
@ -119,6 +124,23 @@ def GetInputFilename(fname):
|
||||||
raise ValueError("Filename '%s' not found in input path (%s) (cwd='%s')" %
|
raise ValueError("Filename '%s' not found in input path (%s) (cwd='%s')" %
|
||||||
(fname, ','.join(indir), os.getcwd()))
|
(fname, ','.join(indir), os.getcwd()))
|
||||||
|
|
||||||
|
def GetInputFilenameGlob(pattern):
|
||||||
|
"""Return a list of filenames for use as input.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
pattern: Filename pattern to search for
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A list of matching files in all input directories
|
||||||
|
"""
|
||||||
|
if not indir:
|
||||||
|
return glob.glob(fname)
|
||||||
|
files = []
|
||||||
|
for dirname in indir:
|
||||||
|
pathname = os.path.join(dirname, pattern)
|
||||||
|
files += glob.glob(pathname)
|
||||||
|
return sorted(files)
|
||||||
|
|
||||||
def Align(pos, align):
|
def Align(pos, align):
|
||||||
if align:
|
if align:
|
||||||
mask = align - 1
|
mask = align - 1
|
||||||
|
@ -128,8 +150,31 @@ def Align(pos, align):
|
||||||
def NotPowerOfTwo(num):
|
def NotPowerOfTwo(num):
|
||||||
return num and (num & (num - 1))
|
return num and (num & (num - 1))
|
||||||
|
|
||||||
|
def PathHasFile(fname):
|
||||||
|
"""Check if a given filename is in the PATH
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fname: Filename to check
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if found, False if not
|
||||||
|
"""
|
||||||
|
for dir in os.environ['PATH'].split(':'):
|
||||||
|
if os.path.exists(os.path.join(dir, fname)):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def Run(name, *args):
|
def Run(name, *args):
|
||||||
command.Run(name, *args, cwd=outdir)
|
try:
|
||||||
|
return command.Run(name, *args, cwd=outdir, capture=True)
|
||||||
|
except:
|
||||||
|
if not PathHasFile(name):
|
||||||
|
msg = "Plesae install tool '%s'" % name
|
||||||
|
package = packages.get(name)
|
||||||
|
if package:
|
||||||
|
msg += " (e.g. from package '%s')" % package
|
||||||
|
raise ValueError(msg)
|
||||||
|
raise
|
||||||
|
|
||||||
def Filename(fname):
|
def Filename(fname):
|
||||||
"""Resolve a file path to an absolute path.
|
"""Resolve a file path to an absolute path.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue