mkimage: Add support for bundling TFA BL31 in mkimage -f auto

Introduce two new parameters to be used with mkimage -f auto to bundle
TFA BL31 image into fitImage, using auto-generated fitImage. Add -y to
specify TFA BL31 file name and -Y to specify TFA BL31 load and entry
point address. This is meant to be used with systems which boot all of
TFA BL31, Linux and its DT from a single fitImage, all booted by U-Boot.

Example invocation:
"
$ mkimage -E -A arm64 -C none -e 0x50200000 -a 0x50200000 -f auto \
          -d arch/arm64/boot/Image \
	  -b arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dtb \
	  -y ../tfa/build/rcar_gen4/release/bl31.bin -Y 0x46400000 \
	  /path/to/output/fitImage
"

Documentation update and test are also included, the test validates
both positive and negative test cases, where fitImage does not include
TFA BL31 and does include TFA BL31 blobs.

Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
This commit is contained in:
Marek Vasut
2025-09-03 00:01:55 +02:00
committed by Tom Rini
parent 559f11e66c
commit 6dfd14e122
6 changed files with 146 additions and 3 deletions

View File

@@ -239,6 +239,18 @@ Set the
command will not load the image data, and instead will assume it is already command will not load the image data, and instead will assume it is already
accessible at the load address (such as via memory-mapped flash). accessible at the load address (such as via memory-mapped flash).
. .
.TP
.B \-y
.TQ
.B \-\-tfa-bl31-file
Append TFA BL31 file to the image.
.
.TP
.B \-Y
.TQ
.B \-\-tfa-bl31-addr
Set TFA BL31 file load and entry point address.
.
.SS Options for creating FIT images .SS Options for creating FIT images
. .
.TP .TP

View File

@@ -1104,6 +1104,7 @@ int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
#define FIT_STANDALONE_PROP "standalone" #define FIT_STANDALONE_PROP "standalone"
#define FIT_SCRIPT_PROP "script" #define FIT_SCRIPT_PROP "script"
#define FIT_PHASE_PROP "phase" #define FIT_PHASE_PROP "phase"
#define FIT_TFA_BL31_PROP "tfa-bl31"
#define FIT_MAX_HASH_LEN HASH_MAX_DIGEST_SIZE #define FIT_MAX_HASH_LEN HASH_MAX_DIGEST_SIZE

View File

@@ -117,6 +117,23 @@ class SignedFitHelper(object):
algo = self.__fdt_get_string(f'{node}/signature', 'algo') algo = self.__fdt_get_string(f'{node}/signature', 'algo')
assert algo == sign_algo + "\n", "Missing expected signature algo!" assert algo == sign_algo + "\n", "Missing expected signature algo!"
def check_fit_loadables(self, present):
"""Test that loadables contains both kernel and TFA BL31 entries.
Each configuration must have a loadables property which lists both
kernel-1 and tfa-bl31-1 strings in the string list.
"""
if present:
assert "/images/tfa-bl31-1" in self.images_nodes
else:
assert "/images/tfa-bl31-1" not in self.images_nodes
for node in self.confgs_nodes:
loadables = self.__fdt_get_string(f'{node}', 'loadables')
assert "kernel-1" in loadables
if present:
assert "tfa-bl31-1" in loadables
else:
assert "tfa-bl31-1" not in loadables
@pytest.mark.buildconfigspec('fit_signature') @pytest.mark.buildconfigspec('fit_signature')
@pytest.mark.requiredtool('fdtget') @pytest.mark.requiredtool('fdtget')
@@ -139,6 +156,7 @@ def test_fit_auto_signed(ubman):
kernel_file = f'{tempdir}/vmlinuz' kernel_file = f'{tempdir}/vmlinuz'
dt1_file = f'{tempdir}/dt-1.dtb' dt1_file = f'{tempdir}/dt-1.dtb'
dt2_file = f'{tempdir}/dt-2.dtb' dt2_file = f'{tempdir}/dt-2.dtb'
tfa_file = f'{tempdir}/tfa-bl31.bin'
key_name = 'sign-key' key_name = 'sign-key'
sign_algo = 'sha256,rsa4096' sign_algo = 'sha256,rsa4096'
key_file = f'{tempdir}/{key_name}.key' key_file = f'{tempdir}/{key_name}.key'
@@ -154,6 +172,9 @@ def test_fit_auto_signed(ubman):
with open(dt2_file, 'wb') as fd: with open(dt2_file, 'wb') as fd:
fd.write(os.urandom(256)) fd.write(os.urandom(256))
with open(tfa_file, 'wb') as fd:
fd.write(os.urandom(256))
# Create 4096 RSA key and write to file to be read by mkimage # Create 4096 RSA key and write to file to be read by mkimage
key = RSA.generate(bits=4096) key = RSA.generate(bits=4096)
verifier = pkcs1_15.new(key) verifier = pkcs1_15.new(key)
@@ -173,6 +194,8 @@ def test_fit_auto_signed(ubman):
fit.check_fit_crc32_images() fit.check_fit_crc32_images()
fit.check_fit_loadables(present=False)
# 2 - Create auto FIT with signed images, and verify it # 2 - Create auto FIT with signed images, and verify it
utils.run_and_log(ubman, mkimage + ' -fauto' + b_args + s_args + " " + utils.run_and_log(ubman, mkimage + ' -fauto' + b_args + s_args + " " +
fit_file) fit_file)
@@ -183,6 +206,8 @@ def test_fit_auto_signed(ubman):
fit.check_fit_signed_images(key_name, sign_algo, verifier) fit.check_fit_signed_images(key_name, sign_algo, verifier)
fit.check_fit_loadables(present=False)
# 3 - Create auto FIT with signed configs and hashed images, and verify it # 3 - Create auto FIT with signed configs and hashed images, and verify it
utils.run_and_log(ubman, mkimage + ' -fauto-conf' + b_args + s_args + " " + utils.run_and_log(ubman, mkimage + ' -fauto-conf' + b_args + s_args + " " +
fit_file) fit_file)
@@ -192,3 +217,45 @@ def test_fit_auto_signed(ubman):
raise ValueError('FIT-3 has no "/image" nor "/configuration" nodes') raise ValueError('FIT-3 has no "/image" nor "/configuration" nodes')
fit.check_fit_signed_confgs(key_name, sign_algo) fit.check_fit_signed_confgs(key_name, sign_algo)
fit.check_fit_loadables(present=False)
# Run the same tests as 1/2/3 above, but this time with TFA BL31
# options -y tfa-bl31.bin -Y 0x12340000 to cover both mkimage with
# and without TFA BL31 use cases.
b_args = " -d" + kernel_file + " -b" + dt1_file + " -b" + dt2_file + " -y" + tfa_file + " -Y 0x12340000"
# 4 - Create auto FIT with images crc32 checksum, and verify it
utils.run_and_log(ubman, mkimage + ' -fauto' + b_args + " " + fit_file)
fit = SignedFitHelper(ubman, fit_file)
if fit.build_nodes_sets() == 0:
raise ValueError('FIT-4 has no "/image" nor "/configuration" nodes')
fit.check_fit_crc32_images()
fit.check_fit_loadables(present=True)
# 5 - Create auto FIT with signed images, and verify it
utils.run_and_log(ubman, mkimage + ' -fauto' + b_args + s_args + " " +
fit_file)
fit = SignedFitHelper(ubman, fit_file)
if fit.build_nodes_sets() == 0:
raise ValueError('FIT-5 has no "/image" nor "/configuration" nodes')
fit.check_fit_signed_images(key_name, sign_algo, verifier)
fit.check_fit_loadables(present=True)
# 6 - Create auto FIT with signed configs and hashed images, and verify it
utils.run_and_log(ubman, mkimage + ' -fauto-conf' + b_args + s_args + " " +
fit_file)
fit = SignedFitHelper(ubman, fit_file)
if fit.build_nodes_sets() == 0:
raise ValueError('FIT-6 has no "/image" nor "/configuration" nodes')
fit.check_fit_signed_confgs(key_name, sign_algo)
fit.check_fit_loadables(present=True)

View File

@@ -173,6 +173,13 @@ static int fit_calc_size(struct image_tool_params *params)
total_size += size; total_size += size;
} }
if (params->fit_tfa_bl31) {
size = imagetool_get_filesize(params, params->fit_tfa_bl31);
if (size < 0)
return -1;
total_size += size;
}
for (cont = params->content_head; cont; cont = cont->next) { for (cont = params->content_head; cont; cont = cont->next) {
size = imagetool_get_filesize(params, cont->fname); size = imagetool_get_filesize(params, cont->fname);
if (size < 0) if (size < 0)
@@ -402,6 +409,30 @@ static int fit_write_images(struct image_tool_params *params, char *fdt)
fdt_end_node(fdt); fdt_end_node(fdt);
} }
/* And a TFA BL31 file if available */
if (params->fit_tfa_bl31) {
fdt_begin_node(fdt, FIT_TFA_BL31_PROP "-1");
fdt_property_string(fdt, FIT_TYPE_PROP, FIT_TFA_BL31_PROP);
fdt_property_string(fdt, FIT_OS_PROP,
genimg_get_os_short_name(params->os));
fdt_property_string(fdt, FIT_ARCH_PROP,
genimg_get_arch_short_name(params->arch));
get_basename(str, sizeof(str), params->fit_tfa_bl31);
fdt_property_string(fdt, FIT_DESC_PROP, str);
ret = fdt_property_file(params, fdt, FIT_DATA_PROP,
params->fit_tfa_bl31);
if (ret)
return ret;
fdt_property_u32(fdt, FIT_LOAD_PROP, params->fit_tfa_bl31_addr);
fdt_property_u32(fdt, FIT_ENTRY_PROP, params->fit_tfa_bl31_addr);
fit_add_hash_or_sign(params, fdt, true);
if (ret)
return ret;
fdt_end_node(fdt);
}
fdt_end_node(fdt); fdt_end_node(fdt);
return 0; return 0;
@@ -421,7 +452,7 @@ static void fit_write_configs(struct image_tool_params *params, char *fdt)
struct content_info *cont; struct content_info *cont;
const char *typename; const char *typename;
char str[100]; char str[100];
int upto; int upto, len;
fdt_begin_node(fdt, "configurations"); fdt_begin_node(fdt, "configurations");
fdt_property_string(fdt, FIT_DEFAULT_PROP, "conf-1"); fdt_property_string(fdt, FIT_DEFAULT_PROP, "conf-1");
@@ -439,8 +470,16 @@ static void fit_write_configs(struct image_tool_params *params, char *fdt)
typename = genimg_get_type_short_name(params->fit_image_type); typename = genimg_get_type_short_name(params->fit_image_type);
snprintf(str, sizeof(str), "%s-1", typename); snprintf(str, sizeof(str), "%s-1", typename);
len = strlen(str);
fdt_property_string(fdt, typename, str); fdt_property_string(fdt, typename, str);
fdt_property_string(fdt, FIT_LOADABLE_PROP, str);
if (params->fit_tfa_bl31) {
snprintf(str, sizeof(str), "%s-1." FIT_TFA_BL31_PROP "-1", typename);
str[len] = 0;
len += strlen(FIT_TFA_BL31_PROP "-1") + 1;
}
fdt_property(fdt, FIT_LOADABLE_PROP, str, len + 1);
if (params->fit_ramdisk) if (params->fit_ramdisk)
fdt_property_string(fdt, FIT_RAMDISK_PROP, fdt_property_string(fdt, FIT_RAMDISK_PROP,
@@ -456,8 +495,17 @@ static void fit_write_configs(struct image_tool_params *params, char *fdt)
fdt_begin_node(fdt, "conf-1"); fdt_begin_node(fdt, "conf-1");
typename = genimg_get_type_short_name(params->fit_image_type); typename = genimg_get_type_short_name(params->fit_image_type);
snprintf(str, sizeof(str), "%s-1", typename); snprintf(str, sizeof(str), "%s-1", typename);
len = strlen(str);
fdt_property_string(fdt, typename, str); fdt_property_string(fdt, typename, str);
if (params->fit_tfa_bl31) {
snprintf(str, sizeof(str), "%s-1." FIT_TFA_BL31_PROP "-1", typename);
str[len] = 0;
len += strlen(FIT_TFA_BL31_PROP "-1") + 1;
}
fdt_property(fdt, FIT_LOADABLE_PROP, str, len + 1);
if (params->fit_ramdisk) if (params->fit_ramdisk)
fdt_property_string(fdt, FIT_RAMDISK_PROP, fdt_property_string(fdt, FIT_RAMDISK_PROP,
FIT_RAMDISK_PROP "-1"); FIT_RAMDISK_PROP "-1");

View File

@@ -99,6 +99,8 @@ struct image_tool_params {
const char *engine_id; /* Engine to use for signing */ const char *engine_id; /* Engine to use for signing */
bool reset_timestamp; /* Reset the timestamp on an existing image */ bool reset_timestamp; /* Reset the timestamp on an existing image */
struct image_summary summary; /* results of signing process */ struct image_summary summary; /* results of signing process */
char *fit_tfa_bl31; /* TFA BL31 file to include */
unsigned int fit_tfa_bl31_addr; /* TFA BL31 load and entry point address */
}; };
/* /*

View File

@@ -160,7 +160,7 @@ static int add_content(int type, const char *fname)
} }
static const char optstring[] = static const char optstring[] =
"a:A:b:B:c:C:d:D:e:Ef:Fg:G:i:k:K:ln:N:o:O:p:qrR:stT:vVx"; "a:A:b:B:c:C:d:D:e:Ef:Fg:G:i:k:K:ln:N:o:O:p:qrR:stT:vVxy:Y:";
static const struct option longopts[] = { static const struct option longopts[] = {
{ "load-address", required_argument, NULL, 'a' }, { "load-address", required_argument, NULL, 'a' },
@@ -196,6 +196,8 @@ static const struct option longopts[] = {
{ "verbose", no_argument, NULL, 'v' }, { "verbose", no_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'V' }, { "version", no_argument, NULL, 'V' },
{ "xip", no_argument, NULL, 'x' }, { "xip", no_argument, NULL, 'x' },
{ "tfa-bl31-file", no_argument, NULL, 'y' },
{ "tfa-bl31-addr", no_argument, NULL, 'Y' },
{ /* sentinel */ }, { /* sentinel */ },
}; };
@@ -367,6 +369,17 @@ static void process_args(int argc, char **argv)
case 'x': case 'x':
params.xflag++; params.xflag++;
break; break;
case 'y':
params.fit_tfa_bl31 = optarg;
break;
case 'Y':
params.fit_tfa_bl31_addr = strtoull(optarg, &ptr, 16);
if (*ptr) {
fprintf(stderr, "%s: invalid TFA BL31 address %s\n",
params.cmdname, optarg);
exit(EXIT_FAILURE);
}
break;
default: default:
usage("Invalid option"); usage("Invalid option");
} }