def _HandleMake(self, commit, brd, stage, cwd, *args, **kwargs): """Handle execution of 'make' Args: commit: Commit object that is being built brd: Board object that is being built stage: Stage that we are at (mrproper, config, build) cwd: Directory where make should be run args: Arguments to pass to make kwargs: Arguments to pass to command.run_pipe() """ self._make_calls += 1 if stage == 'mrproper': return command.CommandResult(return_code=0) elif stage == 'config': return command.CommandResult(return_code=0, combined='Test configuration complete') elif stage == 'build': stderr = '' out_dir = '' for arg in args: if arg.startswith('O='): out_dir = arg[2:] fname = os.path.join(cwd or '', out_dir, 'u-boot') tools.write_file(fname, b'U-Boot') if type(commit) is not str: stderr = self._error.get((brd.target, commit.sequence)) if stderr: return command.CommandResult(return_code=1, stderr=stderr) return command.CommandResult(return_code=0) # Not handled, so abort print('make', stage) sys.exit(1)
def fake_run(*cmd): if cmd[0] == 'make': # See Bintool.build_from_git() tmpdir = cmd[2] self.fname = os.path.join(tmpdir, 'pathname') if write_file: tools.write_file(self.fname, b'hello')
def BuildSectionData(self, required): """Build FIT entry contents This adds the 'data' properties to the input ITB (Image-tree Binary) then runs mkimage to process it. Args: required (bool): True if the data must be present, False if it is OK to return None Returns: bytes: Contents of the section """ data = self._build_input() uniq = self.GetUniqueName() input_fname = tools.get_output_filename(f'{uniq}.itb') output_fname = tools.get_output_filename(f'{uniq}.fit') tools.write_file(input_fname, data) tools.write_file(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 None: # Bintool is missing; just use empty data as the output self.record_missing_bintool(self.mkimage) return tools.get_bytes(0, 1024) return tools.read_file(output_fname)
def collect_contents_to_file(self, entries, prefix): """Put the contents of a list of entries into a file Args: entries (list of Entry): Entries to collect prefix (str): Filename prefix of file to write to If any entry does not have contents yet, this function returns False for the data. Returns: Tuple: bytes: Concatenated data from all the entries (or False) str: Filename of file written (or False if no data) str: Unique portion of filename (or False if no data) """ data = b'' for entry in entries: # First get the input data and put it in a file. If not available, # try later. if not entry.ObtainContents(): return False, False, False data += entry.GetData() uniq = self.GetUniqueName() fname = tools.get_output_filename(f'{prefix}.{uniq}') tools.write_file(fname, data) return data, fname, uniq
def handle_download(_): """Take the tools.download() function by writing a file""" if self.seq: raise urllib.error.URLError('not found') self.seq += 1 tools.write_file(fname, expected) return fname, dirname
def parse_atf_source(srcdir, dstfile, oldfile): """parse_atf_source(): Parse the ATF source tree and update this file Args: srcdir (str): Path to 'arm-trusted-firmware' directory. Get this from: https://github.com/ARM-software/arm-trusted-firmware.git dstfile (str): File to write new code to, if an update is needed oldfile (str): Python source file to compare against Raises: ValueError: srcdir readme.rst is missing or the first line does not match what is expected """ # We expect a readme file readme_fname = os.path.join(srcdir, 'readme.rst') if not os.path.exists(readme_fname): raise ValueError( f"Expected file '{readme_fname}' - try using -s to specify the " 'arm-trusted-firmware directory') readme = tools.read_file(readme_fname, binary=False) first_line = 'Trusted Firmware-A' if readme.splitlines()[0] != first_line: raise ValueError(f"'{readme_fname}' does not start with '{first_line}'") macros = parse_macros(srcdir) names = parse_names(srcdir) output = create_code_output(macros, names) orig = tools.read_file(oldfile, binary=False) re_fip_list = re.compile(r'(.*FIP_TYPE_LIST = \[).*?( ] # end.*)', re.S) mat = re_fip_list.match(orig) new_code = mat.group(1) + '\n' + output + mat.group(2) if mat else output if new_code == orig: print(f"Existing code in '{oldfile}' is up-to-date") else: tools.write_file(dstfile, new_code, binary=False) print(f'Needs update, try:\n\tmeld {dstfile} {oldfile}')
def ExtractEntries(image_fname, output_fname, outdir, entry_paths, decomp=True, alt_format=None): """Extract the data from one or more entries and write it to files Args: image_fname: Image filename to process output_fname: Single output filename to use if extracting one file, None otherwise outdir: Output directory to use (for any number of files), else None entry_paths: List of entry paths to extract decomp: True to decompress the entry data Returns: List of EntryInfo records that were written """ image = Image.FromFile(image_fname) if alt_format == 'list': ShowAltFormats(image) return # Output an entry to a single file, as a special case if output_fname: if not entry_paths: raise ValueError('Must specify an entry path to write with -f') if len(entry_paths) != 1: raise ValueError( 'Must specify exactly one entry path to write with -f') entry = image.FindEntryPath(entry_paths[0]) data = entry.ReadData(decomp, alt_format) tools.write_file(output_fname, data) tout.notice("Wrote %#x bytes to file '%s'" % (len(data), output_fname)) return # Otherwise we will output to a path given by the entry path of each entry. # This means that entries will appear in subdirectories if they are part of # a sub-section. einfos = image.GetListEntries(entry_paths)[0] tout.notice('%d entries match and will be written' % len(einfos)) for einfo in einfos: entry = einfo.entry data = entry.ReadData(decomp, alt_format) path = entry.GetPath()[1:] fname = os.path.join(outdir, path) # If this entry has children, create a directory for it and put its # data in a file called 'root' in that directory if entry.GetEntries(): if fname and not os.path.exists(fname): os.makedirs(fname) fname = os.path.join(fname, 'root') tout.notice("Write entry '%s' size %x to '%s'" % (entry.GetPath(), len(data), fname)) tools.write_file(fname, data) return einfos
def ReadBlobContents(self): if self._strip: uniq = self.GetUniqueName() out_fname = tools.get_output_filename('%s.stripped' % uniq) tools.write_file(out_fname, tools.read_file(self._pathname)) tools.run('strip', out_fname) self._pathname = out_fname super().ReadBlobContents() return True
def test_struct_scan_errors(self): """Test scanning a header file with an invalid unicode file""" output = tools.get_output_filename('output.h') tools.write_file(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_no_debug(self): """Test running without the -D flag""" self.setup_readme() self.setup_macro() self.setup_name() args = self.args.copy() args.remove('-D') tools.write_file(self.src_file, '', binary=False) with test_util.capture_sys_output(): fip_util.main(args, self.src_file)
def _make_input_file(cls, fname, contents): """Create a new test input file, creating directories as needed Args: fname: Filename to create contents: File contents to write in to the file Returns: Full pathname of file created """ pathname = os.path.join(cls._indir, fname) tools.write_file(pathname, contents) return pathname
def FromFile(cls, fname): """Convert an image file into an Image for use in binman Args: fname: Filename of image file to read Returns: Image object on success Raises: ValueError if something goes wrong """ data = tools.read_file(fname) size = len(data) # First look for an image header pos = image_header.LocateHeaderOffset(data) if pos is None: # Look for the FDT map pos = fdtmap.LocateFdtmap(data) if pos is None: raise ValueError('Cannot find FDT map in image') # We don't know the FDT size, so check its header first probe_dtb = fdt.Fdt.FromData(data[pos + fdtmap.FDTMAP_HDR_LEN:pos + 256]) dtb_size = probe_dtb.GetFdtObj().totalsize() fdtmap_data = data[pos:pos + dtb_size + fdtmap.FDTMAP_HDR_LEN] fdt_data = fdtmap_data[fdtmap.FDTMAP_HDR_LEN:] out_fname = tools.get_output_filename('fdtmap.in.dtb') tools.write_file(out_fname, fdt_data) dtb = fdt.Fdt(out_fname) dtb.Scan() # Return an Image with the associated nodes root = dtb.GetRoot() image = Image('image', root, copy_to_orig=False, ignore_missing=True, missing_etype=True, generate=False) image.image_node = fdt_util.GetString(root, 'image-node', 'image') image.fdtmap_dtb = dtb image.fdtmap_data = fdtmap_data image._data = data image._filename = fname image.image_name, _ = os.path.splitext(fname) return image
def decompress(self, indata): """Decompress data with lz4 Args: indata (bytes): Data to decompress Returns: bytes: Decompressed data """ with tempfile.NamedTemporaryFile(prefix='decomp.tmp', dir=tools.get_output_dir()) as inf: tools.write_file(inf.name, indata) args = ['-cd', inf.name] return self.run_cmd(*args, binary=True)
def compress(self, indata): """Compress data with lz4 Args: indata (bytes): Data to compress Returns: bytes: Compressed data """ with tempfile.NamedTemporaryFile(prefix='comp.tmp', dir=tools.get_output_dir()) as tmp: tools.write_file(tmp.name, indata) args = ['--no-frame-crc', '-B4', '-5', '-c', tmp.name] return self.run_cmd(*args, binary=True)
def UpdateFdtContents(etype, data): """Update the contents of a particular device tree The device tree is updated and written back to its file. This affects what is returned from future called to GetFdtContents(), etc. Args: etype: Entry type (e.g. 'u-boot-dtb') data: Data to replace the DTB with """ dtb, fname = output_fdt_info[etype] dtb_fname = dtb.GetFilename() tools.write_file(dtb_fname, data) dtb = fdt.FdtScan(dtb_fname) output_fdt_info[etype] = [dtb, fname]
def decompress(self, indata): """Decompress data with lzma_alone Args: indata (bytes): Data to decompress Returns: bytes: Decompressed data """ with tempfile.NamedTemporaryFile(prefix='decomp.tmp', dir=tools.get_output_dir()) as inf: tools.write_file(inf.name, indata) with tempfile.NamedTemporaryFile(prefix='compo.otmp', dir=tools.get_output_dir()) as outf: args = ['d', inf.name, outf.name] self.run_cmd(*args, binary=True) return tools.read_file(outf.name, binary=True)
def test_fiptool_list(self): """Create a FIP and check that fiptool can read it""" fwu = b'my data' tb_fw = b'some more data' fip = fip_util.FipWriter(0x123, 0x10) fip.add_entry('fwu', fwu, 0x456) fip.add_entry('tb-fw', tb_fw, 0) fip.add_entry(bytes(range(16)), tb_fw, 0) data = fip.get_data() fname = tools.get_output_filename('data.fip') tools.write_file(fname, data) result = FIPTOOL.info(fname) self.assertEqual( '''Firmware Updater NS_BL2U: offset=0xB0, size=0x7, cmdline="--fwu" Trusted Boot Firmware BL2: offset=0xC0, size=0xE, cmdline="--tb-fw" 00010203-0405-0607-0809-0A0B0C0D0E0F: offset=0xD0, size=0xE, cmdline="--blob" ''', result)
def make_commit_with_file(self, subject, body, fname, text): """Create a file and add it to the git repo with a new commit Args: subject (str): Subject for the commit body (str): Body text of the commit fname (str): Filename of file to create text (str): Text to put into the file """ path = os.path.join(self.gitdir, fname) tools.write_file(path, text, binary=False) index = self.repo.index index.add(fname) author = pygit2.Signature('Test user', '*****@*****.**') committer = author tree = index.write_tree() message = subject + '\n' + body self.repo.create_commit('HEAD', author, committer, message, tree, [self.repo.head.target])
def adjust_cfg_file(fname, adjust_cfg): """Make adjustments to a .config file Args: fname (str): Filename of .config file to change adjust_cfg (dict of str): Changes to make to .config file before building: key: str config to change, without the CONFIG_ prefix, e.g. FRED value: str change to make (C is config option without prefix): C to enable C ~C to disable C C=val to set the value of C (val must have quotes if C is a string Kconfig) """ lines = tools.read_file(fname, binary=False).splitlines() out_lines = adjust_cfg_lines(lines, adjust_cfg) out = '\n'.join(out_lines) + '\n' tools.write_file(fname, out, binary=False)
def PrepareFromLoadedData(image): """Get device tree files ready for use with a loaded image Loaded images are different from images that are being created by binman, since there is generally already an fdtmap and we read the description from that. This provides the position and size of every entry in the image with no calculation required. This function uses the same output_fdt_info[] as Prepare(). It finds the device tree files, adds a reference to the fdtmap and sets the FDT path prefix to translate from the fdtmap (where the root node is the image node) to the normal device tree (where the image node is under a /binman node). Args: images: List of images being used """ global output_fdt_info, main_dtb, fdt_path_prefix tout.info('Preparing device trees') output_fdt_info.clear() fdt_path_prefix = '' output_fdt_info['fdtmap'] = [image.fdtmap_dtb, 'u-boot.dtb'] main_dtb = None tout.info(" Found device tree type 'fdtmap' '%s'" % image.fdtmap_dtb.name) for etype, value in image.GetFdts().items(): entry, fname = value out_fname = tools.get_output_filename('%s.dtb' % entry.etype) tout.info(" Found device tree type '%s' at '%s' path '%s'" % (etype, out_fname, entry.GetPath())) entry._filename = entry.GetDefaultFilename() data = entry.ReadData() tools.write_file(out_fname, data) dtb = fdt.Fdt(out_fname) dtb.Scan() image_node = dtb.GetNode('/binman') if 'multiple-images' in image_node.props: image_node = dtb.GetNode('/binman/%s' % image.image_node) fdt_path_prefix = image_node.path output_fdt_info[etype] = [dtb, None] tout.info(" FDT path prefix '%s'" % fdt_path_prefix)
def UpdateFile(infile, outfile, start_sym, end_sym, insert): tout.notice("Creating file '%s' with data length %#x (%d) between symbols '%s' and '%s'" % (outfile, len(insert), len(insert), start_sym, end_sym)) syms = GetSymbolFileOffset(infile, [start_sym, end_sym]) if len(syms) != 2: raise ValueError("Expected two symbols '%s' and '%s': got %d: %s" % (start_sym, end_sym, len(syms), ','.join(syms.keys()))) size = syms[end_sym].offset - syms[start_sym].offset if len(insert) > size: raise ValueError("Not enough space in '%s' for data length %#x (%d); size is %#x (%d)" % (infile, len(insert), len(insert), size, size)) data = tools.read_file(infile) newdata = data[:syms[start_sym].offset] newdata += insert + tools.get_bytes(0, size - len(insert)) newdata += data[syms[end_sym].offset:] tools.write_file(outfile, newdata) tout.info('Written to offset %#x' % syms[start_sym].offset)
def _compare_expected_cbfs(self, data, cbfstool_fname): """Compare against what cbfstool creates This compares what binman creates with what cbfstool creates for what is proportedly the same thing. Args: data: CBFS created by binman cbfstool_fname: CBFS created by cbfstool """ if not self.have_cbfstool or not self.have_lz4: return expect = tools.read_file(cbfstool_fname) if expect != data: tools.write_file('/tmp/expect', expect) tools.write_file('/tmp/actual', data) print( 'diff -y <(xxd -g1 /tmp/expect) <(xxd -g1 /tmp/actual) | colordiff' ) self.fail('cbfstool produced a different result')
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.get_output_filename('mkimage.%s' % uniq) tools.write_file(input_fname, data) output_fname = tools.get_output_filename('mkimage-out.%s' % uniq) if self.mkimage.run_cmd('-d', input_fname, *self._args, output_fname) is not None: self.SetContents(tools.read_file(output_fname)) else: # Bintool is missing; just use the input data as the output self.record_missing_bintool(self.mkimage) self.SetContents(data) 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.get_output_filename('ifwi.bin') if self.ifwitool.create_ifwi(inname, outname) is None: # Bintool is missing; just create a zeroed ifwi.bin self.record_missing_bintool(self.ifwitool) self.SetContents(tools.get_bytes(0, 1024)) 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 if self.ifwitool.delete_subpart(outname, 'OBBP') is None: # Bintool is missing; just use zero data self.record_missing_bintool(self.ifwitool) self.SetContents(tools.get_bytes(0, 1024)) return True for entry in self._ifwi_entries.values(): # First get the input data and put it in a file data = entry.GetPaddedData() uniq = self.GetUniqueName() input_fname = tools.get_output_filename('input.%s' % uniq) tools.write_file(input_fname, data) # At this point we know that ifwitool is present, so we don't need # to check for None here self.ifwitool.add_subpart(outname, entry._ifwi_subpart, entry._ifwi_entry_name, input_fname, entry._ifwi_replace) self.ReadBlobContents() return True
def Prepare(images, dtb): """Get device tree files ready for use This sets up a set of device tree files that can be retrieved by GetAllFdts(). This includes U-Boot proper and any SPL device trees. Args: images: List of images being used dtb: Main dtb """ global output_fdt_info, main_dtb, fdt_path_prefix # Import these here in case libfdt.py is not available, in which case # the above help option still works. from dtoc import fdt from dtoc import fdt_util # If we are updating the DTBs we need to put these updated versions # where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb' # since it is assumed to be the one passed in with options.dt, and # was handled just above. main_dtb = dtb output_fdt_info.clear() fdt_path_prefix = '' output_fdt_info['u-boot-dtb'] = [dtb, 'u-boot.dtb'] if use_fake_dtb: for etype, fname in DTB_TYPE_FNAME.items(): output_fdt_info[etype] = [dtb, fname] else: fdt_set = {} for etype, fname in DTB_TYPE_FNAME.items(): infile = tools.get_input_filename(fname, allow_missing=True) if infile and os.path.exists(infile): fname_dtb = fdt_util.EnsureCompiled(infile) out_fname = tools.get_output_filename('%s.out' % os.path.split(fname)[1]) tools.write_file(out_fname, tools.read_file(fname_dtb)) other_dtb = fdt.FdtScan(out_fname) output_fdt_info[etype] = [other_dtb, out_fname]
def test_changes(self): """Check handling of a source file that does/doesn't need changes""" self.setup_readme() self.setup_macro() self.setup_name() # Check generating the file when changes are needed tools.write_file(self.src_file, ''' # This is taken from tbbr_config.c in ARM Trusted Firmware FIP_TYPE_LIST = [ # ToC Entry UUIDs FipType('scp-fwu-cfg', 'SCP Firmware Updater Configuration FWU SCP_BL2U', [0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44, 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), ] # end blah de blah ''', binary=False) with test_util.capture_sys_output() as (stdout, _): fip_util.main(self.args, self.src_file) self.assertIn('Needs update', stdout.getvalue()) # Check generating the file when no changes are needed tools.write_file(self.src_file, ''' # This is taken from tbbr_config.c in ARM Trusted Firmware FIP_TYPE_LIST = [ # ToC Entry UUIDs FipType('scp-fwu-cfg', 'SCP Firmware Updater Configuration FWU SCP_BL2U', [0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44, 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), FipType('ap-fwu-cfg', 'AP Firmware Updater Configuration BL2U', [0x60, 0xb3, 0xeb, 0x37, 0xc1, 0xe5, 0xea, 0x41, 0x9d, 0xf3, 0x19, 0xed, 0xa1, 0x1f, 0x68, 0x01]), ] # end blah blah''', binary=False) with test_util.capture_sys_output() as (stdout, _): fip_util.main(self.args, self.src_file) self.assertIn('is up-to-date', stdout.getvalue())
def ObtainContents(self): # If the section does not need microcode, there is nothing to do found = False for suffix in ['', '-spl', '-tpl']: name = 'u-boot%s-with-ucode-ptr' % suffix entry = self.section.FindEntryType(name) if entry and entry.target_offset: found = True if not found: self.data = b'' return True # Get the microcode from the device tree entry. If it is not available # yet, return False so we will be called later. If the section simply # doesn't exist, then we may as well return True, since we are going to # get an error anyway. for suffix in ['', '-spl', '-tpl']: name = 'u-boot%s-dtb-with-ucode' % suffix fdt_entry = self.section.FindEntryType(name) if fdt_entry: break if not fdt_entry: self.data = b'' return True if not fdt_entry.ready: return False if not fdt_entry.collate: # This binary can be empty self.data = b'' return True # Write it out to a file self._pathname = tools.get_output_filename('u-boot-ucode.bin') tools.write_file(self._pathname, fdt_entry.ucode_data) self.ReadBlobContents() return True
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.get_output_filename('vblock.%s' % uniq) input_fname = tools.get_output_filename('input.%s' % uniq) tools.write_file(input_fname, input_data) prefix = self.keydir + '/' stdout = self.futility.sign_firmware(vblock=output_fname, keyblock=prefix + self.keyblock, signprivate=prefix + self.signprivate, version=f'{self.version,}', firmware=input_fname, kernelkey=prefix + self.kernelkey, flags=f'{self.preamble_flags}') if stdout is not None: data = tools.read_file(output_fname) else: # Bintool is missing; just use 4KB of zero data self.record_missing_bintool(self.futility) data = tools.get_bytes(0, 4096) return data
def create_fiptool_image(self): """Create an image with fiptool which we can use for testing Returns: FipReader: reader for the image """ fwu = os.path.join(self._indir, 'fwu') tools.write_file(fwu, self.fwu_data) tb_fw = os.path.join(self._indir, 'tb_fw') tools.write_file(tb_fw, self.tb_fw_data) other_fw = os.path.join(self._indir, 'other_fw') tools.write_file(other_fw, self.other_fw_data) fname = tools.get_output_filename('data.fip') uuid = 'e3b78d9e-4a64-11ec-b45c-fba2b9b49788' FIPTOOL.create_new(fname, 8, 0x123, fwu, tb_fw, uuid, other_fw) return fip_util.FipReader(tools.read_file(fname))
def _Touch(fname): tools.write_file(os.path.join(base_dir, fname), b'')