Simon Glass | b8dbca9 | 2022-01-09 20:13:52 -0700 | [diff] [blame] | 1 | # SPDX-License-Identifier: GPL-2.0+ |
| 2 | # Copyright 2022 Google LLC |
| 3 | # |
| 4 | """Bintool implementation for cbfstool |
| 5 | |
| 6 | cfstool provides a number of features useful with Coreboot Filesystem binaries. |
| 7 | |
| 8 | Documentation is at https://www.coreboot.org/CBFS |
| 9 | |
| 10 | Source code is at https://github.com/coreboot/coreboot/blob/master/util/cbfstool/cbfstool.c |
| 11 | |
| 12 | Here is the help: |
| 13 | |
| 14 | cbfstool: Management utility for CBFS formatted ROM images |
| 15 | |
| 16 | USAGE: |
| 17 | cbfstool [-h] |
| 18 | cbfstool FILE COMMAND [-v] [PARAMETERS]... |
| 19 | |
| 20 | OPTIONs: |
| 21 | -H header_offset Do not search for header; use this offset* |
| 22 | -T Output top-aligned memory address |
| 23 | -u Accept short data; fill upward/from bottom |
| 24 | -d Accept short data; fill downward/from top |
| 25 | -F Force action |
| 26 | -g Generate position and alignment arguments |
| 27 | -U Unprocessed; don't decompress or make ELF |
| 28 | -v Provide verbose output |
| 29 | -h Display this help message |
| 30 | |
| 31 | COMMANDs: |
| 32 | add [-r image,regions] -f FILE -n NAME -t TYPE [-A hash] \ |
| 33 | [-c compression] [-b base-address | -a alignment] \ |
| 34 | [-p padding size] [-y|--xip if TYPE is FSP] \ |
| 35 | [-j topswap-size] (Intel CPUs only) [--ibb] |
| 36 | Add a component |
| 37 | -j valid size: 0x10000 0x20000 0x40000 0x80000 0x100000 |
| 38 | add-payload [-r image,regions] -f FILE -n NAME [-A hash] \ |
| 39 | [-c compression] [-b base-address] \ |
| 40 | (linux specific: [-C cmdline] [-I initrd]) |
| 41 | Add a payload to the ROM |
| 42 | add-stage [-r image,regions] -f FILE -n NAME [-A hash] \ |
| 43 | [-c compression] [-b base] [-S section-to-ignore] \ |
| 44 | [-a alignment] [-y|--xip] [-P page-size] [--ibb] |
| 45 | Add a stage to the ROM |
| 46 | add-flat-binary [-r image,regions] -f FILE -n NAME \ |
| 47 | [-A hash] -l load-address -e entry-point \ |
| 48 | [-c compression] [-b base] |
| 49 | Add a 32bit flat mode binary |
| 50 | add-int [-r image,regions] -i INTEGER -n NAME [-b base] |
| 51 | Add a raw 64-bit integer value |
| 52 | add-master-header [-r image,regions] \ |
| 53 | [-j topswap-size] (Intel CPUs only) |
| 54 | Add a legacy CBFS master header |
| 55 | remove [-r image,regions] -n NAME |
| 56 | Remove a component |
| 57 | compact -r image,regions |
| 58 | Defragment CBFS image. |
| 59 | copy -r image,regions -R source-region |
| 60 | Create a copy (duplicate) cbfs instance in fmap |
| 61 | create -m ARCH -s size [-b bootblock offset] \ |
| 62 | [-o CBFS offset] [-H header offset] [-B bootblock] |
| 63 | Create a legacy ROM file with CBFS master header* |
| 64 | create -M flashmap [-r list,of,regions,containing,cbfses] |
| 65 | Create a new-style partitioned firmware image |
| 66 | locate [-r image,regions] -f FILE -n NAME [-P page-size] \ |
| 67 | [-a align] [-T] |
| 68 | Find a place for a file of that size |
| 69 | layout [-w] |
| 70 | List mutable (or, with -w, readable) image regions |
| 71 | print [-r image,regions] |
| 72 | Show the contents of the ROM |
| 73 | extract [-r image,regions] [-m ARCH] -n NAME -f FILE [-U] |
| 74 | Extracts a file from ROM |
| 75 | write [-F] -r image,regions -f file [-u | -d] [-i int] |
| 76 | Write file into same-size [or larger] raw region |
| 77 | read [-r fmap-region] -f file |
| 78 | Extract raw region contents into binary file |
| 79 | truncate [-r fmap-region] |
| 80 | Truncate CBFS and print new size on stdout |
| 81 | expand [-r fmap-region] |
| 82 | Expand CBFS to span entire region |
| 83 | OFFSETs: |
| 84 | Numbers accompanying -b, -H, and -o switches* may be provided |
| 85 | in two possible formats: if their value is greater than |
| 86 | 0x80000000, they are interpreted as a top-aligned x86 memory |
| 87 | address; otherwise, they are treated as an offset into flash. |
| 88 | ARCHes: |
| 89 | arm64, arm, mips, ppc64, power8, riscv, x86, unknown |
| 90 | TYPEs: |
| 91 | bootblock, cbfs header, stage, simple elf, fit, optionrom, bootsplash, raw, |
| 92 | vsa, mbi, microcode, fsp, mrc, cmos_default, cmos_layout, spd, |
| 93 | mrc_cache, mma, efi, struct, deleted, null |
| 94 | |
| 95 | * Note that these actions and switches are only valid when |
| 96 | working with legacy images whose structure is described |
| 97 | primarily by a CBFS master header. New-style images, in |
| 98 | contrast, exclusively make use of an FMAP to describe their |
| 99 | layout: this must minimally contain an 'FMAP' section |
| 100 | specifying the location of this FMAP itself and a 'COREBOOT' |
| 101 | section describing the primary CBFS. It should also be noted |
| 102 | that, when working with such images, the -F and -r switches |
| 103 | default to 'COREBOOT' for convenience, and both the -b switch to |
| 104 | CBFS operations and the output of the locate action become |
| 105 | relative to the selected CBFS region's lowest address. |
| 106 | The one exception to this rule is the top-aligned address, |
| 107 | which is always relative to the end of the entire image |
| 108 | rather than relative to the local region; this is true for |
| 109 | for both input (sufficiently large) and output (-T) data. |
| 110 | |
| 111 | |
| 112 | Since binman has a native implementation of CBFS (see cbfs_util.py), we don't |
| 113 | actually need this tool, except for sanity checks in the tests. |
| 114 | """ |
| 115 | |
| 116 | from binman import bintool |
| 117 | |
| 118 | class Bintoolcbfstool(bintool.Bintool): |
| 119 | """Coreboot filesystem (CBFS) tool |
| 120 | |
| 121 | This bintool supports creating new CBFS images and adding files to an |
| 122 | existing image, i.e. the features needed by binman. |
| 123 | |
| 124 | It also supports fetching a binary cbfstool, since building it from source |
| 125 | is fairly slow. |
| 126 | |
| 127 | Documentation about CBFS is at https://www.coreboot.org/CBFS |
| 128 | """ |
| 129 | def __init__(self, name): |
| 130 | super().__init__(name, 'Manipulate CBFS files') |
| 131 | |
| 132 | def create_new(self, cbfs_fname, size, arch='x86'): |
| 133 | """Create a new CBFS |
| 134 | |
| 135 | Args: |
| 136 | cbfs_fname (str): Filename of CBFS to create |
| 137 | size (int): Size of CBFS in bytes |
| 138 | arch (str): Architecture for which this CBFS is intended |
| 139 | |
| 140 | Returns: |
| 141 | str: Tool output |
| 142 | """ |
| 143 | args = [cbfs_fname, 'create', '-s', f'{size:#x}', '-m', arch] |
| 144 | return self.run_cmd(*args) |
| 145 | |
| 146 | # pylint: disable=R0913 |
| 147 | def add_raw(self, cbfs_fname, name, fname, compress=None, base=None): |
| 148 | """Add a raw file to the CBFS |
| 149 | |
| 150 | Args: |
| 151 | cbfs_fname (str): Filename of CBFS to create |
| 152 | name (str): Name to use inside the CBFS |
| 153 | fname (str): Filename of file to add |
| 154 | compress (str): Compression to use (cbfs_util.COMPRESS_NAMES) or |
| 155 | None for None |
| 156 | base (int): Address to place the file, or None for anywhere |
| 157 | |
| 158 | Returns: |
| 159 | str: Tool output |
| 160 | """ |
| 161 | args = [cbfs_fname, |
| 162 | 'add', |
| 163 | '-n', name, |
| 164 | '-t', 'raw', |
| 165 | '-f', fname, |
| 166 | '-c', compress or 'none'] |
| 167 | if base: |
| 168 | args += ['-b', f'{base:#x}'] |
| 169 | return self.run_cmd(*args) |
| 170 | |
| 171 | def add_stage(self, cbfs_fname, name, fname): |
| 172 | """Add a stage file to the CBFS |
| 173 | |
| 174 | Args: |
| 175 | cbfs_fname (str): Filename of CBFS to create |
| 176 | name (str): Name to use inside the CBFS |
| 177 | fname (str): Filename of file to add |
| 178 | |
| 179 | Returns: |
| 180 | str: Tool output |
| 181 | """ |
| 182 | args = [cbfs_fname, |
| 183 | 'add-stage', |
| 184 | '-n', name, |
| 185 | '-f', fname |
| 186 | ] |
| 187 | return self.run_cmd(*args) |
| 188 | |
| 189 | def fail(self): |
| 190 | """Run cbfstool with invalid arguments to check it reports failure |
| 191 | |
| 192 | This is really just a sanity check |
| 193 | |
| 194 | Returns: |
| 195 | CommandResult: Result from running the bad command |
| 196 | """ |
| 197 | args = ['missing-file', 'bad-command'] |
| 198 | return self.run_cmd_result(*args) |
| 199 | |
| 200 | def fetch(self, method): |
| 201 | """Fetch handler for cbfstool |
| 202 | |
| 203 | This installs cbfstool by downloading from Google Drive. |
| 204 | |
| 205 | Args: |
| 206 | method (FETCH_...): Method to use |
| 207 | |
| 208 | Returns: |
| 209 | True if the file was fetched and now installed, None if a method |
| 210 | other than FETCH_BIN was requested |
| 211 | |
| 212 | Raises: |
| 213 | Valuerror: Fetching could not be completed |
| 214 | """ |
| 215 | if method != bintool.FETCH_BIN: |
| 216 | return None |
| 217 | fname, tmpdir = self.fetch_from_drive( |
| 218 | '1IOnE0Qvy97d-0WOCwF64xBGpKSY2sMtJ') |
| 219 | return fname, tmpdir |