def ObtainContents(self): """Obtain the contents of the FIT This adds the 'data' properties to the input ITB (Image-tree Binary) then runs mkimage to process it. """ # self._BuildInput() either returns bytes or raises an exception. data = self._BuildInput(self._fdt) uniq = self.GetUniqueName() input_fname = tools.GetOutputFilename('%s.itb' % uniq) output_fname = tools.GetOutputFilename('%s.fit' % uniq) tools.WriteFile(input_fname, data) tools.WriteFile(output_fname, data) args = [] ext_offset = self._fit_props.get('fit,external-offset') if ext_offset is not None: args += [ '-E', '-p', '%x' % fdt_util.fdt32_to_cpu(ext_offset.value) ] tools.Run('mkimage', '-t', '-F', output_fname, *args) self.SetContents(tools.ReadFile(output_fname)) return True
def ObtainContents(self): """Obtain the contents of the FIT This adds the 'data' properties to the input ITB (Image-tree Binary) then runs mkimage to process it. """ # self._BuildInput() either returns bytes or raises an exception. data = self._BuildInput(self._fdt) uniq = self.GetUniqueName() input_fname = tools.GetOutputFilename('%s.itb' % uniq) output_fname = tools.GetOutputFilename('%s.fit' % uniq) tools.WriteFile(input_fname, data) tools.WriteFile(output_fname, data) args = {} ext_offset = self._fit_props.get('fit,external-offset') if ext_offset is not None: args = { 'external': True, 'pad': fdt_util.fdt32_to_cpu(ext_offset.value) } if self.mkimage.run(reset_timestamp=True, output_fname=output_fname, **args) is not None: self.SetContents(tools.ReadFile(output_fname)) else: # Bintool is missing; just use empty data as the output self.record_missing_bintool(self.mkimage) self.SetContents(tools.GetBytes(0, 1024)) return True
def _BuildIfwi(self): """Build the contents of the IFWI and write it to the 'data' property""" # Create the IFWI file if needed if self._convert_fit: inname = self._pathname outname = tools.GetOutputFilename('ifwi.bin') tools.RunIfwiTool(inname, tools.CMD_CREATE, outname) self._filename = 'ifwi.bin' self._pathname = outname else: # Provide a different code path here to ensure we have test coverage outname = self._pathname # Delete OBBP if it is there, then add the required new items. tools.RunIfwiTool(outname, tools.CMD_DELETE, subpart='OBBP') for entry in self._ifwi_entries.values(): # First get the input data and put it in a file data = entry.GetData() uniq = self.GetUniqueName() input_fname = tools.GetOutputFilename('input.%s' % uniq) tools.WriteFile(input_fname, data) tools.RunIfwiTool(outname, tools.CMD_REPLACE if entry._ifwi_replace else tools.CMD_ADD, input_fname, entry._ifwi_subpart, entry._ifwi_entry_name) self.ReadBlobContents() return True
def GetVblock(self): # Join up the data files to be signed input_data = b'' for entry_phandle in self.content: data = self.section.GetContentsByPhandle(entry_phandle, self) if data is None: # Data not available yet return False input_data += data uniq = self.GetUniqueName() output_fname = tools.GetOutputFilename('vblock.%s' % uniq) input_fname = tools.GetOutputFilename('input.%s' % uniq) tools.WriteFile(input_fname, input_data) prefix = self.keydir + '/' args = [ 'vbutil_firmware', '--vblock', output_fname, '--keyblock', prefix + self.keyblock, '--signprivate', prefix + self.signprivate, '--version', '%d' % self.version, '--fv', input_fname, '--kernelkey', prefix + self.kernelkey, '--flags', '%d' % self.preamble_flags, ] #out.Notice("Sign '%s' into %s" % (', '.join(self.value), self.label)) stdout = tools.Run('futility', *args) return tools.ReadFile(output_fname)
def ObtainContents(self): data = b'' for entry in self._mkimage_entries.values(): # First get the input data and put it in a file. If not available, # try later. if not entry.ObtainContents(): return False data += entry.GetData() uniq = self.GetUniqueName() input_fname = tools.GetOutputFilename('mkimage.%s' % uniq) tools.WriteFile(input_fname, data) output_fname = tools.GetOutputFilename('mkimage-out.%s' % uniq) tools.Run('mkimage', '-d', input_fname, *self._args, output_fname) self.SetContents(tools.ReadFile(output_fname)) return True
def ObtainContents(self): gbb = 'gbb.bin' fname = tools.GetOutputFilename(gbb) if not self.size: self.Raise('GBB must have a fixed size') gbb_size = self.size bmpfv_size = gbb_size - 0x2180 if bmpfv_size < 0: self.Raise('GBB is too small (minimum 0x2180 bytes)') sizes = [0x100, 0x1000, bmpfv_size, 0x1000] sizes = ['%#x' % size for size in sizes] keydir = tools.GetInputFilename(self.keydir) gbb_set_command = [ 'gbb_utility', '-s', '--hwid=%s' % self.hardware_id, '--rootkey=%s/root_key.vbpubk' % keydir, '--recoverykey=%s/recovery_key.vbpubk' % keydir, '--flags=%d' % self.gbb_flags, '--bmpfv=%s' % tools.GetInputFilename(self.bmpblk), fname ] tools.Run('futility', 'gbb_utility', '-c', ','.join(sizes), fname) tools.Run('futility', *gbb_set_command) self.SetContents(tools.ReadFile(fname)) return True
def test_driver_alias(self): """Test output from a device tree file with a driver alias""" dtb_file = get_dtb_file('dtoc_test_driver_alias.dts') output = tools.GetOutputFilename('output') self.run_test(['struct'], dtb_file, output) with open(output) as infile: data = infile.read() self._CheckStrings(HEADER + ''' struct dtd_sandbox_gpio { \tconst char *\tgpio_bank_name; \tbool\t\tgpio_controller; \tfdt32_t\t\tsandbox_gpio_count; }; ''', data) self.run_test(['platdata'], dtb_file, output) with open(output) as infile: data = infile.read() self._CheckStrings(C_HEADER + ''' static struct dtd_sandbox_gpio dtv_gpios_at_0 = { \t.gpio_bank_name\t\t= "a", \t.gpio_controller\t= true, \t.sandbox_gpio_count\t= 0x14, }; U_BOOT_DEVICE(gpios_at_0) = { \t.name\t\t= "sandbox_gpio", \t.platdata\t= &dtv_gpios_at_0, \t.platdata_size\t= sizeof(dtv_gpios_at_0), }; void dm_populate_phandle_data(void) { } ''', data)
def testScanDrivers(self): """Test running dtoc with additional drivers to scan""" dtb_file = get_dtb_file('dtoc_test_simple.dts') output = tools.GetOutputFilename('output') with test_util.capture_sys_output() as (stdout, stderr): dtb_platdata.run_steps(['struct'], dtb_file, False, output, True, [None, '', 'tools/dtoc/dtoc_test_scan_drivers.cxx'])
def test_driver_alias(self): """Test output from a device tree file with a driver alias""" dtb_file = get_dtb_file('dtoc_test_driver_alias.dts') output = tools.GetOutputFilename('output') self.run_test(['struct'], dtb_file, output) with open(output) as infile: data = infile.read() self._check_strings(HEADER + ''' struct dtd_sandbox_gpio { \tconst char *\tgpio_bank_name; \tbool\t\tgpio_controller; \tfdt32_t\t\tsandbox_gpio_count; }; ''', data) self.run_test(['platdata'], dtb_file, output) with open(output) as infile: data = infile.read() self._check_strings(C_HEADER + ''' /* Node /gpios@0 index 0 */ static struct dtd_sandbox_gpio dtv_gpios_at_0 = { \t.gpio_bank_name\t\t= "a", \t.gpio_controller\t= true, \t.sandbox_gpio_count\t= 0x14, }; U_BOOT_DRVINFO(gpios_at_0) = { \t.name\t\t= "sandbox_gpio", \t.plat\t= &dtv_gpios_at_0, \t.plat_size\t= sizeof(dtv_gpios_at_0), \t.parent_idx\t= -1, }; ''', data)
def test_phandle_reorder(self): """Test that phandle targets are generated before their references""" dtb_file = get_dtb_file('dtoc_test_phandle_reorder.dts') output = tools.GetOutputFilename('output') self.run_test(['platdata'], dtb_file, output) with open(output) as infile: data = infile.read() self._check_strings(C_HEADER + ''' /* Node /phandle-source2 index 0 */ static struct dtd_source dtv_phandle_source2 = { \t.clocks\t\t\t= { \t\t\t{1, {}},}, }; U_BOOT_DRVINFO(phandle_source2) = { \t.name\t\t= "source", \t.plat\t= &dtv_phandle_source2, \t.plat_size\t= sizeof(dtv_phandle_source2), \t.parent_idx\t= -1, }; /* Node /phandle-target index 1 */ static struct dtd_target dtv_phandle_target = { }; U_BOOT_DRVINFO(phandle_target) = { \t.name\t\t= "target", \t.plat\t= &dtv_phandle_target, \t.plat_size\t= sizeof(dtv_phandle_target), \t.parent_idx\t= -1, }; ''', data)
def test_aliases(self): """Test output from a node with multiple compatible strings""" dtb_file = get_dtb_file('dtoc_test_aliases.dts') output = tools.GetOutputFilename('output') self.run_test(['struct'], dtb_file, output) with open(output) as infile: data = infile.read() self._CheckStrings( HEADER + ''' struct dtd_compat1 { \tfdt32_t\t\tintval; }; #define dtd_compat2_1_fred dtd_compat1 #define dtd_compat3 dtd_compat1 ''', data) self.run_test(['platdata'], dtb_file, output) with open(output) as infile: data = infile.read() self._CheckStrings( C_HEADER + ''' static struct dtd_compat1 dtv_spl_test = { \t.intval\t\t\t= 0x1, }; U_BOOT_DEVICE(spl_test) = { \t.name\t\t= "compat1", \t.platdata\t= &dtv_spl_test, \t.platdata_size\t= sizeof(dtv_spl_test), }; ''' + C_EMPTY_POPULATE_PHANDLE_DATA, data)
def ObtainContents(self): gbb = 'gbb.bin' fname = tools.GetOutputFilename(gbb) if not self.size: self.Raise('GBB must have a fixed size') gbb_size = self.size bmpfv_size = gbb_size - 0x2180 if bmpfv_size < 0: self.Raise('GBB is too small (minimum 0x2180 bytes)') keydir = tools.GetInputFilename(self.keydir) stdout = self.futility.gbb_create( fname, [0x100, 0x1000, bmpfv_size, 0x1000]) if stdout is not None: stdout = self.futility.gbb_set( fname, hwid=self.hardware_id, rootkey='%s/root_key.vbpubk' % keydir, recoverykey='%s/recovery_key.vbpubk' % keydir, flags=self.gbb_flags, bmpfv=tools.GetInputFilename(self.bmpblk)) if stdout is not None: self.SetContents(tools.ReadFile(fname)) else: # Bintool is missing; just use the required amount of zero data self.record_missing_bintool(self.futility) self.SetContents(tools.GetBytes(0, gbb_size)) return True
def test_multi_to_file(self): """Test output of multiple pieces to a single file""" dtb_file = get_dtb_file('dtoc_test_simple.dts') output = tools.GetOutputFilename('output') self.run_test(['all'], dtb_file, output) data = tools.ReadFile(output, binary=False) self._check_strings(self.platdata_text + self.struct_text, data)
def test_phandle_reorder(self): """Test that phandle targets are generated before their references""" dtb_file = get_dtb_file('dtoc_test_phandle_reorder.dts') output = tools.GetOutputFilename('output') self.run_test(['platdata'], dtb_file, output) with open(output) as infile: data = infile.read() self._CheckStrings( C_HEADER + ''' static struct dtd_target dtv_phandle_target = { }; U_BOOT_DEVICE(phandle_target) = { \t.name\t\t= "target", \t.platdata\t= &dtv_phandle_target, \t.platdata_size\t= sizeof(dtv_phandle_target), }; static struct dtd_source dtv_phandle_source2 = { \t.clocks\t\t\t= { \t\t\t{NULL, {}},}, }; U_BOOT_DEVICE(phandle_source2) = { \t.name\t\t= "source", \t.platdata\t= &dtv_phandle_source2, \t.platdata_size\t= sizeof(dtv_phandle_source2), }; void dm_populate_phandle_data(void) { \tdtv_phandle_source2.clocks[0].node = DM_GET_DEVICE(phandle_target); } ''', data)
def test_invalid_driver(self): """Test output from a device tree file with an invalid driver""" dtb_file = get_dtb_file('dtoc_test_invalid_driver.dts') output = tools.GetOutputFilename('output') with test_util.capture_sys_output() as (stdout, stderr): dtb_platdata.run_steps(['struct'], dtb_file, False, output) with open(output) as infile: data = infile.read() self._CheckStrings(HEADER + ''' struct dtd_invalid { }; ''', data) with test_util.capture_sys_output() as (stdout, stderr): dtb_platdata.run_steps(['platdata'], dtb_file, False, output) with open(output) as infile: data = infile.read() self._CheckStrings( C_HEADER + ''' static struct dtd_invalid dtv_spl_test = { }; U_BOOT_DEVICE(spl_test) = { \t.name\t\t= "invalid", \t.platdata\t= &dtv_spl_test, \t.platdata_size\t= sizeof(dtv_spl_test), }; void dm_populate_phandle_data(void) { } ''', data)
def test_invalid_driver(self): """Test output from a device tree file with an invalid driver""" dtb_file = get_dtb_file('dtoc_test_invalid_driver.dts') output = tools.GetOutputFilename('output') with test_util.capture_sys_output() as _: dtb_platdata.run_steps(['struct'], dtb_file, False, output, []) with open(output) as infile: data = infile.read() self._check_strings(HEADER + ''' struct dtd_invalid { }; ''', data) with test_util.capture_sys_output() as _: dtb_platdata.run_steps(['platdata'], dtb_file, False, output, []) with open(output) as infile: data = infile.read() self._check_strings(C_HEADER + ''' /* Node /spl-test index 0 */ static struct dtd_invalid dtv_spl_test = { }; U_BOOT_DRVINFO(spl_test) = { \t.name\t\t= "invalid", \t.plat\t= &dtv_spl_test, \t.plat_size\t= sizeof(dtv_spl_test), \t.parent_idx\t= -1, }; ''', data)
def test_phandle_reorder(self): """Test that phandle targets are generated before their references""" dtb_file = get_dtb_file('dtoc_test_phandle_reorder.dts') output = tools.GetOutputFilename('output') dtb_platdata.run_steps(['platdata'], dtb_file, False, output) with open(output) as infile: data = infile.read() self._CheckStrings( C_HEADER + ''' static const struct dtd_target dtv_phandle_target = { }; U_BOOT_DEVICE(phandle_target) = { \t.name\t\t= "target", \t.platdata\t= &dtv_phandle_target, \t.platdata_size\t= sizeof(dtv_phandle_target), }; static const struct dtd_source dtv_phandle_source2 = { \t.clocks\t\t\t= { \t\t\t{&dtv_phandle_target, {}},}, }; U_BOOT_DEVICE(phandle_source2) = { \t.name\t\t= "source", \t.platdata\t= &dtv_phandle_source2, \t.platdata_size\t= sizeof(dtv_phandle_source2), }; ''', data)
def BuildImage(self): """Write the image to a file""" fname = tools.GetOutputFilename(self._filename) tout.Info("Writing image to '%s'" % fname) with open(fname, 'wb') as fd: data = self.GetPaddedData() fd.write(data) tout.Info("Wrote %#x bytes" % len(data))
def EnsureCompiled(fname, tmpdir=None, capture_stderr=False): """Compile an fdt .dts source file into a .dtb binary blob if needed. Args: fname: Filename (if .dts it will be compiled). It not it will be left alone tmpdir: Temporary directory for output files, or None to use the tools-module output directory Returns: Filename of resulting .dtb file """ _, ext = os.path.splitext(fname) if ext != '.dts': return fname if tmpdir: dts_input = os.path.join(tmpdir, 'source.dts') dtb_output = os.path.join(tmpdir, 'source.dtb') else: dts_input = tools.GetOutputFilename('source.dts') dtb_output = tools.GetOutputFilename('source.dtb') search_paths = [os.path.join(os.getcwd(), 'include')] root, _ = os.path.splitext(fname) cc, args = tools.GetTargetCompileTool('cc') args += ['-E', '-P', '-x', 'assembler-with-cpp', '-D__ASSEMBLY__'] args += ['-Ulinux'] for path in search_paths: args.extend(['-I', path]) args += ['-o', dts_input, fname] command.Run(cc, *args) # If we don't have a directory, put it in the tools tempdir search_list = [] for path in search_paths: search_list.extend(['-i', path]) dtc, args = tools.GetTargetCompileTool('dtc') args += [ '-I', 'dts', '-o', dtb_output, '-O', 'dtb', '-W', 'no-unit_address_vs_reg' ] args.extend(search_list) args.append(dts_input) command.Run(dtc, *args, capture_stderr=capture_stderr) return dtb_output
def testBadCommand(self): """Test running dtoc with an invalid command""" dtb_file = get_dtb_file('dtoc_test_simple.dts') output = tools.GetOutputFilename('output') with self.assertRaises(ValueError) as e: dtb_platdata.run_steps(['invalid-cmd'], dtb_file, False, output) self.assertIn("Unknown command 'invalid-cmd': (use: struct, platdata)", str(e.exception))
def test_bad_command(self): """Test running dtoc with an invalid command""" dtb_file = get_dtb_file('dtoc_test_simple.dts') output = tools.GetOutputFilename('output') with self.assertRaises(ValueError) as exc: self.run_test(['invalid-cmd'], dtb_file, output) self.assertIn("Unknown command 'invalid-cmd': (use: platdata, struct)", str(exc.exception))
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._pathname = out_fname super().ReadBlobContents() return True
def test_addresses64_32(self): """Test output from a node with a 'reg' property with na=2, ns=1""" dtb_file = get_dtb_file('dtoc_test_addr64_32.dts') output = tools.GetOutputFilename('output') self.run_test(['struct'], dtb_file, output) with open(output) as infile: data = infile.read() self._CheckStrings(HEADER + ''' struct dtd_test1 { \tfdt64_t\t\treg[2]; }; struct dtd_test2 { \tfdt64_t\t\treg[2]; }; struct dtd_test3 { \tfdt64_t\t\treg[4]; }; ''', data) self.run_test(['platdata'], dtb_file, output) with open(output) as infile: data = infile.read() self._CheckStrings(C_HEADER + ''' /* Node /test1 index 0 */ static struct dtd_test1 dtv_test1 = { \t.reg\t\t\t= {0x123400000000, 0x5678}, }; U_BOOT_DEVICE(test1) = { \t.name\t\t= "test1", \t.platdata\t= &dtv_test1, \t.platdata_size\t= sizeof(dtv_test1), \t.parent_idx\t= -1, }; /* Node /test2 index 1 */ static struct dtd_test2 dtv_test2 = { \t.reg\t\t\t= {0x1234567890123456, 0x98765432}, }; U_BOOT_DEVICE(test2) = { \t.name\t\t= "test2", \t.platdata\t= &dtv_test2, \t.platdata_size\t= sizeof(dtv_test2), \t.parent_idx\t= -1, }; /* Node /test3 index 2 */ static struct dtd_test3 dtv_test3 = { \t.reg\t\t\t= {0x1234567890123456, 0x98765432, 0x2, 0x3}, }; U_BOOT_DEVICE(test3) = { \t.name\t\t= "test3", \t.platdata\t= &dtv_test3, \t.platdata_size\t= sizeof(dtv_test3), \t.parent_idx\t= -1, }; ''' + C_EMPTY_POPULATE_PHANDLE_DATA, data)
def test_bad_reg(self): """Test that a reg property with an invalid type generates an error""" # Capture stderr since dtc will emit warnings for this file dtb_file = get_dtb_file('dtoc_test_bad_reg.dts', capture_stderr=True) output = tools.GetOutputFilename('output') with self.assertRaises(ValueError) as exc: self.run_test(['struct'], dtb_file, output) self.assertIn("Node 'spl-test' reg property is not an int", str(exc.exception))
def test_addresses32_64(self): """Test output from a node with a 'reg' property with na=1, ns=2""" dtb_file = get_dtb_file('dtoc_test_addr32_64.dts') output = tools.GetOutputFilename('output') self.run_test(['struct'], dtb_file, output) with open(output) as infile: data = infile.read() self._check_strings(HEADER + ''' struct dtd_test1 { \tfdt64_t\t\treg[2]; }; struct dtd_test2 { \tfdt64_t\t\treg[2]; }; struct dtd_test3 { \tfdt64_t\t\treg[4]; }; ''', data) self.run_test(['platdata'], dtb_file, output) with open(output) as infile: data = infile.read() self._check_strings(C_HEADER + ''' /* Node /test1 index 0 */ static struct dtd_test1 dtv_test1 = { \t.reg\t\t\t= {0x1234, 0x567800000000}, }; U_BOOT_DRVINFO(test1) = { \t.name\t\t= "test1", \t.plat\t= &dtv_test1, \t.plat_size\t= sizeof(dtv_test1), \t.parent_idx\t= -1, }; /* Node /test2 index 1 */ static struct dtd_test2 dtv_test2 = { \t.reg\t\t\t= {0x12345678, 0x9876543210987654}, }; U_BOOT_DRVINFO(test2) = { \t.name\t\t= "test2", \t.plat\t= &dtv_test2, \t.plat_size\t= sizeof(dtv_test2), \t.parent_idx\t= -1, }; /* Node /test3 index 2 */ static struct dtd_test3 dtv_test3 = { \t.reg\t\t\t= {0x12345678, 0x9876543210987654, 0x2, 0x3}, }; U_BOOT_DRVINFO(test3) = { \t.name\t\t= "test3", \t.plat\t= &dtv_test3, \t.plat_size\t= sizeof(dtv_test3), \t.parent_idx\t= -1, }; ''', data)
def test_phandle_bad2(self): """Test a phandle target missing its #*-cells property""" dtb_file = get_dtb_file('dtoc_test_phandle_bad2.dts', capture_stderr=True) output = tools.GetOutputFilename('output') with self.assertRaises(ValueError) as exc: self.run_test(['struct'], dtb_file, output) self.assertIn("Node 'phandle-target' has no cells property", str(exc.exception))
def test_phandle_bad(self): """Test a node containing an invalid phandle fails""" dtb_file = get_dtb_file('dtoc_test_phandle_bad.dts', capture_stderr=True) output = tools.GetOutputFilename('output') with self.assertRaises(ValueError) as exc: self.run_test(['struct'], dtb_file, output) self.assertIn("Cannot parse 'clocks' in node 'phandle-source'", str(exc.exception))
def test_struct_scan_errors(self): """Test scanning a header file with an invalid unicode file""" output = tools.GetOutputFilename('output.h') tools.WriteFile(output, b'struct this is a test \x81 of bad unicode') scan = src_scan.Scanner(None, None) with test_util.capture_sys_output() as (stdout, _): scan.scan_header(output) self.assertIn('due to unicode error', stdout.getvalue())
def test_bad_reg2(self): """Test that a reg property with an invalid cell count is detected""" # Capture stderr since dtc will emit warnings for this file dtb_file = get_dtb_file('dtoc_test_bad_reg2.dts', capture_stderr=True) output = tools.GetOutputFilename('output') with self.assertRaises(ValueError) as e: self.run_test(['struct'], dtb_file, output) self.assertIn("Node 'spl-test' reg property has 3 cells which is not a multiple of na + ns = 1 + 1)", str(e.exception))
def GetVblock(self, required): """Get the contents of this entry Args: required: True if the data must be present, False if it is OK to return None Returns: bytes content of the entry, which is the signed vblock for the provided data """ # Join up the data files to be signed input_data = self.GetContents(required) if input_data is None: return None uniq = self.GetUniqueName() output_fname = tools.GetOutputFilename('vblock.%s' % uniq) input_fname = tools.GetOutputFilename('input.%s' % uniq) tools.WriteFile(input_fname, input_data) prefix = self.keydir + '/' args = [ 'vbutil_firmware', '--vblock', output_fname, '--keyblock', prefix + self.keyblock, '--signprivate', prefix + self.signprivate, '--version', '%d' % self.version, '--fv', input_fname, '--kernelkey', prefix + self.kernelkey, '--flags', '%d' % self.preamble_flags, ] #out.Notice("Sign '%s' into %s" % (', '.join(self.value), self.label)) stdout = tools.Run('futility', *args) return tools.ReadFile(output_fname)