220 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			220 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Python
		
	
	
	
| # 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
 |