aboutsummaryrefslogtreecommitdiff
path: root/tools/binman/btool/cbfstool.py
blob: 2d8559abb2b2895e4993eb41470eb1e8cba3b4de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# 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
        # Version 4.22.01
        fname, tmpdir = self.fetch_from_drive(
            '1gxNxRuJgD0Iiy9LAPCSB_0959eJCp98g')
        return fname, tmpdir