# SPDX-License-Identifier: GPL-2.0+ # Copyright 2022 Google LLC # """Bintool implementation for cbfstool cfstool provides a number of features useful with Coreboot Filesystem binaries. Documentation is at https://www.coreboot.org/CBFS Source code is at https://github.com/coreboot/coreboot/blob/master/util/cbfstool/cbfstool.c Here is the help: cbfstool: Management utility for CBFS formatted ROM images USAGE: cbfstool [-h] cbfstool FILE COMMAND [-v] [PARAMETERS]... OPTIONs: -H header_offset Do not search for header; use this offset* -T Output top-aligned memory address -u Accept short data; fill upward/from bottom -d Accept short data; fill downward/from top -F Force action -g Generate position and alignment arguments -U Unprocessed; don't decompress or make ELF -v Provide verbose output -h Display this help message COMMANDs: add [-r image,regions] -f FILE -n NAME -t TYPE [-A hash] \ [-c compression] [-b base-address | -a alignment] \ [-p padding size] [-y|--xip if TYPE is FSP] \ [-j topswap-size] (Intel CPUs only) [--ibb] Add a component -j valid size: 0x10000 0x20000 0x40000 0x80000 0x100000 add-payload [-r image,regions] -f FILE -n NAME [-A hash] \ [-c compression] [-b base-address] \ (linux specific: [-C cmdline] [-I initrd]) Add a payload to the ROM add-stage [-r image,regions] -f FILE -n NAME [-A hash] \ [-c compression] [-b base] [-S section-to-ignore] \ [-a alignment] [-y|--xip] [-P page-size] [--ibb] Add a stage to the ROM add-flat-binary [-r image,regions] -f FILE -n NAME \ [-A hash] -l load-address -e entry-point \ [-c compression] [-b base] Add a 32bit flat mode binary add-int [-r image,regions] -i INTEGER -n NAME [-b base] Add a raw 64-bit integer value add-master-header [-r image,regions] \ [-j topswap-size] (Intel CPUs only) Add a legacy CBFS master header remove [-r image,regions] -n NAME Remove a component compact -r image,regions Defragment CBFS image. copy -r image,regions -R source-region Create a copy (duplicate) cbfs instance in fmap create -m ARCH -s size [-b bootblock offset] \ [-o CBFS offset] [-H header offset] [-B bootblock] Create a legacy ROM file with CBFS master header* create -M flashmap [-r list,of,regions,containing,cbfses] Create a new-style partitioned firmware image locate [-r image,regions] -f FILE -n NAME [-P page-size] \ [-a align] [-T] Find a place for a file of that size layout [-w] List mutable (or, with -w, readable) image regions print [-r image,regions] Show the contents of the ROM extract [-r image,regions] [-m ARCH] -n NAME -f FILE [-U] Extracts a file from ROM write [-F] -r image,regions -f file [-u | -d] [-i int] Write file into same-size [or larger] raw region read [-r fmap-region] -f file Extract raw region contents into binary file truncate [-r fmap-region] Truncate CBFS and print new size on stdout expand [-r fmap-region] Expand CBFS to span entire region OFFSETs: Numbers accompanying -b, -H, and -o switches* may be provided in two possible formats: if their value is greater than 0x80000000, they are interpreted as a top-aligned x86 memory address; otherwise, they are treated as an offset into flash. ARCHes: arm64, arm, mips, ppc64, power8, riscv, x86, unknown TYPEs: bootblock, cbfs header, stage, simple elf, fit, optionrom, bootsplash, raw, vsa, mbi, microcode, fsp, mrc, cmos_default, cmos_layout, spd, mrc_cache, mma, efi, struct, deleted, null * Note that these actions and switches are only valid when working with legacy images whose structure is described primarily by a CBFS master header. New-style images, in contrast, exclusively make use of an FMAP to describe their layout: this must minimally contain an 'FMAP' section specifying the location of this FMAP itself and a 'COREBOOT' section describing the primary CBFS. It should also be noted that, when working with such images, the -F and -r switches default to 'COREBOOT' for convenience, and both the -b switch to CBFS operations and the output of the locate action become relative to the selected CBFS region's lowest address. The one exception to this rule is the top-aligned address, which is always relative to the end of the entire image rather than relative to the local region; this is true for for both input (sufficiently large) and output (-T) data. Since binman has a native implementation of CBFS (see cbfs_util.py), we don't actually need this tool, except for sanity checks in the tests. """ from binman import bintool class Bintoolcbfstool(bintool.Bintool): """Coreboot filesystem (CBFS) tool This bintool supports creating new CBFS images and adding files to an existing image, i.e. the features needed by binman. It also supports fetching a binary cbfstool, since building it from source is fairly slow. Documentation about CBFS is at https://www.coreboot.org/CBFS """ def __init__(self, name): super().__init__(name, 'Manipulate CBFS files') def create_new(self, cbfs_fname, size, arch='x86'): """Create a new CBFS Args: cbfs_fname (str): Filename of CBFS to create size (int): Size of CBFS in bytes arch (str): Architecture for which this CBFS is intended Returns: str: Tool output """ args = [cbfs_fname, 'create', '-s', f'{size:#x}', '-m', arch] return self.run_cmd(*args) # pylint: disable=R0913 def add_raw(self, cbfs_fname, name, fname, compress=None, base=None): """Add a raw file to the CBFS Args: cbfs_fname (str): Filename of CBFS to create name (str): Name to use inside the CBFS fname (str): Filename of file to add compress (str): Compression to use (cbfs_util.COMPRESS_NAMES) or None for None base (int): Address to place the file, or None for anywhere Returns: str: Tool output """ args = [cbfs_fname, 'add', '-n', name, '-t', 'raw', '-f', fname, '-c', compress or 'none'] if base: args += ['-b', f'{base:#x}'] return self.run_cmd(*args) def add_stage(self, cbfs_fname, name, fname): """Add a stage file to the CBFS Args: cbfs_fname (str): Filename of CBFS to create name (str): Name to use inside the CBFS fname (str): Filename of file to add Returns: str: Tool output """ args = [cbfs_fname, 'add-stage', '-n', name, '-f', fname ] return self.run_cmd(*args) def fail(self): """Run cbfstool with invalid arguments to check it reports failure This is really just a sanity check Returns: CommandResult: Result from running the bad command """ args = ['missing-file', 'bad-command'] return self.run_cmd_result(*args) def fetch(self, method): """Fetch handler for cbfstool This installs cbfstool by downloading from Google Drive. Args: method (FETCH_...): Method to use Returns: True if the file was fetched and now installed, None if a method other than FETCH_BIN was requested Raises: Valuerror: Fetching could not be completed """ if method != bintool.FETCH_BIN: return None fname, tmpdir = self.fetch_from_drive( '1IOnE0Qvy97d-0WOCwF64xBGpKSY2sMtJ') return fname, tmpdir