diff options
| author | Jamin Lin <jamin_lin@aspeedtech.com> | 2025-02-17 16:52:33 +0800 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2025-02-27 10:55:17 +0000 |
| commit | 0247289464b1b08e486b8358005e080926a0175e (patch) | |
| tree | 9836087909de0dc42707004ce9d5d8844c1d9bee /meta/lib | |
| parent | 7be7e16cbb26f87ed1fda853c037265c0cbb00a3 (diff) | |
| download | poky-0247289464b1b08e486b8358005e080926a0175e.tar.gz | |
oe-selftest: fitimage: add testcases to test ATF and TEE
Add "test_uboot_atf_tee_fit_image" test caste to check u-boot FIT image and
Image Tree Source(ITS) are built and the ITS has the correct fields.
Add "test_sign_standalone_uboot_atf_tee_fit_image" test case to check if u-boot
FIT image and Image Tree Source (ITS) are created and signed correctly for the
scenario where only the u-boot proper fitImage is being created and signed.
Currently, ATF and TEE(optee-os) recipes are placed in meta-arm layer.
OpenEmbedded-Core is a basic and core meta layer. To avoid OpenEmbedded-core
depends meta-arm, both test cases are used dummy images for testing.
(From OE-Core rev: 92e51452f8831f74e0907b960135eef8cecd012a)
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Signed-off-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/lib')
| -rw-r--r-- | meta/lib/oeqa/selftest/cases/fitimage.py | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/meta/lib/oeqa/selftest/cases/fitimage.py b/meta/lib/oeqa/selftest/cases/fitimage.py index 5a400c200f..5af9ea8afc 100644 --- a/meta/lib/oeqa/selftest/cases/fitimage.py +++ b/meta/lib/oeqa/selftest/cases/fitimage.py | |||
| @@ -894,3 +894,284 @@ FIT_HASH_ALG = "sha256" | |||
| 894 | # Check if the u-boot boot.scr script is in the fitImage | 894 | # Check if the u-boot boot.scr script is in the fitImage |
| 895 | dumpimage_result = self._run_dumpimage(fitimage_path, uboot_tools_bindir) | 895 | dumpimage_result = self._run_dumpimage(fitimage_path, uboot_tools_bindir) |
| 896 | self._verify_fitimage_uboot_env(dumpimage_result) | 896 | self._verify_fitimage_uboot_env(dumpimage_result) |
| 897 | |||
| 898 | |||
| 899 | def test_uboot_atf_tee_fit_image(self): | ||
| 900 | """ | ||
| 901 | Summary: Check if U-boot FIT image and Image Tree Source | ||
| 902 | (its) are built and the Image Tree Source has the | ||
| 903 | correct fields. | ||
| 904 | Expected: 1. Create atf and tee dummy images | ||
| 905 | 2. Both u-boot-fitImage and u-boot-its can be built | ||
| 906 | 3. The os, load address, entrypoint address and | ||
| 907 | default values of U-boot, ATF and TEE images are | ||
| 908 | correct in the Image Tree Source. Not all the | ||
| 909 | fields are tested, only the key fields that wont | ||
| 910 | vary between different architectures. | ||
| 911 | Product: oe-core | ||
| 912 | Author: Jamin Lin <jamin_lin@aspeedtech.com> | ||
| 913 | """ | ||
| 914 | config = """ | ||
| 915 | # We need at least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set | ||
| 916 | MACHINE = "qemuarm" | ||
| 917 | UBOOT_MACHINE = "am57xx_evm_defconfig" | ||
| 918 | SPL_BINARY = "MLO" | ||
| 919 | |||
| 920 | # Enable creation of the U-Boot fitImage | ||
| 921 | UBOOT_FITIMAGE_ENABLE = "1" | ||
| 922 | |||
| 923 | # (U-boot) fitImage properties | ||
| 924 | UBOOT_LOADADDRESS = "0x80080000" | ||
| 925 | UBOOT_ENTRYPOINT = "0x80080000" | ||
| 926 | UBOOT_FIT_DESC = "A model description" | ||
| 927 | |||
| 928 | # Enable creation of the TEE fitImage | ||
| 929 | UBOOT_FIT_TEE = "1" | ||
| 930 | |||
| 931 | # TEE fitImage properties | ||
| 932 | UBOOT_FIT_TEE_IMAGE = "${TOPDIR}/tee-dummy.bin" | ||
| 933 | UBOOT_FIT_TEE_LOADADDRESS = "0x80180000" | ||
| 934 | UBOOT_FIT_TEE_ENTRYPOINT = "0x80180000" | ||
| 935 | |||
| 936 | # Enable creation of the ATF fitImage | ||
| 937 | UBOOT_FIT_ARM_TRUSTED_FIRMWARE = "1" | ||
| 938 | |||
| 939 | # ATF fitImage properties | ||
| 940 | UBOOT_FIT_ARM_TRUSTED_FIRMWARE_IMAGE = "${TOPDIR}/atf-dummy.bin" | ||
| 941 | UBOOT_FIT_ARM_TRUSTED_FIRMWARE_LOADADDRESS = "0x80280000" | ||
| 942 | UBOOT_FIT_ARM_TRUSTED_FIRMWARE_ENTRYPOINT = "0x80280000" | ||
| 943 | """ | ||
| 944 | self.write_config(config) | ||
| 945 | |||
| 946 | # Create an ATF dummy image | ||
| 947 | atf_dummy_image = os.path.join(self.builddir, "atf-dummy.bin") | ||
| 948 | cmd = 'dd if=/dev/random of=%s bs=1k count=64' % (atf_dummy_image) | ||
| 949 | result = runCmd(cmd) | ||
| 950 | self.logger.debug("%s\nreturned: %s\n%s", cmd, str(result.status), result.output) | ||
| 951 | |||
| 952 | # Create a TEE dummy image | ||
| 953 | tee_dummy_image = os.path.join(self.builddir, "tee-dummy.bin") | ||
| 954 | cmd = 'dd if=/dev/random of=%s bs=1k count=64' % (tee_dummy_image) | ||
| 955 | result = runCmd(cmd) | ||
| 956 | self.logger.debug("%s\nreturned: %s\n%s", cmd, str(result.status), result.output) | ||
| 957 | |||
| 958 | # The U-Boot fitImage is created as part of the U-Boot recipe | ||
| 959 | bitbake("virtual/bootloader") | ||
| 960 | |||
| 961 | deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') | ||
| 962 | machine = get_bb_var('MACHINE') | ||
| 963 | fitimage_its_path = os.path.join(deploy_dir_image, | ||
| 964 | "u-boot-its-%s" % (machine,)) | ||
| 965 | fitimage_path = os.path.join(deploy_dir_image, | ||
| 966 | "u-boot-fitImage-%s" % (machine,)) | ||
| 967 | |||
| 968 | self.assertExists(fitimage_its_path, "%s image tree source doesn't exist" % (fitimage_its_path)) | ||
| 969 | self.assertExists(fitimage_path, "%s FIT image doesn't exist" % (fitimage_path)) | ||
| 970 | |||
| 971 | # Check that the type, load address, entrypoint address and default | ||
| 972 | # values for u-boot, ATF and TEE in Image Tree Source are as expected. | ||
| 973 | # The order of fields in the below array is important. Not all the | ||
| 974 | # fields are tested, only the key fields that wont vary between | ||
| 975 | # different architectures. | ||
| 976 | its_field_check = [ | ||
| 977 | 'description = "A model description";', | ||
| 978 | 'type = "standalone";', | ||
| 979 | 'load = <0x80080000>;', | ||
| 980 | 'entry = <0x80080000>;', | ||
| 981 | 'description = "Trusted Execution Environment";', | ||
| 982 | 'os = "tee";', | ||
| 983 | 'load = <0x80180000>;', | ||
| 984 | 'entry = <0x80180000>;', | ||
| 985 | 'description = "ARM Trusted Firmware";', | ||
| 986 | 'os = "arm-trusted-firmware";', | ||
| 987 | 'load = <0x80280000>;', | ||
| 988 | 'entry = <0x80280000>;', | ||
| 989 | 'default = "conf";', | ||
| 990 | 'loadables = "atf", "tee", "uboot";', | ||
| 991 | 'fdt = "fdt";' | ||
| 992 | ] | ||
| 993 | |||
| 994 | with open(fitimage_its_path) as its_file: | ||
| 995 | field_index = 0 | ||
| 996 | for line in its_file: | ||
| 997 | if field_index == len(its_field_check): | ||
| 998 | break | ||
| 999 | if its_field_check[field_index] in line: | ||
| 1000 | field_index +=1 | ||
| 1001 | |||
| 1002 | if field_index != len(its_field_check): # if its equal, the test passed | ||
| 1003 | self.assertTrue(field_index == len(its_field_check), | ||
| 1004 | "Fields in Image Tree Source File %s did not match, error in finding %s" | ||
| 1005 | % (fitimage_its_path, its_field_check[field_index])) | ||
| 1006 | |||
| 1007 | |||
| 1008 | def test_sign_standalone_uboot_atf_tee_fit_image(self): | ||
| 1009 | """ | ||
| 1010 | Summary: Check if U-Boot FIT image and Image Tree Source (its) are | ||
| 1011 | created and signed correctly for the scenario where only | ||
| 1012 | the U-Boot proper fitImage is being created and signed. | ||
| 1013 | Expected: 1. Create atf and tee dummy images | ||
| 1014 | 2. U-Boot its and FIT image are built successfully | ||
| 1015 | 3. Scanning the its file indicates signing is enabled | ||
| 1016 | as requested by SPL_SIGN_ENABLE (using keys generated | ||
| 1017 | via UBOOT_FIT_GENERATE_KEYS) | ||
| 1018 | 4. Dumping the FIT image indicates signature values | ||
| 1019 | are present | ||
| 1020 | 5. Examination of the do_uboot_assemble_fitimage | ||
| 1021 | runfile/logfile indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN | ||
| 1022 | and SPL_MKIMAGE_SIGN_ARGS are working as expected. | ||
| 1023 | Product: oe-core | ||
| 1024 | Author: Jamin Lin <jamin_lin@aspeedtech.com> | ||
| 1025 | """ | ||
| 1026 | a_comment = "a smart U-Boot ATF TEE comment" | ||
| 1027 | config = """ | ||
| 1028 | # There's no U-boot deconfig with CONFIG_FIT_SIGNATURE yet, so we need at | ||
| 1029 | # least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set | ||
| 1030 | MACHINE = "qemuarm" | ||
| 1031 | UBOOT_MACHINE = "am57xx_evm_defconfig" | ||
| 1032 | SPL_BINARY = "MLO" | ||
| 1033 | # The kernel-fitimage class is a dependency even if we're only | ||
| 1034 | # creating/signing the U-Boot fitImage | ||
| 1035 | KERNEL_CLASSES = " kernel-fitimage" | ||
| 1036 | # Enable creation and signing of the U-Boot fitImage | ||
| 1037 | UBOOT_FITIMAGE_ENABLE = "1" | ||
| 1038 | SPL_SIGN_ENABLE = "1" | ||
| 1039 | SPL_SIGN_KEYNAME = "spl-oe-selftest" | ||
| 1040 | SPL_SIGN_KEYDIR = "${TOPDIR}/signing-keys" | ||
| 1041 | UBOOT_DTB_BINARY = "u-boot.dtb" | ||
| 1042 | UBOOT_ENTRYPOINT = "0x80000000" | ||
| 1043 | UBOOT_LOADADDRESS = "0x80000000" | ||
| 1044 | UBOOT_ARCH = "arm" | ||
| 1045 | SPL_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" | ||
| 1046 | SPL_MKIMAGE_SIGN_ARGS = "-c '%s'" | ||
| 1047 | UBOOT_EXTLINUX = "0" | ||
| 1048 | UBOOT_FIT_GENERATE_KEYS = "1" | ||
| 1049 | UBOOT_FIT_HASH_ALG = "sha256" | ||
| 1050 | |||
| 1051 | # Enable creation of the TEE fitImage | ||
| 1052 | UBOOT_FIT_TEE = "1" | ||
| 1053 | |||
| 1054 | # TEE fitImage properties | ||
| 1055 | UBOOT_FIT_TEE_IMAGE = "${TOPDIR}/tee-dummy.bin" | ||
| 1056 | UBOOT_FIT_TEE_LOADADDRESS = "0x80180000" | ||
| 1057 | UBOOT_FIT_TEE_ENTRYPOINT = "0x80180000" | ||
| 1058 | |||
| 1059 | # Enable creation of the ATF fitImage | ||
| 1060 | UBOOT_FIT_ARM_TRUSTED_FIRMWARE = "1" | ||
| 1061 | |||
| 1062 | # ATF fitImage properties | ||
| 1063 | UBOOT_FIT_ARM_TRUSTED_FIRMWARE_IMAGE = "${TOPDIR}/atf-dummy.bin" | ||
| 1064 | UBOOT_FIT_ARM_TRUSTED_FIRMWARE_LOADADDRESS = "0x80280000" | ||
| 1065 | UBOOT_FIT_ARM_TRUSTED_FIRMWARE_ENTRYPOINT = "0x80280000" | ||
| 1066 | """ % a_comment | ||
| 1067 | |||
| 1068 | self.write_config(config) | ||
| 1069 | |||
| 1070 | # Create an ATF dummy image | ||
| 1071 | atf_dummy_image = os.path.join(self.builddir, "atf-dummy.bin") | ||
| 1072 | cmd = 'dd if=/dev/random of=%s bs=1k count=64' % (atf_dummy_image) | ||
| 1073 | result = runCmd(cmd) | ||
| 1074 | self.logger.debug("%s\nreturned: %s\n%s", cmd, str(result.status), result.output) | ||
| 1075 | |||
| 1076 | # Create a TEE dummy image | ||
| 1077 | tee_dummy_image = os.path.join(self.builddir, "tee-dummy.bin") | ||
| 1078 | cmd = 'dd if=/dev/random of=%s bs=1k count=64' % (tee_dummy_image) | ||
| 1079 | result = runCmd(cmd) | ||
| 1080 | self.logger.debug("%s\nreturned: %s\n%s", cmd, str(result.status), result.output) | ||
| 1081 | |||
| 1082 | # The U-Boot fitImage is created as part of the U-Boot recipe | ||
| 1083 | bitbake("virtual/bootloader") | ||
| 1084 | |||
| 1085 | deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') | ||
| 1086 | machine = get_bb_var('MACHINE') | ||
| 1087 | fitimage_its_path = os.path.join(deploy_dir_image, | ||
| 1088 | "u-boot-its-%s" % (machine,)) | ||
| 1089 | fitimage_path = os.path.join(deploy_dir_image, | ||
| 1090 | "u-boot-fitImage-%s" % (machine,)) | ||
| 1091 | |||
| 1092 | self.assertExists(fitimage_its_path, "%s image tree source doesn't exist" % (fitimage_its_path)) | ||
| 1093 | self.assertExists(fitimage_path, "%s FIT image doesn't exist" % (fitimage_path)) | ||
| 1094 | |||
| 1095 | req_itspaths = [ | ||
| 1096 | ['/', 'images', 'uboot'], | ||
| 1097 | ['/', 'images', 'uboot', 'signature'], | ||
| 1098 | ['/', 'images', 'fdt'], | ||
| 1099 | ['/', 'images', 'fdt', 'signature'], | ||
| 1100 | ['/', 'images', 'tee'], | ||
| 1101 | ['/', 'images', 'tee', 'signature'], | ||
| 1102 | ['/', 'images', 'atf'], | ||
| 1103 | ['/', 'images', 'atf', 'signature'], | ||
| 1104 | ] | ||
| 1105 | |||
| 1106 | itspath = [] | ||
| 1107 | itspaths = [] | ||
| 1108 | linect = 0 | ||
| 1109 | sigs = {} | ||
| 1110 | with open(fitimage_its_path) as its_file: | ||
| 1111 | linect += 1 | ||
| 1112 | for line in its_file: | ||
| 1113 | line = line.strip() | ||
| 1114 | if line.endswith('};'): | ||
| 1115 | itspath.pop() | ||
| 1116 | elif line.endswith('{'): | ||
| 1117 | itspath.append(line[:-1].strip()) | ||
| 1118 | itspaths.append(itspath[:]) | ||
| 1119 | elif itspath and itspath[-1] == 'signature': | ||
| 1120 | itsdotpath = '.'.join(itspath) | ||
| 1121 | if not itsdotpath in sigs: | ||
| 1122 | sigs[itsdotpath] = {} | ||
| 1123 | if not '=' in line or not line.endswith(';'): | ||
| 1124 | self.fail('Unexpected formatting in %s sigs section line %d:%s' % (fitimage_its_path, linect, line)) | ||
| 1125 | key, value = line.split('=', 1) | ||
| 1126 | sigs[itsdotpath][key.rstrip()] = value.lstrip().rstrip(';') | ||
| 1127 | |||
| 1128 | for reqpath in req_itspaths: | ||
| 1129 | if not reqpath in itspaths: | ||
| 1130 | self.fail('Missing section in its file: %s' % reqpath) | ||
| 1131 | |||
| 1132 | reqsigvalues_image = { | ||
| 1133 | 'algo': '"sha256,rsa2048"', | ||
| 1134 | 'key-name-hint': '"spl-oe-selftest"', | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | for itspath, values in sigs.items(): | ||
| 1138 | reqsigvalues = reqsigvalues_image | ||
| 1139 | for reqkey, reqvalue in reqsigvalues.items(): | ||
| 1140 | value = values.get(reqkey, None) | ||
| 1141 | if value is None: | ||
| 1142 | self.fail('Missing key "%s" in its file signature section %s' % (reqkey, itspath)) | ||
| 1143 | self.assertEqual(value, reqvalue) | ||
| 1144 | |||
| 1145 | # Dump the image to see if it really got signed | ||
| 1146 | uboot_tools_bindir = self._setup_uboot_tools_native() | ||
| 1147 | dumpimage_result = self._run_dumpimage(fitimage_path, uboot_tools_bindir) | ||
| 1148 | in_signed = None | ||
| 1149 | signed_sections = {} | ||
| 1150 | for line in dumpimage_result.output.splitlines(): | ||
| 1151 | if line.startswith((' Image')): | ||
| 1152 | in_signed = re.search(r'\((.*)\)', line).groups()[0] | ||
| 1153 | elif re.match(' \w', line): | ||
| 1154 | in_signed = None | ||
| 1155 | elif in_signed: | ||
| 1156 | if not in_signed in signed_sections: | ||
| 1157 | signed_sections[in_signed] = {} | ||
| 1158 | key, value = line.split(':', 1) | ||
| 1159 | signed_sections[in_signed][key.strip()] = value.strip() | ||
| 1160 | self.assertIn('uboot', signed_sections) | ||
| 1161 | self.assertIn('fdt', signed_sections) | ||
| 1162 | self.assertIn('tee', signed_sections) | ||
| 1163 | self.assertIn('atf', signed_sections) | ||
| 1164 | for signed_section, values in signed_sections.items(): | ||
| 1165 | value = values.get('Sign algo', None) | ||
| 1166 | self.assertEqual(value, 'sha256,rsa2048:spl-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) | ||
| 1167 | value = values.get('Sign value', None) | ||
| 1168 | self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section) | ||
| 1169 | |||
| 1170 | # Check for SPL_MKIMAGE_SIGN_ARGS | ||
| 1171 | # Looks like mkimage supports to add a comment but does not support to read it back. | ||
| 1172 | found_comments = FitImageTests._find_string_in_bin_file(fitimage_path, a_comment) | ||
| 1173 | self.assertEqual(found_comments, 4, "Expected 4 signed and commented section in the fitImage.") | ||
| 1174 | |||
| 1175 | # Verify the signature | ||
| 1176 | self._verify_fit_image_signature(uboot_tools_bindir, fitimage_path, | ||
| 1177 | os.path.join(deploy_dir_image, 'u-boot-spl.dtb')) | ||
