More tests and fixes for fdt command

binman signing feature
 fix buildman -A bug introduced recently
 -----BEGIN PGP SIGNATURE-----
 
 iQFFBAABCgAvFiEEslwAIq+Gp8wWVbYnfxc6PpAIreYFAmQQ8KIRHHNqZ0BjaHJv
 bWl1bS5vcmcACgkQfxc6PpAIreYRmwgA1XAHafEOfhaya54nalUgW9qYZe5Ntfqd
 4Tg7zj3gadZuv82LuyskEyBKptwRCzgX0Tyx62V3Oop9vJ/cCwjIB4AGhCsMKERf
 NqcMd8fbGbJ9jJzOp7gNTHzV4vSmwKM0lRkxbClMFcvMsfVdKcBRPswLLghk5/xL
 Uu4Ww4yfe7UCqgBm9uouVaIbcNNcl8p0QnSJT9HvwjGKawPT6uSHOHK9Wpkud0q1
 ZyrPpCMA29mifhIU8aH5CJH5G61UbGcVSDhm9lIKwqZg+KJGuYf64JbZoY9JI2/z
 pOUHLZx7fVHoFyWKWfVkA9l6HRjZTRc0nJhYFx5HyNUOU50hMENeTQ==
 =ko2P
 -----END PGP SIGNATURE-----

Merge tag 'dm-next-12mar23a' of git://git.denx.de/u-boot-dm into next

More tests and fixes for fdt command
binman signing feature
fix buildman -A bug introduced recently

Signed-off-by: Tom Rini <trini@konsulko.com>
This commit is contained in:
Tom Rini 2023-03-16 12:16:14 -04:00
commit cb90ddb2a6
25 changed files with 1155 additions and 84 deletions

View file

@ -478,7 +478,7 @@ static int do_fdt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
/* Get address */
char buf[19];
snprintf(buf, sizeof(buf), "0x%lx",
snprintf(buf, sizeof(buf), "%lx",
(ulong)map_to_sysmem(nodep));
env_set(var, buf);
} else if (subcmd[0] == 's') {

View file

@ -842,7 +842,7 @@ int console_record_readline(char *str, int maxlen)
return -ENOSPC;
return membuff_readline((struct membuff *)&gd->console_out, str,
maxlen, ' ');
maxlen, '\0');
}
int console_record_avail(void)

View file

@ -13,6 +13,7 @@
#include <command.h>
#include <console.h>
#include <env.h>
#include <fdtdec.h>
#include <init.h>
#include <net.h>
#include <version_string.h>

View file

@ -125,36 +125,47 @@ int ut_check_console_dump(struct unit_test_state *uts, int total_bytes);
fmt, ##args)
/* Assert that a condition is non-zero */
#define ut_assert(cond) \
#define ut_assert(cond) ({ \
int __ret = 0; \
\
if (!(cond)) { \
ut_fail(uts, __FILE__, __LINE__, __func__, #cond); \
return CMD_RET_FAILURE; \
}
__ret = CMD_RET_FAILURE; \
} \
__ret; \
})
/* Assert that a condition is non-zero, with printf() string */
#define ut_assertf(cond, fmt, args...) \
#define ut_assertf(cond, fmt, args...) ({ \
int __ret = 0; \
\
if (!(cond)) { \
ut_failf(uts, __FILE__, __LINE__, __func__, #cond, \
fmt, ##args); \
return CMD_RET_FAILURE; \
}
__ret = CMD_RET_FAILURE; \
} \
__ret; \
})
/* Assert that two int expressions are equal */
#define ut_asserteq(expr1, expr2) { \
#define ut_asserteq(expr1, expr2) ({ \
unsigned int _val1 = (expr1), _val2 = (expr2); \
int __ret = 0; \
\
if (_val1 != _val2) { \
ut_failf(uts, __FILE__, __LINE__, __func__, \
#expr1 " == " #expr2, \
"Expected %#x (%d), got %#x (%d)", \
_val1, _val1, _val2, _val2); \
return CMD_RET_FAILURE; \
__ret = CMD_RET_FAILURE; \
} \
}
__ret; \
})
/* Assert that two 64 int expressions are equal */
#define ut_asserteq_64(expr1, expr2) { \
#define ut_asserteq_64(expr1, expr2) ({ \
u64 _val1 = (expr1), _val2 = (expr2); \
int __ret = 0; \
\
if (_val1 != _val2) { \
ut_failf(uts, __FILE__, __LINE__, __func__, \
@ -164,43 +175,49 @@ int ut_check_console_dump(struct unit_test_state *uts, int total_bytes);
(unsigned long long)_val1, \
(unsigned long long)_val2, \
(unsigned long long)_val2); \
return CMD_RET_FAILURE; \
__ret = CMD_RET_FAILURE; \
} \
}
__ret; \
})
/* Assert that two string expressions are equal */
#define ut_asserteq_str(expr1, expr2) { \
#define ut_asserteq_str(expr1, expr2) ({ \
const char *_val1 = (expr1), *_val2 = (expr2); \
int __ret = 0; \
\
if (strcmp(_val1, _val2)) { \
ut_failf(uts, __FILE__, __LINE__, __func__, \
#expr1 " = " #expr2, \
"Expected \"%s\", got \"%s\"", _val1, _val2); \
return CMD_RET_FAILURE; \
__ret = CMD_RET_FAILURE; \
} \
}
__ret; \
})
/*
* Assert that two string expressions are equal, up to length of the
* first
*/
#define ut_asserteq_strn(expr1, expr2) { \
#define ut_asserteq_strn(expr1, expr2) ({ \
const char *_val1 = (expr1), *_val2 = (expr2); \
int _len = strlen(_val1); \
int __ret = 0; \
\
if (memcmp(_val1, _val2, _len)) { \
ut_failf(uts, __FILE__, __LINE__, __func__, \
#expr1 " = " #expr2, \
"Expected \"%.*s\", got \"%.*s\"", \
_len, _val1, _len, _val2); \
return CMD_RET_FAILURE; \
__ret = CMD_RET_FAILURE; \
} \
}
__ret; \
})
/* Assert that two memory areas are equal */
#define ut_asserteq_mem(expr1, expr2, len) { \
#define ut_asserteq_mem(expr1, expr2, len) ({ \
const u8 *_val1 = (u8 *)(expr1), *_val2 = (u8 *)(expr2); \
const uint __len = len; \
int __ret = 0; \
\
if (memcmp(_val1, _val2, __len)) { \
char __buf1[64 + 1] = "\0"; \
@ -211,128 +228,163 @@ int ut_check_console_dump(struct unit_test_state *uts, int total_bytes);
#expr1 " = " #expr2, \
"Expected \"%s\", got \"%s\"", \
__buf1, __buf2); \
return CMD_RET_FAILURE; \
__ret = CMD_RET_FAILURE; \
} \
}
__ret; \
})
/* Assert that two pointers are equal */
#define ut_asserteq_ptr(expr1, expr2) { \
#define ut_asserteq_ptr(expr1, expr2) ({ \
const void *_val1 = (expr1), *_val2 = (expr2); \
int __ret = 0; \
\
if (_val1 != _val2) { \
ut_failf(uts, __FILE__, __LINE__, __func__, \
#expr1 " = " #expr2, \
"Expected %p, got %p", _val1, _val2); \
return CMD_RET_FAILURE; \
__ret = CMD_RET_FAILURE; \
} \
}
__ret; \
})
/* Assert that two addresses (converted from pointers) are equal */
#define ut_asserteq_addr(expr1, expr2) { \
#define ut_asserteq_addr(expr1, expr2) ({ \
ulong _val1 = map_to_sysmem(expr1); \
ulong _val2 = map_to_sysmem(expr2); \
int __ret = 0; \
\
if (_val1 != _val2) { \
ut_failf(uts, __FILE__, __LINE__, __func__, \
#expr1 " = " #expr2, \
"Expected %lx, got %lx", _val1, _val2); \
return CMD_RET_FAILURE; \
__ret = CMD_RET_FAILURE; \
} \
}
__ret; \
})
/* Assert that a pointer is NULL */
#define ut_assertnull(expr) { \
#define ut_assertnull(expr) ({ \
const void *_val = (expr); \
int __ret = 0; \
\
if (_val) { \
if (_val) { \
ut_failf(uts, __FILE__, __LINE__, __func__, \
#expr " != NULL", \
"Expected NULL, got %p", _val); \
return CMD_RET_FAILURE; \
__ret = CMD_RET_FAILURE; \
} \
}
__ret; \
})
/* Assert that a pointer is not NULL */
#define ut_assertnonnull(expr) { \
#define ut_assertnonnull(expr) ({ \
const void *_val = (expr); \
int __ret = 0; \
\
if (!_val) { \
if (!_val) { \
ut_failf(uts, __FILE__, __LINE__, __func__, \
#expr " = NULL", \
"Expected non-null, got NULL"); \
return CMD_RET_FAILURE; \
__ret = CMD_RET_FAILURE; \
} \
}
__ret; \
})
/* Assert that a pointer is not an error pointer */
#define ut_assertok_ptr(expr) { \
#define ut_assertok_ptr(expr) ({ \
const void *_val = (expr); \
int __ret = 0; \
\
if (IS_ERR(_val)) { \
ut_failf(uts, __FILE__, __LINE__, __func__, \
#expr " = NULL", \
"Expected pointer, got error %ld", \
PTR_ERR(_val)); \
return CMD_RET_FAILURE; \
__ret = CMD_RET_FAILURE; \
} \
}
__ret; \
})
/* Assert that an operation succeeds (returns 0) */
#define ut_assertok(cond) ut_asserteq(0, cond)
/* Assert that the next console output line matches */
#define ut_assert_nextline(fmt, args...) \
#define ut_assert_nextline(fmt, args...) ({ \
int __ret = 0; \
\
if (ut_check_console_line(uts, fmt, ##args)) { \
ut_failf(uts, __FILE__, __LINE__, __func__, \
"console", "\nExpected '%s',\n got '%s'", \
uts->expect_str, uts->actual_str); \
return CMD_RET_FAILURE; \
__ret = CMD_RET_FAILURE; \
} \
__ret; \
})
/* Assert that the next console output line matches up to the length */
#define ut_assert_nextlinen(fmt, args...) \
#define ut_assert_nextlinen(fmt, args...) ({ \
int __ret = 0; \
\
if (ut_check_console_linen(uts, fmt, ##args)) { \
ut_failf(uts, __FILE__, __LINE__, __func__, \
"console", "\nExpected '%s',\n got '%s'", \
uts->expect_str, uts->actual_str); \
return CMD_RET_FAILURE; \
__ret = CMD_RET_FAILURE; \
} \
__ret; \
})
/* Assert that there is a 'next' console output line, and skip it */
#define ut_assert_skipline() \
#define ut_assert_skipline() ({ \
int __ret = 0; \
\
if (ut_check_skipline(uts)) { \
ut_failf(uts, __FILE__, __LINE__, __func__, \
"console", "\nExpected a line, got end"); \
return CMD_RET_FAILURE; \
__ret = CMD_RET_FAILURE; \
} \
__ret; \
})
/* Assert that a following console output line matches */
#define ut_assert_skip_to_line(fmt, args...) \
#define ut_assert_skip_to_line(fmt, args...) ({ \
int __ret = 0; \
\
if (ut_check_skip_to_line(uts, fmt, ##args)) { \
ut_failf(uts, __FILE__, __LINE__, __func__, \
"console", "\nExpected '%s',\n got to '%s'", \
uts->expect_str, uts->actual_str); \
return CMD_RET_FAILURE; \
__ret = CMD_RET_FAILURE; \
} \
__ret; \
})
/* Assert that there is no more console output */
#define ut_assert_console_end() \
#define ut_assert_console_end() ({ \
int __ret = 0; \
\
if (ut_check_console_end(uts)) { \
ut_failf(uts, __FILE__, __LINE__, __func__, \
"console", "Expected no more output, got '%s'",\
uts->actual_str); \
return CMD_RET_FAILURE; \
__ret = CMD_RET_FAILURE; \
} \
__ret; \
})
/* Assert that the next lines are print_buffer() dump at an address */
#define ut_assert_nextlines_are_dump(total_bytes) \
#define ut_assert_nextlines_are_dump(total_bytes) ({ \
int __ret = 0; \
\
if (ut_check_console_dump(uts, total_bytes)) { \
ut_failf(uts, __FILE__, __LINE__, __func__, \
"console", \
"Expected dump of length %x bytes, got '%s'", \
total_bytes, uts->actual_str); \
return CMD_RET_FAILURE; \
__ret = CMD_RET_FAILURE; \
} \
__ret; \
})
/* Assert that the next console output line is empty */
#define ut_assert_nextline_empty() \

View file

@ -303,6 +303,149 @@ static int fdt_test_resize(struct unit_test_state *uts)
}
FDT_TEST(fdt_test_resize, UT_TESTF_CONSOLE_REC);
static int fdt_test_print_list_common(struct unit_test_state *uts,
const char *opc, const char *node)
{
/*
* Test printing/listing the working FDT
* subnode $node/subnode
*/
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt %s %s/subnode", opc, node));
ut_assert_nextline("subnode {");
ut_assert_nextline("\t#address-cells = <0x00000000>;");
ut_assert_nextline("\t#size-cells = <0x00000000>;");
ut_assert_nextline("\tcompatible = \"u-boot,fdt-subnode-test-device\";");
ut_assert_nextline("};");
ut_assertok(ut_check_console_end(uts));
/*
* Test printing/listing the working FDT
* path / string property model
*/
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt %s / model", opc));
ut_assert_nextline("model = \"U-Boot FDT test\"");
ut_assertok(ut_check_console_end(uts));
/*
* Test printing/listing the working FDT
* path $node string property compatible
*/
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt %s %s compatible", opc, node));
ut_assert_nextline("compatible = \"u-boot,fdt-test-device1\"");
ut_assertok(ut_check_console_end(uts));
/*
* Test printing/listing the working FDT
* path $node stringlist property clock-names
*/
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt %s %s clock-names", opc, node));
ut_assert_nextline("clock-names = \"fixed\", \"i2c\", \"spi\", \"uart2\", \"uart1\"");
ut_assertok(ut_check_console_end(uts));
/*
* Test printing/listing the working FDT
* path $node u32 property clock-frequency
*/
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt %s %s clock-frequency", opc, node));
ut_assert_nextline("clock-frequency = <0x00fde800>");
ut_assertok(ut_check_console_end(uts));
/*
* Test printing/listing the working FDT
* path $node empty property u-boot,empty-property
*/
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt %s %s u-boot,empty-property", opc, node));
/*
* This is the only 'fdt print' / 'fdt list' incantation which
* prefixes the property with node path. This has been in U-Boot
* since the beginning of the command 'fdt', keep it.
*/
ut_assert_nextline("%s u-boot,empty-property", node);
ut_assertok(ut_check_console_end(uts));
/*
* Test printing/listing the working FDT
* path $node prop-encoded array property regs
*/
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt %s %s regs", opc, node));
ut_assert_nextline("regs = <0x00001234 0x00001000>");
ut_assertok(ut_check_console_end(uts));
return 0;
}
static int fdt_test_print_list(struct unit_test_state *uts, bool print)
{
const char *opc = print ? "print" : "list";
char fdt[4096];
ulong addr;
int ret;
/* Original source DT */
ut_assertok(make_fuller_fdt(uts, fdt, sizeof(fdt)));
addr = map_to_sysmem(fdt);
set_working_fdt_addr(addr);
/* Test printing/listing the working FDT -- node / */
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt %s", opc));
ut_assert_nextline("/ {");
ut_assert_nextline("\t#address-cells = <0x00000001>;");
ut_assert_nextline("\t#size-cells = <0x00000001>;");
ut_assert_nextline("\tcompatible = \"u-boot,fdt-test\";");
ut_assert_nextline("\tmodel = \"U-Boot FDT test\";");
ut_assert_nextline("\taliases {");
if (print) {
ut_assert_nextline("\t\tbadalias = \"/bad/alias\";");
ut_assert_nextline("\t\tsubnodealias = \"/test-node@1234/subnode\";");
ut_assert_nextline("\t\ttestnodealias = \"/test-node@1234\";");
}
ut_assert_nextline("\t};");
ut_assert_nextline("\ttest-node@1234 {");
if (print) {
ut_assert_nextline("\t\t#address-cells = <0x00000000>;");
ut_assert_nextline("\t\t#size-cells = <0x00000000>;");
ut_assert_nextline("\t\tcompatible = \"u-boot,fdt-test-device1\";");
ut_assert_nextline("\t\tclock-names = \"fixed\", \"i2c\", \"spi\", \"uart2\", \"uart1\";");
ut_assert_nextline("\t\tu-boot,empty-property;");
ut_assert_nextline("\t\tclock-frequency = <0x00fde800>;");
ut_assert_nextline("\t\tregs = <0x00001234 0x00001000>;");
ut_assert_nextline("\t\tsubnode {");
ut_assert_nextline("\t\t\t#address-cells = <0x00000000>;");
ut_assert_nextline("\t\t\t#size-cells = <0x00000000>;");
ut_assert_nextline("\t\t\tcompatible = \"u-boot,fdt-subnode-test-device\";");
ut_assert_nextline("\t\t};");
}
ut_assert_nextline("\t};");
ut_assert_nextline("};");
ut_assertok(ut_check_console_end(uts));
ret = fdt_test_print_list_common(uts, opc, "/test-node@1234");
if (!ret)
ret = fdt_test_print_list_common(uts, opc, "testnodealias");
return 0;
}
static int fdt_test_print(struct unit_test_state *uts)
{
return fdt_test_print_list(uts, true);
}
FDT_TEST(fdt_test_print, UT_TESTF_CONSOLE_REC);
static int fdt_test_list(struct unit_test_state *uts)
{
return fdt_test_print_list(uts, false);
}
FDT_TEST(fdt_test_list, UT_TESTF_CONSOLE_REC);
/* Test 'fdt get value' reading an fdt */
static int fdt_test_get_value_string(struct unit_test_state *uts,
const char *node, const char *prop,
@ -653,23 +796,21 @@ static int fdt_test_set_single(struct unit_test_state *uts,
* => fdt set /path property
*/
ut_assertok(console_record_reset_enable());
if (sval) {
if (sval)
ut_assertok(run_commandf("fdt set %s %s %s", path, prop, sval));
} else if (integer) {
else if (integer)
ut_assertok(run_commandf("fdt set %s %s <%d>", path, prop, ival));
} else {
else
ut_assertok(run_commandf("fdt set %s %s", path, prop));
}
/* Validate the property is present and has correct value. */
ut_assertok(run_commandf("fdt get value svar %s %s", path, prop));
if (sval) {
if (sval)
ut_asserteq_str(sval, env_get("svar"));
} else if (integer) {
else if (integer)
ut_asserteq(ival, env_get_hex("svar", 0x1234));
} else {
else
ut_assertnull(env_get("svar"));
}
ut_assertok(ut_check_console_end(uts));
return 0;
@ -971,6 +1112,411 @@ static int fdt_test_bootcpu(struct unit_test_state *uts)
}
FDT_TEST(fdt_test_bootcpu, UT_TESTF_CONSOLE_REC);
static int fdt_test_header_get(struct unit_test_state *uts,
const char *field, const unsigned long val)
{
/* Test getting valid header entry */
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt header get fvar %s", field));
ut_asserteq(val, env_get_hex("fvar", 0x1234));
ut_assertok(ut_check_console_end(uts));
/* Test getting malformed header entry */
ut_assertok(console_record_reset_enable());
ut_asserteq(1, run_commandf("fdt header get fvar typo%stypo", field));
ut_assertok(ut_check_console_end(uts));
return 0;
}
static int fdt_test_header(struct unit_test_state *uts)
{
char fdt[256];
ulong addr;
ut_assertok(make_test_fdt(uts, fdt, sizeof(fdt)));
addr = map_to_sysmem(fdt);
set_working_fdt_addr(addr);
/* Test header print */
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt header"));
ut_assert_nextline("magic:\t\t\t0x%x", fdt_magic(fdt));
ut_assert_nextline("totalsize:\t\t0x%x (%d)", fdt_totalsize(fdt), fdt_totalsize(fdt));
ut_assert_nextline("off_dt_struct:\t\t0x%x", fdt_off_dt_struct(fdt));
ut_assert_nextline("off_dt_strings:\t\t0x%x", fdt_off_dt_strings(fdt));
ut_assert_nextline("off_mem_rsvmap:\t\t0x%x", fdt_off_mem_rsvmap(fdt));
ut_assert_nextline("version:\t\t%d", fdt_version(fdt));
ut_assert_nextline("last_comp_version:\t%d", fdt_last_comp_version(fdt));
ut_assert_nextline("boot_cpuid_phys:\t0x%x", fdt_boot_cpuid_phys(fdt));
ut_assert_nextline("size_dt_strings:\t0x%x", fdt_size_dt_strings(fdt));
ut_assert_nextline("size_dt_struct:\t\t0x%x", fdt_size_dt_struct(fdt));
ut_assert_nextline("number mem_rsv:\t\t0x%x", fdt_num_mem_rsv(fdt));
ut_assert_nextline_empty();
ut_assertok(ut_check_console_end(uts));
/* Test header get */
fdt_test_header_get(uts, "magic", fdt_magic(fdt));
fdt_test_header_get(uts, "totalsize", fdt_totalsize(fdt));
fdt_test_header_get(uts, "off_dt_struct", fdt_off_dt_struct(fdt));
fdt_test_header_get(uts, "off_dt_strings", fdt_off_dt_strings(fdt));
fdt_test_header_get(uts, "off_mem_rsvmap", fdt_off_mem_rsvmap(fdt));
fdt_test_header_get(uts, "version", fdt_version(fdt));
fdt_test_header_get(uts, "last_comp_version", fdt_last_comp_version(fdt));
fdt_test_header_get(uts, "boot_cpuid_phys", fdt_boot_cpuid_phys(fdt));
fdt_test_header_get(uts, "size_dt_strings", fdt_size_dt_strings(fdt));
fdt_test_header_get(uts, "size_dt_struct", fdt_size_dt_struct(fdt));
return 0;
}
FDT_TEST(fdt_test_header, UT_TESTF_CONSOLE_REC);
static int fdt_test_memory_cells(struct unit_test_state *uts,
const unsigned int cells)
{
unsigned char *pada, *pads;
unsigned char *seta, *sets;
char fdt[8192];
const int size = sizeof(fdt);
fdt32_t *regs;
ulong addr;
char *spc;
int i;
/* Create DT with node /memory { regs = <0x100 0x200>; } and #*cells */
ut_assertnonnull(regs = calloc(2 * cells, sizeof(*regs)));
ut_assertnonnull(pada = calloc(12, cells));
ut_assertnonnull(pads = calloc(12, cells));
ut_assertnonnull(seta = calloc(12, cells));
ut_assertnonnull(sets = calloc(12, cells));
for (i = cells; i >= 1; i--) {
regs[cells - 1] = cpu_to_fdt32(i * 0x10000);
regs[(cells * 2) - 1] = cpu_to_fdt32(~i);
snprintf(seta + (8 * (cells - i)), 9, "%08x", i * 0x10000);
snprintf(sets + (8 * (cells - i)), 9, "%08x", ~i);
spc = (i != 1) ? " " : "";
snprintf(pada + (11 * (cells - i)), 12, "0x%08x%s", i * 0x10000, spc);
snprintf(pads + (11 * (cells - i)), 12, "0x%08x%s", ~i, spc);
}
ut_assertok(fdt_create(fdt, size));
ut_assertok(fdt_finish_reservemap(fdt));
ut_assert(fdt_begin_node(fdt, "") >= 0);
ut_assertok(fdt_property_u32(fdt, "#address-cells", cells));
ut_assertok(fdt_property_u32(fdt, "#size-cells", cells));
ut_assert(fdt_begin_node(fdt, "memory") >= 0);
ut_assertok(fdt_property_string(fdt, "device_type", "memory"));
ut_assertok(fdt_property(fdt, "reg", &regs, cells * 2));
ut_assertok(fdt_end_node(fdt));
ut_assertok(fdt_end_node(fdt));
ut_assertok(fdt_finish(fdt));
fdt_shrink_to_minimum(fdt, 4096); /* Resize with 4096 extra bytes */
addr = map_to_sysmem(fdt);
set_working_fdt_addr(addr);
/* Test updating the memory node */
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt memory 0x%s 0x%s", seta, sets));
ut_assertok(run_commandf("fdt print /memory"));
ut_assert_nextline("memory {");
ut_assert_nextline("\tdevice_type = \"memory\";");
ut_assert_nextline("\treg = <%s %s>;", pada, pads);
ut_assert_nextline("};");
ut_assertok(ut_check_console_end(uts));
free(sets);
free(seta);
free(pads);
free(pada);
free(regs);
return 0;
}
static int fdt_test_memory(struct unit_test_state *uts)
{
/*
* Test memory fixup for 32 and 64 bit systems, anything bigger is
* so far unsupported and fails because of simple_stroull() being
* 64bit tops in the 'fdt memory' command implementation.
*/
fdt_test_memory_cells(uts, 1);
fdt_test_memory_cells(uts, 2);
/*
* The 'fdt memory' command is limited to /memory node, it does
* not support any other valid DT memory node format, which is
* either one or multiple /memory@adresss nodes. Therefore, this
* DT variant is not tested here.
*/
return 0;
}
FDT_TEST(fdt_test_memory, UT_TESTF_CONSOLE_REC);
static int fdt_test_rsvmem(struct unit_test_state *uts)
{
char fdt[8192];
ulong addr;
ut_assertok(make_test_fdt(uts, fdt, sizeof(fdt)));
fdt_shrink_to_minimum(fdt, 4096); /* Resize with 4096 extra bytes */
fdt_add_mem_rsv(fdt, 0x42, 0x1701);
fdt_add_mem_rsv(fdt, 0x74656, 0x9);
addr = map_to_sysmem(fdt);
set_working_fdt_addr(addr);
/* Test default reserved memory node presence */
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt rsvmem print"));
ut_assert_nextline("index\t\t start\t\t size");
ut_assert_nextline("------------------------------------------------");
ut_assert_nextline(" %x\t%016x\t%016x", 0, 0x42, 0x1701);
ut_assert_nextline(" %x\t%016x\t%016x", 1, 0x74656, 0x9);
ut_assertok(ut_check_console_end(uts));
/* Test add new reserved memory node */
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt rsvmem add 0x1234 0x5678"));
ut_assertok(run_commandf("fdt rsvmem print"));
ut_assert_nextline("index\t\t start\t\t size");
ut_assert_nextline("------------------------------------------------");
ut_assert_nextline(" %x\t%016x\t%016x", 0, 0x42, 0x1701);
ut_assert_nextline(" %x\t%016x\t%016x", 1, 0x74656, 0x9);
ut_assert_nextline(" %x\t%016x\t%016x", 2, 0x1234, 0x5678);
ut_assertok(ut_check_console_end(uts));
/* Test delete reserved memory node */
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt rsvmem delete 0"));
ut_assertok(run_commandf("fdt rsvmem print"));
ut_assert_nextline("index\t\t start\t\t size");
ut_assert_nextline("------------------------------------------------");
ut_assert_nextline(" %x\t%016x\t%016x", 0, 0x74656, 0x9);
ut_assert_nextline(" %x\t%016x\t%016x", 1, 0x1234, 0x5678);
ut_assertok(ut_check_console_end(uts));
/* Test re-add new reserved memory node */
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt rsvmem add 0x42 0x1701"));
ut_assertok(run_commandf("fdt rsvmem print"));
ut_assert_nextline("index\t\t start\t\t size");
ut_assert_nextline("------------------------------------------------");
ut_assert_nextline(" %x\t%016x\t%016x", 0, 0x74656, 0x9);
ut_assert_nextline(" %x\t%016x\t%016x", 1, 0x1234, 0x5678);
ut_assert_nextline(" %x\t%016x\t%016x", 2, 0x42, 0x1701);
ut_assertok(ut_check_console_end(uts));
/* Test delete nonexistent reserved memory node */
ut_assertok(console_record_reset_enable());
ut_asserteq(1, run_commandf("fdt rsvmem delete 10"));
ut_assert_nextline("libfdt fdt_del_mem_rsv(): FDT_ERR_NOTFOUND");
ut_assertok(ut_check_console_end(uts));
return 0;
}
FDT_TEST(fdt_test_rsvmem, UT_TESTF_CONSOLE_REC);
static int fdt_test_chosen(struct unit_test_state *uts)
{
const char *env_bootargs = env_get("bootargs");
char fdt[8192];
ulong addr;
ut_assertok(make_test_fdt(uts, fdt, sizeof(fdt)));
fdt_shrink_to_minimum(fdt, 4096); /* Resize with 4096 extra bytes */
addr = map_to_sysmem(fdt);
set_working_fdt_addr(addr);
/* Test default chosen node presence, fail as there is no /chosen node */
ut_assertok(console_record_reset_enable());
ut_asserteq(1, run_commandf("fdt print /chosen"));
ut_assert_nextline("libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND");
ut_assertok(ut_check_console_end(uts));
/* Test add new chosen node without initrd */
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt chosen"));
ut_assertok(run_commandf("fdt print /chosen"));
ut_assert_nextline("chosen {");
ut_assert_nextlinen("\tu-boot,version = "); /* Ignore the version string */
if (env_bootargs)
ut_assert_nextline("\tbootargs = \"%s\";", env_bootargs);
ut_assert_nextline("};");
ut_assertok(ut_check_console_end(uts));
/* Test add new chosen node with initrd */
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt chosen 0x1234 0x5678"));
ut_assertok(run_commandf("fdt print /chosen"));
ut_assert_nextline("chosen {");
ut_assert_nextline("\tlinux,initrd-end = <0x%08x 0x%08x>;",
upper_32_bits(0x1234 + 0x5678 - 1),
lower_32_bits(0x1234 + 0x5678 - 1));
ut_assert_nextline("\tlinux,initrd-start = <0x%08x 0x%08x>;",
upper_32_bits(0x1234), lower_32_bits(0x1234));
ut_assert_nextlinen("\tu-boot,version = "); /* Ignore the version string */
if (env_bootargs)
ut_assert_nextline("\tbootargs = \"%s\";", env_bootargs);
ut_assert_nextline("};");
ut_assertok(ut_check_console_end(uts));
return 0;
}
FDT_TEST(fdt_test_chosen, UT_TESTF_CONSOLE_REC);
static int fdt_test_apply(struct unit_test_state *uts)
{
char fdt[8192], fdto[8192];
ulong addr, addro;
/* Create base DT with __symbols__ node */
ut_assertok(fdt_create(fdt, sizeof(fdt)));
ut_assertok(fdt_finish_reservemap(fdt));
ut_assert(fdt_begin_node(fdt, "") >= 0);
ut_assert(fdt_begin_node(fdt, "__symbols__") >= 0);
ut_assertok(fdt_end_node(fdt));
ut_assertok(fdt_end_node(fdt));
ut_assertok(fdt_finish(fdt));
fdt_shrink_to_minimum(fdt, 4096); /* Resize with 4096 extra bytes */
addr = map_to_sysmem(fdt);
set_working_fdt_addr(addr);
/* Create DTO which adds single property to root node / */
ut_assertok(fdt_create(fdto, sizeof(fdto)));
ut_assertok(fdt_finish_reservemap(fdto));
ut_assert(fdt_begin_node(fdto, "") >= 0);
ut_assert(fdt_begin_node(fdto, "fragment") >= 0);
ut_assertok(fdt_property_string(fdto, "target-path", "/"));
ut_assert(fdt_begin_node(fdto, "__overlay__") >= 0);
ut_assertok(fdt_property_string(fdto, "newstring", "newvalue"));
ut_assertok(fdt_end_node(fdto));
ut_assertok(fdt_end_node(fdto));
ut_assertok(fdt_finish(fdto));
addro = map_to_sysmem(fdto);
/* Test default DT print */
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt print /"));
ut_assert_nextline("/ {");
ut_assert_nextline("\t__symbols__ {");
ut_assert_nextline("\t};");
ut_assert_nextline("};");
ut_assertok(ut_check_console_end(uts));
/* Test simple DTO application */
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt apply 0x%08x", addro));
ut_assertok(run_commandf("fdt print /"));
ut_assert_nextline("/ {");
ut_assert_nextline("\tnewstring = \"newvalue\";");
ut_assert_nextline("\t__symbols__ {");
ut_assert_nextline("\t};");
ut_assert_nextline("};");
ut_assertok(ut_check_console_end(uts));
/*
* Create complex DTO which:
* - modifies newstring property in root node /
* - adds new properties to root node /
* - adds new subnode with properties to root node /
* - adds phandle to the subnode and therefore __symbols__ node
*/
ut_assertok(fdt_create(fdto, sizeof(fdto)));
ut_assertok(fdt_finish_reservemap(fdto));
ut_assert(fdt_begin_node(fdto, "") >= 0);
ut_assertok(fdt_property_cell(fdto, "#address-cells", 1));
ut_assertok(fdt_property_cell(fdto, "#size-cells", 0));
ut_assert(fdt_begin_node(fdto, "fragment@0") >= 0);
ut_assertok(fdt_property_string(fdto, "target-path", "/"));
ut_assert(fdt_begin_node(fdto, "__overlay__") >= 0);
ut_assertok(fdt_property_string(fdto, "newstring", "newervalue"));
ut_assertok(fdt_property_u32(fdto, "newu32", 0x12345678));
ut_assertok(fdt_property(fdto, "empty-property", NULL, 0));
ut_assert(fdt_begin_node(fdto, "subnode") >= 0);
ut_assertok(fdt_property_string(fdto, "subnewstring", "newervalue"));
ut_assertok(fdt_property_u32(fdto, "subnewu32", 0x12345678));
ut_assertok(fdt_property(fdto, "subempty-property", NULL, 0));
ut_assertok(fdt_property_u32(fdto, "phandle", 0x01));
ut_assertok(fdt_end_node(fdto));
ut_assertok(fdt_end_node(fdto));
ut_assertok(fdt_end_node(fdto));
ut_assert(fdt_begin_node(fdto, "__symbols__") >= 0);
ut_assertok(fdt_property_string(fdto, "subnodephandle", "/fragment@0/__overlay__/subnode"));
ut_assertok(fdt_end_node(fdto));
ut_assertok(fdt_finish(fdto));
addro = map_to_sysmem(fdto);
/* Test complex DTO application */
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt apply 0x%08x", addro));
ut_assertok(run_commandf("fdt print /"));
ut_assert_nextline("/ {");
ut_assert_nextline("\tempty-property;");
ut_assert_nextline("\tnewu32 = <0x12345678>;");
ut_assert_nextline("\tnewstring = \"newervalue\";");
ut_assert_nextline("\tsubnode {");
ut_assert_nextline("\t\tphandle = <0x00000001>;");
ut_assert_nextline("\t\tsubempty-property;");
ut_assert_nextline("\t\tsubnewu32 = <0x12345678>;");
ut_assert_nextline("\t\tsubnewstring = \"newervalue\";");
ut_assert_nextline("\t};");
ut_assert_nextline("\t__symbols__ {");
ut_assert_nextline("\t\tsubnodephandle = \"/subnode\";");
ut_assert_nextline("\t};");
ut_assert_nextline("};");
ut_assertok(ut_check_console_end(uts));
/*
* Create complex DTO which:
* - modifies subnewu32 property in subnode via phandle and uses __fixups__ node
*/
ut_assertok(fdt_create(fdto, sizeof(fdto)));
ut_assertok(fdt_finish_reservemap(fdto));
ut_assert(fdt_begin_node(fdto, "") >= 0);
ut_assertok(fdt_property_cell(fdto, "#address-cells", 1));
ut_assertok(fdt_property_cell(fdto, "#size-cells", 0));
ut_assert(fdt_begin_node(fdto, "fragment@0") >= 0);
ut_assertok(fdt_property_u32(fdto, "target", 0xffffffff));
ut_assert(fdt_begin_node(fdto, "__overlay__") >= 0);
ut_assertok(fdt_property_u32(fdto, "subnewu32", 0xabcdef01));
ut_assertok(fdt_end_node(fdto));
ut_assertok(fdt_end_node(fdto));
ut_assert(fdt_begin_node(fdto, "__fixups__") >= 0);
ut_assertok(fdt_property_string(fdto, "subnodephandle", "/fragment@0:target:0"));
ut_assertok(fdt_end_node(fdto));
ut_assertok(fdt_end_node(fdto));
ut_assertok(fdt_finish(fdto));
addro = map_to_sysmem(fdto);
/* Test complex DTO application */
ut_assertok(console_record_reset_enable());
ut_assertok(run_commandf("fdt apply 0x%08x", addro));
ut_assertok(run_commandf("fdt print /"));
ut_assert_nextline("/ {");
ut_assert_nextline("\tempty-property;");
ut_assert_nextline("\tnewu32 = <0x12345678>;");
ut_assert_nextline("\tnewstring = \"newervalue\";");
ut_assert_nextline("\tsubnode {");
ut_assert_nextline("\t\tphandle = <0x00000001>;");
ut_assert_nextline("\t\tsubempty-property;");
ut_assert_nextline("\t\tsubnewu32 = <0xabcdef01>;");
ut_assert_nextline("\t\tsubnewstring = \"newervalue\";");
ut_assert_nextline("\t};");
ut_assert_nextline("\t__symbols__ {");
ut_assert_nextline("\t\tsubnodephandle = \"/subnode\";");
ut_assert_nextline("\t};");
ut_assert_nextline("};");
ut_assertok(ut_check_console_end(uts));
return 0;
}
FDT_TEST(fdt_test_apply, UT_TESTF_CONSOLE_REC);
int do_ut_fdt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
struct unit_test *tests = UNIT_TEST_SUITE_START(fdt_test);

View file

@ -27,11 +27,11 @@ static int dm_test_pwm_cmd(struct unit_test_state *uts)
/* pwm <invert> <pwm_dev_num> <channel> <polarity> */
/* cros-ec-pwm doesn't support invert */
ut_asserteq(1, run_command("pwm invert 0 0 1", 0));
ut_assert_nextline("error(-38)")
ut_assert_nextline("error(-38)");
ut_assert_console_end();
ut_asserteq(1, run_command("pwm invert 0 0 0", 0));
ut_assert_nextline("error(-38)")
ut_assert_nextline("error(-38)");
ut_assert_console_end();
/* pwm <config> <pwm_dev_num> <channel> <period_ns> <duty_ns> */

View file

@ -1083,7 +1083,7 @@ static int dm_test_acpi_write_name(struct unit_test_state *uts)
ut_asserteq(NAME_OP, *ptr++);
ptr += 10;
ut_asserteq(STRING_PREFIX, *ptr++);
ut_asserteq_str("baldrick", (char *)ptr)
ut_asserteq_str("baldrick", (char *)ptr);
ptr += 9;
ut_asserteq(NAME_OP, *ptr++);

View file

@ -51,13 +51,13 @@ static int dm_test_misc(struct unit_test_state *uts)
/* Read back last issued ioctl */
ut_assertok(misc_call(dev, 2, NULL, 0, &last_ioctl,
sizeof(last_ioctl)));
ut_asserteq(6, last_ioctl)
ut_asserteq(6, last_ioctl);
ut_assertok(misc_ioctl(dev, 23, NULL));
/* Read back last issued ioctl */
ut_assertok(misc_call(dev, 2, NULL, 0, &last_ioctl,
sizeof(last_ioctl)));
ut_asserteq(23, last_ioctl)
ut_asserteq(23, last_ioctl);
/* Enable / disable tests */

View file

@ -28,22 +28,22 @@ static int dm_test_phy_base(struct unit_test_state *uts)
/*
* Get the same phy port in 2 different ways and compare.
*/
ut_assertok(generic_phy_get_by_name(parent, "phy1", &phy1_method1))
ut_assertok(generic_phy_get_by_index(parent, 0, &phy1_method2))
ut_assertok(generic_phy_get_by_name(parent, "phy1", &phy1_method1));
ut_assertok(generic_phy_get_by_index(parent, 0, &phy1_method2));
ut_asserteq(phy1_method1.id, phy1_method2.id);
/*
* Get the second phy port. Check that the same phy provider (device)
* provides this 2nd phy port, but that the IDs are different
*/
ut_assertok(generic_phy_get_by_name(parent, "phy2", &phy2))
ut_assertok(generic_phy_get_by_name(parent, "phy2", &phy2));
ut_asserteq_ptr(phy1_method2.dev, phy2.dev);
ut_assert(phy1_method1.id != phy2.id);
/*
* Get the third phy port. Check that the phy provider is different
*/
ut_assertok(generic_phy_get_by_name(parent, "phy3", &phy3))
ut_assertok(generic_phy_get_by_name(parent, "phy3", &phy3));
ut_assert(phy2.dev != phy3.dev);
/* Try to get a non-existing phy */

View file

@ -187,10 +187,10 @@ static int dm_test_scmi_resets(struct unit_test_state *uts)
ut_assertnonnull(agent);
/* Test SCMI resect controller manipulation */
ut_assert(!agent->reset[0].asserted)
ut_assert(!agent->reset[0].asserted);
ut_assertok(reset_assert(&scmi_devices->reset[0]));
ut_assert(agent->reset[0].asserted)
ut_assert(agent->reset[0].asserted);
ut_assertok(reset_deassert(&scmi_devices->reset[0]));
ut_assert(!agent->reset[0].asserted);

View file

@ -15,12 +15,12 @@ static int lib_test_is_enabled(struct unit_test_state *uts)
{
ulong val;
ut_asserteq(1, IS_ENABLED(CONFIG_CMDLINE))
ut_asserteq(0, IS_ENABLED(CONFIG__UNDEFINED))
ut_asserteq(1, IS_ENABLED(CONFIG_CMDLINE));
ut_asserteq(0, IS_ENABLED(CONFIG__UNDEFINED));
ut_asserteq(1, CONFIG_IS_ENABLED(CMDLINE))
ut_asserteq(0, CONFIG_IS_ENABLED(OF_PLATDATA))
ut_asserteq(0, CONFIG_IS_ENABLED(_UNDEFINED))
ut_asserteq(1, CONFIG_IS_ENABLED(CMDLINE));
ut_asserteq(0, CONFIG_IS_ENABLED(OF_PLATDATA));
ut_asserteq(0, CONFIG_IS_ENABLED(_UNDEFINED));
ut_asserteq(0xc000,
IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED, CONFIG_BLOBLIST_ADDR));

View file

@ -15,9 +15,9 @@ static int lib_test_spl_is_enabled(struct unit_test_state *uts)
{
ulong val;
ut_asserteq(0, CONFIG_IS_ENABLED(CMDLINE))
ut_asserteq(1, CONFIG_IS_ENABLED(OF_PLATDATA))
ut_asserteq(0, CONFIG_IS_ENABLED(_UNDEFINED))
ut_asserteq(0, CONFIG_IS_ENABLED(CMDLINE));
ut_asserteq(1, CONFIG_IS_ENABLED(OF_PLATDATA));
ut_asserteq(0, CONFIG_IS_ENABLED(_UNDEFINED));
/*
* This fails if CONFIG_TEST_KCONFIG_ENABLE is not enabled, since the

View file

@ -192,7 +192,7 @@ static int unicode_test_utf8_get(struct unit_test_state *uts)
if (!code)
break;
}
ut_asserteq_ptr(s, d2 + 9)
ut_asserteq_ptr(s, d2 + 9);
/* Check characters less than 0x10000 */
s = d3;
@ -203,7 +203,7 @@ static int unicode_test_utf8_get(struct unit_test_state *uts)
if (!code)
break;
}
ut_asserteq_ptr(s, d3 + 9)
ut_asserteq_ptr(s, d3 + 9);
/* Check character greater 0xffff */
s = d4;
@ -228,7 +228,7 @@ static int unicode_test_utf8_put(struct unit_test_state *uts)
/* Commercial at, translates to one character */
pos = buffer;
ut_assert(!utf8_put('@', &pos))
ut_assert(!utf8_put('@', &pos));
ut_asserteq(1, pos - buffer);
ut_asserteq('@', buffer[0]);
ut_assert(!buffer[1]);

1
tools/.gitignore vendored
View file

@ -6,6 +6,7 @@
/dumpimage
/easylogo/easylogo
/envcrc
/fdt_add_pubkey
/fdtgrep
/file2include
/fit_check_sign

View file

@ -65,6 +65,7 @@ mkenvimage-objs := mkenvimage.o os_support.o lib/crc32.o
hostprogs-y += dumpimage mkimage
hostprogs-$(CONFIG_TOOLS_LIBCRYPTO) += fit_info fit_check_sign
hostprogs-$(CONFIG_TOOLS_LIBCRYPTO) += fdt_add_pubkey
ifneq ($(CONFIG_CMD_BOOTEFI_SELFTEST)$(CONFIG_FWU_MDATA_GPT_BLK),)
hostprogs-y += file2include
@ -150,6 +151,7 @@ dumpimage-objs := $(dumpimage-mkimage-objs) dumpimage.o
mkimage-objs := $(dumpimage-mkimage-objs) mkimage.o
fit_info-objs := $(dumpimage-mkimage-objs) fit_info.o
fit_check_sign-objs := $(dumpimage-mkimage-objs) fit_check_sign.o
fdt_add_pubkey-objs := $(dumpimage-mkimage-objs) fdt_add_pubkey.o
file2include-objs := file2include.o
ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_TOOLS_LIBCRYPTO),)
@ -187,6 +189,7 @@ HOSTCFLAGS_fit_image.o += -DMKIMAGE_DTC=\"$(CONFIG_MKIMAGE_DTC_PATH)\"
HOSTLDLIBS_dumpimage := $(HOSTLDLIBS_mkimage)
HOSTLDLIBS_fit_info := $(HOSTLDLIBS_mkimage)
HOSTLDLIBS_fit_check_sign := $(HOSTLDLIBS_mkimage)
HOSTLDLIBS_fdt_add_pubkey := $(HOSTLDLIBS_mkimage)
hostprogs-$(CONFIG_EXYNOS5250) += mkexynosspl
hostprogs-$(CONFIG_EXYNOS5420) += mkexynosspl

View file

@ -1366,6 +1366,24 @@ when it was created.
.. _`BinmanLogging`:
Signing FIT container with private key in an image
--------------------------------------------------
You can sign FIT container with private key in your image.
For example::
$ binman sign -i image.bin -k privatekey -a sha256,rsa4096 fit
binman will extract FIT container, sign and replace it immediately.
If you want to sign and replace FIT container in place::
$ binman sign -i image.bin -k privatekey -a sha256,rsa4096 -f fit.fit fit
which will sign FIT container with private key and replace it immediately
inside your image.
Logging
-------
@ -1751,6 +1769,35 @@ Options:
output directory if a single test is run (pass test name at the end of the
command line
binman sign
-----------
Usage::
binman sign [-h] -a ALGO [-f FILE] -i IMAGE -k KEY [paths ...]
positional arguments:
paths
Paths within file to sign (wildcard)
options:
-h, --help
show this help message and exit
-a ALGO, --algo ALGO
Hash algorithm e.g. sha256,rsa4096
-f FILE, --file FILE
Input filename to sign
-i IMAGE, --image IMAGE
Image filename to update
-k KEY, --key KEY
Private key file for signing
binman tool
-----------

View file

@ -176,6 +176,19 @@ controlled by a description in the board device tree.'''
replace_parser.add_argument('paths', type=str, nargs='*',
help='Paths within file to replace (wildcard)')
sign_parser = subparsers.add_parser('sign',
help='Sign entries in image')
sign_parser.add_argument('-a', '--algo', type=str, required=True,
help='Hash algorithm e.g. sha256,rsa4096')
sign_parser.add_argument('-f', '--file', type=str, required=False,
help='Input filename to sign')
sign_parser.add_argument('-i', '--image', type=str, required=True,
help='Image filename to update')
sign_parser.add_argument('-k', '--key', type=str, required=True,
help='Private key file for signing')
sign_parser.add_argument('paths', type=str, nargs='*',
help='Paths within file to sign (wildcard)')
if HAS_TESTS:
test_parser = subparsers.add_parser('test', help='Run tests')
test_parser.add_argument('-P', '--processes', type=int,

View file

@ -448,6 +448,31 @@ def ReplaceEntries(image_fname, input_fname, indir, entry_paths,
AfterReplace(image, allow_resize=allow_resize, write_map=write_map)
return image
def SignEntries(image_fname, input_fname, privatekey_fname, algo, entry_paths,
write_map=False):
"""Sign and replace the data from one or more entries from input files
Args:
image_fname: Image filename to process
input_fname: Single input filename to use if replacing one file, None
otherwise
algo: Hashing algorithm
entry_paths: List of entry paths to sign
privatekey_fname: Private key filename
write_map (bool): True to write the map file
"""
image_fname = os.path.abspath(image_fname)
image = Image.FromFile(image_fname)
image.mark_build_done()
BeforeReplace(image, allow_resize=True)
for entry_path in entry_paths:
entry = image.FindEntryPath(entry_path)
entry.UpdateSignatures(privatekey_fname, algo, input_fname)
AfterReplace(image, allow_resize=True, write_map=write_map)
def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt, use_expanded):
"""Prepare the images to be processed and select the device tree
@ -660,7 +685,7 @@ def Binman(args):
tools.set_tool_paths(tool_paths or None)
bintool.Bintool.set_tool_dir(args.tooldir)
if args.cmd in ['ls', 'extract', 'replace', 'tool']:
if args.cmd in ['ls', 'extract', 'replace', 'tool', 'sign']:
try:
tout.init(args.verbosity)
if args.cmd == 'replace':
@ -679,6 +704,9 @@ def Binman(args):
do_compress=not args.compressed,
allow_resize=not args.fix_size, write_map=args.map)
if args.cmd == 'sign':
SignEntries(args.image, args.file, args.key, args.algo, args.paths)
if args.cmd == 'tool':
if args.list:
bintool.Bintool.list_all()

View file

@ -1378,3 +1378,6 @@ features to produce new behaviours.
if entries:
for entry in entries.values():
entry.mark_build_done()
def UpdateSignatures(self, privatekey_fname, algo, input_fname):
self.Raise('Updating signatures is not supported with this entry type')

View file

@ -835,3 +835,19 @@ class Entry_fit(Entry_section):
def CheckEntries(self):
pass
def UpdateSignatures(self, privatekey_fname, algo, input_fname):
uniq = self.GetUniqueName()
args = [ '-G', privatekey_fname, '-r', '-o', algo, '-F' ]
if input_fname:
fname = input_fname
else:
fname = tools.get_output_filename('%s.fit' % uniq)
tools.write_file(fname, self.GetData())
args.append(fname)
if self.mkimage.run_cmd(*args) is None:
self.Raise("Missing tool: 'mkimage'")
data = tools.read_file(fname)
self.WriteData(data)

View file

@ -709,6 +709,14 @@ class TestFunctional(unittest.TestCase):
AddNode(dtb.GetRoot(), '')
return tree
def _CheckSign(self, fit, key):
try:
tools.run('fit_check_sign', '-k', key, '-f', fit)
except:
self.fail('Expected signed FIT container')
return False
return True
def testRun(self):
"""Test a basic run with valid args"""
result = self._RunBinman('-h')
@ -6583,6 +6591,91 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
self._DoTestFile('278_mkimage_missing_multiple.dts', allow_missing=False)
self.assertIn("not found in input path", str(e.exception))
def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
"""Prepare sign environment
Create private and public keys, add pubkey into dtb.
Returns:
Tuple:
FIT container
Image name
Private key
DTB
"""
data = self._DoReadFileRealDtb(dts)
updated_fname = tools.get_output_filename('image-updated.bin')
tools.write_file(updated_fname, data)
dtb = tools.get_output_filename('source.dtb')
private_key = tools.get_output_filename('test_key.key')
public_key = tools.get_output_filename('test_key.crt')
fit = tools.get_output_filename('fit.fit')
key_dir = tools.get_output_dir()
tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
'-sha256', '-new', '-nodes', '-x509', '-keyout',
private_key, '-out', public_key)
tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
'-n', 'test_key', '-r', 'conf', dtb)
return fit, updated_fname, private_key, dtb
def testSignSimple(self):
"""Test that a FIT container can be signed in image"""
is_signed = False
fit, fname, private_key, dtb = self._PrepareSignEnv()
# do sign with private key
control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
['fit'])
is_signed = self._CheckSign(fit, dtb)
self.assertEqual(is_signed, True)
def testSignExactFIT(self):
"""Test that a FIT container can be signed and replaced in image"""
is_signed = False
fit, fname, private_key, dtb = self._PrepareSignEnv()
# Make sure we propagate the toolpath, since mkimage may not be on PATH
args = []
if self.toolpath:
for path in self.toolpath:
args += ['--toolpath', path]
# do sign with private key
self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
'sha256,rsa4096', '-f', fit, 'fit')
is_signed = self._CheckSign(fit, dtb)
self.assertEqual(is_signed, True)
def testSignNonFit(self):
"""Test a non-FIT entry cannot be signed"""
is_signed = False
fit, fname, private_key, _ = self._PrepareSignEnv(
'281_sign_non_fit.dts')
# do sign with private key
with self.assertRaises(ValueError) as e:
self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
'sha256,rsa4096', '-f', fit, 'u-boot')
self.assertIn(
"Node '/u-boot': Updating signatures is not supported with this entry type",
str(e.exception))
def testSignMissingMkimage(self):
"""Test that FIT signing handles a missing mkimage tool"""
fit, fname, private_key, _ = self._PrepareSignEnv()
# try to sign with a missing mkimage tool
bintool.Bintool.set_missing_list(['mkimage'])
with self.assertRaises(ValueError) as e:
control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
['fit'])
self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
if __name__ == "__main__":
unittest.main()

View file

@ -0,0 +1,63 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
size = <0x100000>;
allow-repack;
fit {
description = "U-Boot";
offset = <0x10000>;
images {
u-boot-1 {
description = "U-Boot";
type = "standalone";
arch = "arm64";
os = "u-boot";
compression = "none";
hash-1 {
algo = "sha256";
};
u-boot {
};
};
fdt-1 {
description = "test.dtb";
type = "flat_dt";
arch = "arm64";
compression = "none";
hash-1 {
algo = "sha256";
};
u-boot-spl-dtb {
};
};
};
configurations {
default = "conf-1";
conf-1 {
description = "u-boot with fdt";
firmware = "u-boot-1";
fdt = "fdt-1";
signature-1 {
algo = "sha256,rsa4096";
key-name-hint = "test_key";
sign-images = "firmware", "fdt";
};
};
};
};
fdtmap {
};
};
};

View file

@ -0,0 +1,65 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
size = <0x100000>;
allow-repack;
u-boot {
};
fit {
description = "U-Boot";
offset = <0x10000>;
images {
u-boot-1 {
description = "U-Boot";
type = "standalone";
arch = "arm64";
os = "u-boot";
compression = "none";
hash-1 {
algo = "sha256";
};
u-boot {
};
};
fdt-1 {
description = "test.dtb";
type = "flat_dt";
arch = "arm64";
compression = "none";
hash-1 {
algo = "sha256";
};
u-boot-spl-dtb {
};
};
};
configurations {
default = "conf-1";
conf-1 {
description = "u-boot with fdt";
firmware = "u-boot-1";
fdt = "fdt-1";
signature-1 {
algo = "sha256,rsa4096";
key-name-hint = "test_key";
sign-images = "firmware", "fdt";
};
};
};
};
fdtmap {
};
};
};

View file

@ -157,7 +157,9 @@ class Toolchain:
Value of that environment variable or arguments
"""
if which == VAR_CROSS_COMPILE:
return self.GetWrapper() + self.cross
wrapper = self.GetWrapper()
base = '' if self.arch == 'sandbox' else self.path
return wrapper + os.path.join(base, self.cross)
elif which == VAR_PATH:
return self.path
elif which == VAR_ARCH:

138
tools/fdt_add_pubkey.c Normal file
View file

@ -0,0 +1,138 @@
// SPDX-License-Identifier: GPL-2.0+
#include <image.h>
#include "fit_common.h"
static const char *cmdname;
static const char *algo_name = "sha1,rsa2048"; /* -a <algo> */
static const char *keydir = "."; /* -k <keydir> */
static const char *keyname = "key"; /* -n <keyname> */
static const char *require_keys; /* -r <conf|image> */
static const char *keydest; /* argv[n] */
static void print_usage(const char *msg)
{
fprintf(stderr, "Error: %s\n", msg);
fprintf(stderr, "Usage: %s [-a <algo>] [-k <keydir>] [-n <keyname>] [-r <conf|image>]"
" <fdt blob>\n", cmdname);
fprintf(stderr, "Help information: %s [-h]\n", cmdname);
exit(EXIT_FAILURE);
}
static void print_help(void)
{
fprintf(stderr, "Options:\n"
"\t-a <algo> Cryptographic algorithm. Optional parameter, default value: sha1,rsa2048\n"
"\t-k <keydir> Directory with public key. Optional parameter, default value: .\n"
"\t-n <keyname> Public key name. Optional parameter, default value: key\n"
"\t-r <conf|image> Required: If present this indicates that the key must be verified for the image / configuration to be considered valid.\n"
"\t<fdt blob> FDT blob file for adding of the public key. Required parameter.\n");
exit(EXIT_FAILURE);
}
static void process_args(int argc, char *argv[])
{
int opt;
while ((opt = getopt(argc, argv, "a:k:n:r:h")) != -1) {
switch (opt) {
case 'k':
keydir = optarg;
break;
case 'a':
algo_name = optarg;
break;
case 'n':
keyname = optarg;
break;
case 'r':
require_keys = optarg;
break;
case 'h':
print_help();
default:
print_usage("Invalid option");
}
}
/* The last parameter is expected to be the .dtb to add the public key to */
if (optind < argc)
keydest = argv[optind];
if (!keydest)
print_usage("Missing dtb file to update");
}
static void reset_info(struct image_sign_info *info)
{
if (!info)
fprintf(stderr, "Error: info is NULL in %s\n", __func__);
memset(info, 0, sizeof(struct image_sign_info));
info->keydir = keydir;
info->keyname = keyname;
info->name = algo_name;
info->require_keys = require_keys;
info->crypto = image_get_crypto_algo(algo_name);
if (!info->crypto) {
fprintf(stderr, "Unsupported signature algorithm '%s'\n",
algo_name);
exit(EXIT_FAILURE);
}
}
static int add_pubkey(struct image_sign_info *info)
{
int destfd = -1, ret;
void *dest_blob = NULL;
struct stat dest_sbuf;
size_t size_inc = 0;
if (!info)
fprintf(stderr, "Error: info is NULL in %s\n", __func__);
do {
if (destfd >= 0) {
munmap(dest_blob, dest_sbuf.st_size);
close(destfd);
fprintf(stderr, ".dtb too small, increasing size by 1024 bytes\n");
size_inc = 1024;
}
destfd = mmap_fdt(cmdname, keydest, size_inc, &dest_blob,
&dest_sbuf, false, false);
if (destfd < 0)
exit(EXIT_FAILURE);
ret = info->crypto->add_verify_data(info, dest_blob);
if (ret == -ENOSPC)
continue;
else if (ret < 0)
break;
} while (ret == -ENOSPC);
return ret;
}
int main(int argc, char *argv[])
{
struct image_sign_info info;
int ret;
cmdname = argv[0];
process_args(argc, argv);
reset_info(&info);
ret = add_pubkey(&info);
if (ret < 0) {
fprintf(stderr, "%s: Cannot add public key to FIT blob: %s\n",
cmdname, strerror(ret));
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}