1 /* cbfstool, CLI utility for creating rmodules */
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; version 2 of the License.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
20 #include "cbfs_image.h"
21 #include "partitioned_file.h"
24 /* Global variables */
25 partitioned_file_t
*image_file
;
27 static const char *optstring
= "H:j:f:r:d:t:n:s:cAaDvh?";
28 static struct option long_options
[] = {
29 {"file", required_argument
, 0, 'f' },
30 {"region", required_argument
, 0, 'r' },
31 {"add-cbfs-entry", no_argument
, 0, 'a' },
32 {"add-region", no_argument
, 0, 'A' },
33 {"del-entry", required_argument
, 0, 'd' },
34 {"clear-table", no_argument
, 0, 'c' },
35 {"fit-type", required_argument
, 0, 't' },
36 {"cbfs-filename", required_argument
, 0, 'n' },
37 {"max-table-size", required_argument
, 0, 's' },
38 {"topswap-size", required_argument
, 0, 'j' },
39 {"dump", no_argument
, 0, 'D' },
40 {"verbose", no_argument
, 0, 'v' },
41 {"help", no_argument
, 0, 'h' },
42 {"header-offset", required_argument
, 0, 'H' },
46 static void usage(const char *name
)
49 "ifittool: utility for modifying Intel Firmware Interface Table\n\n"
50 "USAGE: %s [-h] [-H] [-v] [-D] [-c] <-f|--file name> <-s|--max-table-size size> <-r|--region fmap region> OPERATION\n"
52 "\t\t-a|--add-entry : Add a CBFS file as new entry to FIT\n"
53 "\t\t-A|--add-region : Add region as new entry to FIT (for microcodes)\n"
54 "\t\t-d|--del-entry number : Delete existing <number> entry\n"
55 "\t\t-t|--fit-type : Type of new entry\n"
56 "\t\t-n|--name : The CBFS filename or region to add to table\n"
57 "\tOPTIONAL ARGUMENTS:\n"
58 "\t\t-h|--help : Display this text\n"
59 "\t\t-H|--header-offset : Do not search for header, use this offset\n"
60 "\t\t-v|--verbose : Be verbose\n"
61 "\t\t-D|--dump : Dump FIT table (at end of operation)\n"
62 "\t\t-c|--clear-table : Remove all existing entries (do not update)\n"
63 "\t\t-j|--topswap-size : Use second FIT table if non zero\n"
64 "\tREQUIRED ARGUMENTS:\n"
65 "\t\t-f|--file name : The file containing the CBFS\n"
66 "\t\t-s|--max-table-size : The number of possible FIT entries in table\n"
67 "\t\t-r|--region : The FMAP region to operate on\n"
71 static int is_valid_topswap(size_t topswap_size
)
73 switch (topswap_size
) {
81 ERROR("Invalid topswap_size %zd\n", topswap_size
);
82 ERROR("topswap can be 64K|128K|256K|512K|1M\n");
89 * Converts between offsets from the start of the specified image region and
90 * "top-aligned" offsets from the top of the entire boot media. See comment
91 * below for convert_to_from_top_aligned() about forming addresses.
93 static unsigned int convert_to_from_absolute_top_aligned(
94 const struct buffer
*region
, unsigned int offset
)
98 size_t image_size
= partitioned_file_total_size(image_file
);
100 return image_size
- region
->offset
- offset
;
104 * Converts between offsets from the start of the specified image region and
105 * "top-aligned" offsets from the top of the image region. Works in either
106 * direction: pass in one type of offset and receive the other type.
107 * N.B. A top-aligned offset is always a positive number, and should not be
108 * confused with a top-aligned *address*, which is its arithmetic inverse. */
109 static unsigned int convert_to_from_top_aligned(const struct buffer
*region
,
114 /* Cover the situation where a negative base address is given by the
115 * user. Callers of this function negate it, so it'll be a positive
116 * number smaller than the region.
118 if ((offset
> 0) && (offset
< region
->size
))
119 return region
->size
- offset
;
121 return convert_to_from_absolute_top_aligned(region
, offset
);
125 * Get a pointer from an offset. This function assumes the ROM is located
126 * in the host address space at [4G - romsize -> 4G). It also assume all
127 * pointers have values within this address range.
129 static inline uint32_t offset_to_ptr(fit_offset_converter_t helper
,
130 const struct buffer
*region
, int offset
)
132 return -helper(region
, offset
);
143 int main(int argc
, char *argv
[])
146 const char *input_file
= NULL
;
147 const char *name
= NULL
;
148 const char *region_name
= NULL
;
149 enum fit_operation op
= NO_OP
;
150 bool dump
= false, clear_table
= false;
151 size_t max_table_size
= 0;
152 size_t table_entry
= 0;
154 size_t topswap_size
= 0;
155 enum fit_type fit_type
= 0;
156 uint32_t headeroffset
= ~0u;
169 c
= getopt_long(argc
, argv
, optstring
, long_options
, &optindex
);
180 ERROR("specified multiple actions at once\n");
188 ERROR("specified multiple actions at once\n");
196 ERROR("specified multiple actions at once\n");
201 addr
= atoll(optarg
);
208 ERROR("specified multiple actions at once\n");
213 table_entry
= atoi(optarg
);
222 headeroffset
= strtoul(optarg
, &suffix
, 0);
223 if (!*optarg
|| (suffix
&& *suffix
)) {
224 ERROR("Invalid header offset '%s'.\n", optarg
);
229 topswap_size
= strtol(optarg
, NULL
, 0);
230 if (!is_valid_topswap(topswap_size
))
237 region_name
= optarg
;
240 max_table_size
= atoi(optarg
);
243 fit_type
= atoi(optarg
);
253 if (input_file
== NULL
) {
254 ERROR("No input file given\n");
259 if (op
== ADD_CBFS_OP
|| op
== ADD_REGI_OP
) {
261 ERROR("Adding FIT entry, but no type given\n");
264 } else if (name
== NULL
) {
265 ERROR("Adding FIT entry, but no name set\n");
268 } else if (max_table_size
== 0) {
269 ERROR("Maximum table size not given\n");
274 if (op
== ADD_ADDR_OP
) {
276 ERROR("Adding FIT entry, but no type given\n");
279 } else if (max_table_size
== 0) {
280 ERROR("Maximum table size not given\n");
287 ERROR("Region not given\n");
292 image_file
= partitioned_file_reopen(input_file
,
293 op
!= NO_OP
|| clear_table
);
295 struct buffer image_region
;
297 if (!partitioned_file_read_region(&image_region
, image_file
,
299 partitioned_file_close(image_file
);
300 ERROR("The image will be left unmodified.\n");
304 struct buffer bootblock
;
305 // The bootblock is part of the CBFS on x86
306 buffer_clone(&bootblock
, &image_region
);
308 struct cbfs_image image
;
309 if (cbfs_image_from_buffer(&image
, &image_region
, headeroffset
)) {
310 partitioned_file_close(image_file
);
314 struct fit_table
*fit
= fit_get_table(&bootblock
,
315 convert_to_from_top_aligned
,
318 partitioned_file_close(image_file
);
319 ERROR("FIT not found.\n");
324 if (fit_clear_table(fit
)) {
325 partitioned_file_close(image_file
);
326 ERROR("Failed to clear table.\n");
334 struct buffer region
;
336 if (partitioned_file_read_region(®ion
, image_file
, name
)) {
337 addr
= -convert_to_from_top_aligned(®ion
, 0);
339 partitioned_file_close(image_file
);
343 if (fit_add_entry(fit
, addr
, 0, fit_type
, max_table_size
)) {
344 partitioned_file_close(image_file
);
345 ERROR("Adding type %u FIT entry\n", fit_type
);
352 if (fit_type
== FIT_TYPE_MICROCODE
) {
353 if (fit_add_microcode_file(fit
, &image
, name
,
354 convert_to_from_top_aligned
,
359 uint32_t offset
, len
;
360 struct cbfs_file
*cbfs_file
;
362 cbfs_file
= cbfs_get_entry(&image
, name
);
364 partitioned_file_close(image_file
);
365 ERROR("%s not found in CBFS.\n", name
);
369 len
= ntohl(cbfs_file
->len
);
370 offset
= offset_to_ptr(convert_to_from_top_aligned
,
372 cbfs_get_entry_addr(&image
, cbfs_file
) +
373 ntohl(cbfs_file
->offset
));
376 if (fit_add_entry(fit
, offset
, len
, fit_type
,
378 partitioned_file_close(image_file
);
379 ERROR("Adding type %u FIT entry\n", fit_type
);
387 if (fit_add_entry(fit
, addr
, 0, fit_type
, max_table_size
)) {
388 partitioned_file_close(image_file
);
389 ERROR("Adding type %u FIT entry\n", fit_type
);
396 if (fit_delete_entry(fit
, table_entry
)) {
397 partitioned_file_close(image_file
);
398 ERROR("Deleting FIT entry %zu failed\n", table_entry
);
408 if (op
!= NO_OP
|| clear_table
) {
409 if (!partitioned_file_write_region(image_file
, &bootblock
)) {
410 ERROR("Failed to write changes to disk.\n");
411 partitioned_file_close(image_file
);
418 partitioned_file_close(image_file
);
423 partitioned_file_close(image_file
);