blob: 41df15745a70afefc17a49b25b9396dc6692c353 [file] [log] [blame]
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +00001/*
Patrick Georgib7b56dd82009-09-14 13:29:27 +00002 * cbfstool, CLI utility for CBFS file manipulation
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +00003 *
Patrick Georgib7b56dd82009-09-14 13:29:27 +00004 * Copyright (C) 2009 coresystems GmbH
5 * written by Patrick Georgi <patrick.georgi@coresystems.de>
David Hendricks90ca3b62012-11-16 14:48:22 -08006 * Copyright (C) 2012 Google, Inc.
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +00007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
20 */
21
Patrick Georgib7b56dd82009-09-14 13:29:27 +000022#include <stdio.h>
Stefan Reinauera1e48242011-10-21 14:24:57 -070023#include <stdlib.h>
Stefan Reinauer336daa72009-12-21 15:09:01 +000024#include <string.h>
Stefan Reinauera1e48242011-10-21 14:24:57 -070025#include <ctype.h>
Stefan Reinauer63217582012-10-29 16:52:36 -070026#include <unistd.h>
27#include <getopt.h>
Patrick Georgib7b56dd82009-09-14 13:29:27 +000028#include "common.h"
29#include "cbfs.h"
Hung-Te Lin3bb035b2013-01-29 02:15:49 +080030#include "cbfs_image.h"
Aaron Durbin6b0d0d62012-12-14 17:16:21 -060031#include "fit.h"
Ronald G. Minnich5d01ec02009-03-31 11:57:36 +000032
Stefan Reinauer3fec29c2009-09-22 15:58:19 +000033struct command {
Stefan Reinauer3fec29c2009-09-22 15:58:19 +000034 const char *name;
Stefan Reinauer63217582012-10-29 16:52:36 -070035 const char *optstring;
36 int (*function) (void);
Stefan Reinauer3fec29c2009-09-22 15:58:19 +000037};
38
Hung-Te Lind1739622013-01-28 14:23:49 +080039static struct param {
40 char *cbfs_name;
41 char *name;
42 char *filename;
43 char *bootblock;
Furquan Shaikh405304a2014-10-30 11:44:20 -070044 char *ignore_section;
Peter Stuge3bfd5b82013-07-09 19:39:13 +020045 uint64_t u64val;
Hung-Te Lind1739622013-01-28 14:23:49 +080046 uint32_t type;
47 uint32_t baseaddress;
Hung-Te Linf56c73f2013-01-29 09:45:12 +080048 uint32_t baseaddress_assigned;
Hung-Te Lind1739622013-01-28 14:23:49 +080049 uint32_t loadaddress;
Hung-Te Linf56c73f2013-01-29 09:45:12 +080050 uint32_t headeroffset;
51 uint32_t headeroffset_assigned;
Hung-Te Lind1739622013-01-28 14:23:49 +080052 uint32_t entrypoint;
53 uint32_t size;
54 uint32_t alignment;
Hung-Te Line9198372013-03-19 12:17:12 +080055 uint32_t pagesize;
Hung-Te Lind1739622013-01-28 14:23:49 +080056 uint32_t offset;
Hung-Te Lin215d1d72013-01-29 03:46:02 +080057 uint32_t top_aligned;
Alexandru Gagniuc35850ae2014-02-02 22:37:28 -060058 uint32_t arch;
Aaron Durbin6b0d0d62012-12-14 17:16:21 -060059 int fit_empty_entries;
Hung-Te Lind1739622013-01-28 14:23:49 +080060 comp_algo algo;
Patrick Georgide36d332013-08-27 20:22:21 +020061 /* for linux payloads */
62 char *initrd;
63 char *cmdline;
Hung-Te Lind1739622013-01-28 14:23:49 +080064} param = {
65 /* All variables not listed are initialized as zero. */
Alexandru Gagniuc35850ae2014-02-02 22:37:28 -060066 .arch = CBFS_ARCHITECTURE_UNKNOWN,
Hung-Te Lind1739622013-01-28 14:23:49 +080067 .algo = CBFS_COMPRESS_NONE,
68};
Stefan Reinauer63217582012-10-29 16:52:36 -070069
Hung-Te Linc13e4bf2013-01-29 15:22:11 +080070typedef int (*convert_buffer_t)(struct buffer *buffer, uint32_t *offset);
Stefan Reinauer63217582012-10-29 16:52:36 -070071
Peter Stuge3bfd5b82013-07-09 19:39:13 +020072static int cbfs_add_integer_component(const char *cbfs_name,
73 const char *name,
74 uint64_t u64val,
75 uint32_t offset) {
76 struct cbfs_image image;
77 struct buffer buffer;
78 int i, ret = 1;
79
80 if (!name) {
81 ERROR("You need to specify -n/--name.\n");
82 return 1;
83 }
84
85 if (buffer_create(&buffer, 8, name) != 0)
86 return 1;
87
88 for (i = 0; i < 8; i++)
89 buffer.data[i] = (u64val >> i*8) & 0xff;
90
91 if (cbfs_image_from_file(&image, cbfs_name) != 0) {
92 ERROR("Could not load ROM image '%s'.\n", cbfs_name);
93 buffer_delete(&buffer);
94 return 1;
95 }
96
97 if (cbfs_get_entry(&image, name)) {
98 ERROR("'%s' already in ROM image.\n", name);
99 goto done;
100 }
101
102 if (cbfs_add_entry(&image, &buffer, name, CBFS_COMPONENT_RAW, param.baseaddress) != 0) {
103 ERROR("Failed to add %llu into ROM image as '%s'.\n", (long long unsigned)u64val, name);
104 goto done;
105 }
106
107 if (cbfs_image_write_file(&image, cbfs_name) == 0)
108 ret = 0;
109
110done:
111 buffer_delete(&buffer);
112 cbfs_image_delete(&image);
113 return ret;
114}
115
Hung-Te Lin5f3eb262013-01-29 10:24:00 +0800116static int cbfs_add_component(const char *cbfs_name,
117 const char *filename,
118 const char *name,
119 uint32_t type,
120 uint32_t offset,
121 convert_buffer_t convert) {
122 struct cbfs_image image;
123 struct buffer buffer;
124
125 if (!filename) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800126 ERROR("You need to specify -f/--filename.\n");
Stefan Reinauer63217582012-10-29 16:52:36 -0700127 return 1;
128 }
129
Hung-Te Lin5f3eb262013-01-29 10:24:00 +0800130 if (!name) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800131 ERROR("You need to specify -n/--name.\n");
Stefan Reinauer63217582012-10-29 16:52:36 -0700132 return 1;
133 }
134
Hung-Te Lin5f3eb262013-01-29 10:24:00 +0800135 if (type == 0) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800136 ERROR("You need to specify a valid -t/--type.\n");
Stefan Reinauer63217582012-10-29 16:52:36 -0700137 return 1;
138 }
139
Stefan Reinauer8f50e532013-11-13 14:34:57 -0800140 if (cbfs_image_from_file(&image, cbfs_name) != 0) {
141 ERROR("Could not load ROM image '%s'.\n", cbfs_name);
142 return 1;
143 }
144
Hung-Te Lin5f3eb262013-01-29 10:24:00 +0800145 if (buffer_from_file(&buffer, filename) != 0) {
146 ERROR("Could not load file '%s'.\n", filename);
Stefan Reinauer8f50e532013-11-13 14:34:57 -0800147 cbfs_image_delete(&image);
Stefan Reinauer63217582012-10-29 16:52:36 -0700148 return 1;
149 }
150
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800151 if (convert && convert(&buffer, &offset) != 0) {
Hung-Te Lin5f3eb262013-01-29 10:24:00 +0800152 ERROR("Failed to parse file '%s'.\n", filename);
153 buffer_delete(&buffer);
Stefan Reinauer8f50e532013-11-13 14:34:57 -0800154 cbfs_image_delete(&image);
Patrick Georgi56f5fb72009-09-30 11:21:18 +0000155 return 1;
Stefan Reinauerfbadc492011-10-14 12:44:14 -0700156 }
Stefan Reinauer63217582012-10-29 16:52:36 -0700157
Hung-Te Lin5f3eb262013-01-29 10:24:00 +0800158 if (cbfs_get_entry(&image, name)) {
159 ERROR("'%s' already in ROM image.\n", name);
160 buffer_delete(&buffer);
161 cbfs_image_delete(&image);
162 return 1;
163 }
164
165 if (cbfs_add_entry(&image, &buffer, name, type, offset) != 0) {
166 ERROR("Failed to add '%s' into ROM image.\n", filename);
167 buffer_delete(&buffer);
168 cbfs_image_delete(&image);
169 return 1;
170 }
171
172 if (cbfs_image_write_file(&image, cbfs_name) != 0) {
173 buffer_delete(&buffer);
174 cbfs_image_delete(&image);
175 return 1;
176 }
177
178 buffer_delete(&buffer);
179 cbfs_image_delete(&image);
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000180 return 0;
181}
182
Alexandru Gagniuc35850ae2014-02-02 22:37:28 -0600183static int cbfstool_convert_mkstage(struct buffer *buffer, uint32_t *offset)
184{
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800185 struct buffer output;
Alexandru Gagniuc35850ae2014-02-02 22:37:28 -0600186 int ret;
187 ret = parse_elf_to_stage(buffer, &output, param.arch, param.algo,
Furquan Shaikh405304a2014-10-30 11:44:20 -0700188 offset, param.ignore_section);
Alexandru Gagniuc35850ae2014-02-02 22:37:28 -0600189 if (ret != 0)
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800190 return -1;
191 buffer_delete(buffer);
192 // direct assign, no dupe.
193 memcpy(buffer, &output, sizeof(*buffer));
194 return 0;
195}
196
197static int cbfstool_convert_mkpayload(struct buffer *buffer, uint32_t *offset) {
198 struct buffer output;
Stefan Reinauer543a6822013-02-04 15:39:13 -0800199 int ret;
200 /* per default, try and see if payload is an ELF binary */
Alexandru Gagniuc35850ae2014-02-02 22:37:28 -0600201 ret = parse_elf_to_payload(buffer, &output, param.arch, param.algo);
Stefan Reinauer543a6822013-02-04 15:39:13 -0800202
203 /* If it's not an ELF, see if it's a UEFI FV */
204 if (ret != 0)
205 ret = parse_fv_to_payload(buffer, &output, param.algo);
206
Patrick Georgide36d332013-08-27 20:22:21 +0200207 /* If it's neither ELF nor UEFI Fv, try bzImage */
208 if (ret != 0)
209 ret = parse_bzImage_to_payload(buffer, &output,
210 param.initrd, param.cmdline, param.algo);
211
Stefan Reinauer543a6822013-02-04 15:39:13 -0800212 /* Not a supported payload type */
213 if (ret != 0) {
214 ERROR("Not a supported payload type (ELF / FV).\n");
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800215 return -1;
Stefan Reinauer543a6822013-02-04 15:39:13 -0800216 }
217
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800218 buffer_delete(buffer);
219 // direct assign, no dupe.
220 memcpy(buffer, &output, sizeof(*buffer));
221 return 0;
222}
223
224static int cbfstool_convert_mkflatpayload(struct buffer *buffer,
225 uint32_t *offset) {
226 struct buffer output;
227 if (parse_flat_binary_to_payload(buffer, &output,
228 param.loadaddress,
229 param.entrypoint,
230 param.algo) != 0) {
231 return -1;
232 }
233 buffer_delete(buffer);
234 // direct assign, no dupe.
235 memcpy(buffer, &output, sizeof(*buffer));
236 return 0;
237}
238
239
Hung-Te Lin5f3eb262013-01-29 10:24:00 +0800240static int cbfs_add(void)
241{
242 return cbfs_add_component(param.cbfs_name,
243 param.filename,
244 param.name,
245 param.type,
246 param.baseaddress,
247 NULL);
248}
249
Stefan Reinauer63217582012-10-29 16:52:36 -0700250static int cbfs_add_stage(void)
Stefan Reinauer20848ee2012-10-22 16:04:13 -0700251{
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800252 return cbfs_add_component(param.cbfs_name,
253 param.filename,
254 param.name,
255 CBFS_COMPONENT_STAGE,
256 param.baseaddress,
257 cbfstool_convert_mkstage);
258}
Stefan Reinauer20848ee2012-10-22 16:04:13 -0700259
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800260static int cbfs_add_payload(void)
261{
262 return cbfs_add_component(param.cbfs_name,
263 param.filename,
264 param.name,
265 CBFS_COMPONENT_PAYLOAD,
266 param.baseaddress,
267 cbfstool_convert_mkpayload);
Stefan Reinauer63217582012-10-29 16:52:36 -0700268}
269
270static int cbfs_add_flat_binary(void)
271{
Hung-Te Lind1739622013-01-28 14:23:49 +0800272 if (param.loadaddress == 0) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800273 ERROR("You need to specify a valid "
Stefan Reinauer63217582012-10-29 16:52:36 -0700274 "-l/--load-address.\n");
275 return 1;
276 }
Hung-Te Lind1739622013-01-28 14:23:49 +0800277 if (param.entrypoint == 0) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800278 ERROR("You need to specify a valid "
Stefan Reinauer63217582012-10-29 16:52:36 -0700279 "-e/--entry-point.\n");
280 return 1;
281 }
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800282 return cbfs_add_component(param.cbfs_name,
283 param.filename,
284 param.name,
285 CBFS_COMPONENT_PAYLOAD,
286 param.baseaddress,
287 cbfstool_convert_mkflatpayload);
Stefan Reinauer20848ee2012-10-22 16:04:13 -0700288}
289
Peter Stuge3bfd5b82013-07-09 19:39:13 +0200290static int cbfs_add_integer(void)
291{
292 return cbfs_add_integer_component(param.cbfs_name,
293 param.name,
294 param.u64val,
295 param.baseaddress);
296}
297
Stefan Reinauer63217582012-10-29 16:52:36 -0700298static int cbfs_remove(void)
Gabe Blacke1bb49e2012-01-27 00:33:47 -0800299{
Hung-Te Linc03d9b02013-01-29 02:38:40 +0800300 struct cbfs_image image;
Gabe Blacke1bb49e2012-01-27 00:33:47 -0800301
Hung-Te Lind1739622013-01-28 14:23:49 +0800302 if (!param.name) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800303 ERROR("You need to specify -n/--name.\n");
Stefan Reinauer63217582012-10-29 16:52:36 -0700304 return 1;
305 }
306
Hung-Te Linc03d9b02013-01-29 02:38:40 +0800307 if (cbfs_image_from_file(&image, param.cbfs_name) != 0) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800308 ERROR("Could not load ROM image '%s'.\n",
Hung-Te Lind1739622013-01-28 14:23:49 +0800309 param.cbfs_name);
Gabe Blacke1bb49e2012-01-27 00:33:47 -0800310 return 1;
311 }
312
Hung-Te Linc03d9b02013-01-29 02:38:40 +0800313 if (cbfs_remove_entry(&image, param.name) != 0) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800314 ERROR("Removing file '%s' failed.\n",
Hung-Te Linc03d9b02013-01-29 02:38:40 +0800315 param.name);
316 cbfs_image_delete(&image);
317 return 1;
318 }
319 if (cbfs_image_write_file(&image, param.cbfs_name) != 0) {
320 cbfs_image_delete(&image);
Gabe Blacke1bb49e2012-01-27 00:33:47 -0800321 return 1;
322 }
323
Hung-Te Linc03d9b02013-01-29 02:38:40 +0800324 cbfs_image_delete(&image);
Gabe Blacke1bb49e2012-01-27 00:33:47 -0800325 return 0;
326}
327
Stefan Reinauer63217582012-10-29 16:52:36 -0700328static int cbfs_create(void)
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000329{
Hung-Te Linf56c73f2013-01-29 09:45:12 +0800330 struct cbfs_image image;
331 struct buffer bootblock;
332
Hung-Te Lind1739622013-01-28 14:23:49 +0800333 if (param.size == 0) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800334 ERROR("You need to specify a valid -s/--size.\n");
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000335 return 1;
336 }
337
Hung-Te Lind1739622013-01-28 14:23:49 +0800338 if (!param.bootblock) {
Hung-Te Linf56c73f2013-01-29 09:45:12 +0800339 ERROR("You need to specify -B/--bootblock.\n");
Stefan Reinauer63217582012-10-29 16:52:36 -0700340 return 1;
Patrick Georgi467b12a2009-12-21 13:50:37 +0000341 }
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000342
Alexandru Gagniuc35850ae2014-02-02 22:37:28 -0600343 if (param.arch == CBFS_ARCHITECTURE_UNKNOWN) {
Stefan Reinauer60a4a732013-03-28 16:46:07 -0700344 ERROR("You need to specify -m/--machine arch.\n");
David Hendricks90ca3b62012-11-16 14:48:22 -0800345 return 1;
346 }
347
Hung-Te Linf56c73f2013-01-29 09:45:12 +0800348 if (buffer_from_file(&bootblock, param.bootblock) != 0) {
349 return 1;
350 }
351
352 // Setup default boot offset and header offset.
353 if (!param.baseaddress_assigned) {
354 // put boot block before end of ROM.
355 param.baseaddress = param.size - bootblock.size;
356 DEBUG("bootblock in end of ROM.\n");
357 }
358 if (!param.headeroffset_assigned) {
359 // Put header before bootblock, and make a reference in end of
360 // bootblock.
361 param.headeroffset = (
362 param.baseaddress -
363 sizeof(struct cbfs_header));
364 if (bootblock.size >= sizeof(uint32_t)) {
365 // TODO this only works for 32b top-aligned system now...
366 uint32_t ptr = param.headeroffset - param.size;
367 uint32_t *sig = (uint32_t *)(bootblock.data +
368 bootblock.size -
369 sizeof(ptr));
370 *sig = ptr;
371 DEBUG("CBFS header reference in end of bootblock.\n");
372 }
373 }
374
375 if (cbfs_image_create(&image,
Alexandru Gagniuc35850ae2014-02-02 22:37:28 -0600376 param.arch,
Hung-Te Linf56c73f2013-01-29 09:45:12 +0800377 param.size,
378 param.alignment,
379 &bootblock,
380 param.baseaddress,
381 param.headeroffset,
382 param.offset) != 0) {
383 ERROR("Failed to create %s.\n", param.cbfs_name);
384 return 1;
385 }
386 buffer_delete(&bootblock);
387
388 if (cbfs_image_write_file(&image, param.cbfs_name) != 0) {
389 ERROR("Failed to write %s.\n", param.cbfs_name);
390 cbfs_image_delete(&image);
391 return 1;
392 }
393 cbfs_image_delete(&image);
394 return 0;
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000395}
396
Stefan Reinauer63217582012-10-29 16:52:36 -0700397static int cbfs_locate(void)
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000398{
Hung-Te Lin215d1d72013-01-29 03:46:02 +0800399 struct cbfs_image image;
400 struct buffer buffer;
401 int32_t address;
Stefan Reinauer63217582012-10-29 16:52:36 -0700402
Hung-Te Lind1739622013-01-28 14:23:49 +0800403 if (!param.filename) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800404 ERROR("You need to specify -f/--filename.\n");
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000405 return 1;
406 }
407
Hung-Te Lind1739622013-01-28 14:23:49 +0800408 if (!param.name) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800409 ERROR("You need to specify -n/--name.\n");
Stefan Reinauer63217582012-10-29 16:52:36 -0700410 return 1;
411 }
412
Hung-Te Lin215d1d72013-01-29 03:46:02 +0800413 if (cbfs_image_from_file(&image, param.cbfs_name) != 0) {
414 ERROR("Failed to load %s.\n", param.cbfs_name);
415 return 1;
416 }
Stefan Reinauer63217582012-10-29 16:52:36 -0700417
Hung-Te Lin215d1d72013-01-29 03:46:02 +0800418 if (cbfs_get_entry(&image, param.name))
419 WARN("'%s' already in CBFS.\n", param.name);
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000420
Hung-Te Lin215d1d72013-01-29 03:46:02 +0800421 if (buffer_from_file(&buffer, param.filename) != 0) {
422 ERROR("Cannot load %s.\n", param.filename);
423 cbfs_image_delete(&image);
424 return 1;
425 }
426
427 address = cbfs_locate_entry(&image, param.name, buffer.size,
Hung-Te Line4ea2ca2013-03-19 12:24:43 +0800428 param.pagesize, param.alignment);
Hung-Te Lin215d1d72013-01-29 03:46:02 +0800429 buffer_delete(&buffer);
430
431 if (address == -1) {
Hung-Te Line4ea2ca2013-03-19 12:24:43 +0800432 ERROR("'%s' can't fit in CBFS for page-size %#x, align %#x.\n",
433 param.name, param.pagesize, param.alignment);
Hung-Te Lin215d1d72013-01-29 03:46:02 +0800434 cbfs_image_delete(&image);
435 return 1;
436 }
437
438 if (param.top_aligned)
Alexandru Gagniucc1d1fd82014-02-05 01:10:08 -0600439 address = address - image.header->romsize;
Hung-Te Lin215d1d72013-01-29 03:46:02 +0800440
441 cbfs_image_delete(&image);
442 printf("0x%x\n", address);
443 return 0;
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000444}
445
Stefan Reinauer63217582012-10-29 16:52:36 -0700446static int cbfs_print(void)
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000447{
Hung-Te Lin3bb035b2013-01-29 02:15:49 +0800448 struct cbfs_image image;
449 if (cbfs_image_from_file(&image, param.cbfs_name) != 0) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800450 ERROR("Could not load ROM image '%s'.\n",
Hung-Te Lind1739622013-01-28 14:23:49 +0800451 param.cbfs_name);
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000452 return 1;
453 }
Hung-Te Lin3bb035b2013-01-29 02:15:49 +0800454 cbfs_print_directory(&image);
455 cbfs_image_delete(&image);
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000456 return 0;
457}
458
Stefan Reinauer63217582012-10-29 16:52:36 -0700459static int cbfs_extract(void)
Aurelien Guillaumefe7d6b92011-01-13 09:09:21 +0000460{
Hung-Te Lin0f8af712013-01-29 02:29:49 +0800461 int result = 0;
462 struct cbfs_image image;
Aurelien Guillaumefe7d6b92011-01-13 09:09:21 +0000463
Hung-Te Lind1739622013-01-28 14:23:49 +0800464 if (!param.filename) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800465 ERROR("You need to specify -f/--filename.\n");
Stefan Reinauer63217582012-10-29 16:52:36 -0700466 return 1;
467 }
468
Hung-Te Lind1739622013-01-28 14:23:49 +0800469 if (!param.name) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800470 ERROR("You need to specify -n/--name.\n");
Stefan Reinauer63217582012-10-29 16:52:36 -0700471 return 1;
472 }
473
Hung-Te Lin0f8af712013-01-29 02:29:49 +0800474 if (cbfs_image_from_file(&image, param.cbfs_name) != 0) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800475 ERROR("Could not load ROM image '%s'.\n",
Hung-Te Lind1739622013-01-28 14:23:49 +0800476 param.cbfs_name);
Hung-Te Lin0f8af712013-01-29 02:29:49 +0800477 result = 1;
478 } else if (cbfs_export_entry(&image, param.name,
479 param.filename) != 0) {
480 result = 1;
Aurelien Guillaumefe7d6b92011-01-13 09:09:21 +0000481 }
482
Hung-Te Lin0f8af712013-01-29 02:29:49 +0800483 cbfs_image_delete(&image);
484 return result;
Aurelien Guillaumefe7d6b92011-01-13 09:09:21 +0000485}
486
Aaron Durbin6b0d0d62012-12-14 17:16:21 -0600487static int cbfs_update_fit(void)
488{
489 int ret = 0;
490 struct cbfs_image image;
491
492 if (!param.name) {
493 ERROR("You need to specify -n/--name.\n");
494 return 1;
495 }
496
497 if (param.fit_empty_entries <= 0) {
498 ERROR("Invalid number of fit entries "
499 "(-x/--empty-fits): %d\n", param.fit_empty_entries);
500 return 1;
501 }
502
503 if (cbfs_image_from_file(&image, param.cbfs_name) != 0) {
504 ERROR("Could not load ROM image '%s'.\n",
505 param.cbfs_name);
506 return 1;
507 }
508
509 ret = fit_update_table(&image, param.fit_empty_entries, param.name);
510 if (!ret)
511 ret = cbfs_image_write_file(&image, param.cbfs_name);
512
513 cbfs_image_delete(&image);
514 return ret;
515}
516
Stefan Reinauera1e48242011-10-21 14:24:57 -0700517static const struct command commands[] = {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800518 {"add", "f:n:t:b:vh?", cbfs_add},
Patrick Georgide36d332013-08-27 20:22:21 +0200519 {"add-payload", "f:n:t:c:b:vh?C:I:", cbfs_add_payload},
Furquan Shaikh405304a2014-10-30 11:44:20 -0700520 {"add-stage", "f:n:t:c:b:S:vh?", cbfs_add_stage},
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800521 {"add-flat-binary", "f:n:l:e:c:b:vh?", cbfs_add_flat_binary},
Peter Stuge3bfd5b82013-07-09 19:39:13 +0200522 {"add-int", "i:n:b:vh?", cbfs_add_integer},
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800523 {"remove", "n:vh?", cbfs_remove},
Hung-Te Linf56c73f2013-01-29 09:45:12 +0800524 {"create", "s:B:b:H:a:o:m:vh?", cbfs_create},
Hung-Te Line4ea2ca2013-03-19 12:24:43 +0800525 {"locate", "f:n:P:a:Tvh?", cbfs_locate},
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800526 {"print", "vh?", cbfs_print},
527 {"extract", "n:f:vh?", cbfs_extract},
Aaron Durbin6b0d0d62012-12-14 17:16:21 -0600528 {"update-fit", "n:x:vh?", cbfs_update_fit},
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000529};
530
Stefan Reinauer63217582012-10-29 16:52:36 -0700531static struct option long_options[] = {
532 {"name", required_argument, 0, 'n' },
533 {"type", required_argument, 0, 't' },
534 {"compression", required_argument, 0, 'c' },
535 {"base-address", required_argument, 0, 'b' },
536 {"load-address", required_argument, 0, 'l' },
Hung-Te Lin215d1d72013-01-29 03:46:02 +0800537 {"top-aligned", required_argument, 0, 'T' },
Stefan Reinauer63217582012-10-29 16:52:36 -0700538 {"entry-point", required_argument, 0, 'e' },
539 {"size", required_argument, 0, 's' },
540 {"bootblock", required_argument, 0, 'B' },
541 {"alignment", required_argument, 0, 'a' },
Hung-Te Line9198372013-03-19 12:17:12 +0800542 {"page-size", required_argument, 0, 'P' },
Stefan Reinauer63217582012-10-29 16:52:36 -0700543 {"offset", required_argument, 0, 'o' },
544 {"file", required_argument, 0, 'f' },
Peter Stuge3bfd5b82013-07-09 19:39:13 +0200545 {"int", required_argument, 0, 'i' },
Stefan Reinauer60a4a732013-03-28 16:46:07 -0700546 {"machine", required_argument, 0, 'm' },
Aaron Durbin6b0d0d62012-12-14 17:16:21 -0600547 {"empty-fits", required_argument, 0, 'x' },
Patrick Georgide36d332013-08-27 20:22:21 +0200548 {"initrd", required_argument, 0, 'I' },
549 {"cmdline", required_argument, 0, 'C' },
Furquan Shaikh405304a2014-10-30 11:44:20 -0700550 {"ignore-sec", required_argument, 0, 'S' },
Stefan Reinauer63217582012-10-29 16:52:36 -0700551 {"verbose", no_argument, 0, 'v' },
552 {"help", no_argument, 0, 'h' },
553 {NULL, 0, 0, 0 }
554};
555
556static void usage(char *name)
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000557{
558 printf
Stefan Reinauer07040582010-04-24 21:24:06 +0000559 ("cbfstool: Management utility for CBFS formatted ROM images\n\n"
Stefan Reinauer63217582012-10-29 16:52:36 -0700560 "USAGE:\n" " %s [-h]\n"
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800561 " %s FILE COMMAND [-v] [PARAMETERS]...\n\n" "OPTIONs:\n"
Hung-Te Lin215d1d72013-01-29 03:46:02 +0800562 " -T Output top-aligned memory address\n"
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800563 " -v Provide verbose output\n"
564 " -h Display this help message\n\n"
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000565 "COMMANDs:\n"
David Hendricks90ca3b62012-11-16 14:48:22 -0800566 " add -f FILE -n NAME -t TYPE [-b base-address] "
Stefan Reinauer63217582012-10-29 16:52:36 -0700567 "Add a component\n"
David Hendricks90ca3b62012-11-16 14:48:22 -0800568 " add-payload -f FILE -n NAME [-c compression] [-b base] "
Stefan Reinauer63217582012-10-29 16:52:36 -0700569 "Add a payload to the ROM\n"
Patrick Georgide36d332013-08-27 20:22:21 +0200570 " (linux specific: [-C cmdline] [-I initrd])\n"
Furquan Shaikh405304a2014-10-30 11:44:20 -0700571 " add-stage -f FILE -n NAME [-c compression] [-b base] \\\n"
572 " [-S section-to-ignore] "
Stefan Reinauer63217582012-10-29 16:52:36 -0700573 "Add a stage to the ROM\n"
574 " add-flat-binary -f FILE -n NAME -l load-address \\\n"
David Hendricks90ca3b62012-11-16 14:48:22 -0800575 " -e entry-point [-c compression] [-b base] "
Stefan Reinauer63217582012-10-29 16:52:36 -0700576 "Add a 32bit flat mode binary\n"
Peter Stuge3bfd5b82013-07-09 19:39:13 +0200577 " add-int -i INTEGER -n NAME [-b base] "
578 "Add a raw 64-bit integer value\n"
David Hendricks90ca3b62012-11-16 14:48:22 -0800579 " remove -n NAME "
Stefan Reinauer63217582012-10-29 16:52:36 -0700580 "Remove a component\n"
David Hendricks90ca3b62012-11-16 14:48:22 -0800581 " create -s size -B bootblock -m ARCH [-a align] [-o offset] "
Stefan Reinauer63217582012-10-29 16:52:36 -0700582 "Create a ROM file\n"
Hung-Te Line4ea2ca2013-03-19 12:24:43 +0800583 " locate -f FILE -n NAME [-P page-size] [-a align] [-T] "
Stefan Reinauer63217582012-10-29 16:52:36 -0700584 "Find a place for a file of that size\n"
David Hendricks90ca3b62012-11-16 14:48:22 -0800585 " print "
Stefan Reinauer63217582012-10-29 16:52:36 -0700586 "Show the contents of the ROM\n"
David Hendricks90ca3b62012-11-16 14:48:22 -0800587 " extract -n NAME -f FILE "
Stefan Reinauer63217582012-10-29 16:52:36 -0700588 "Extracts a raw payload from ROM\n"
Aaron Durbin6b0d0d62012-12-14 17:16:21 -0600589 " update-fit -n MICROCODE_BLOB_NAME -x EMTPY_FIT_ENTRIES\n "
590 "Updates the FIT table with microcode entries\n"
Peter Stugeb347e0d2011-01-17 05:02:09 +0000591 "\n"
David Hendricks90ca3b62012-11-16 14:48:22 -0800592 "ARCHes:\n"
Paul Burton33186922014-06-13 23:56:45 +0100593 " arm64, arm, mips, x86\n"
Stefan Reinauer63217582012-10-29 16:52:36 -0700594 "TYPEs:\n", name, name
595 );
Stefan Reinauer07040582010-04-24 21:24:06 +0000596 print_supported_filetypes();
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000597}
598
599int main(int argc, char **argv)
600{
Mathias Krause41c229c2012-07-17 21:17:15 +0200601 size_t i;
Stefan Reinauer63217582012-10-29 16:52:36 -0700602 int c;
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000603
604 if (argc < 3) {
Stefan Reinauer63217582012-10-29 16:52:36 -0700605 usage(argv[0]);
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000606 return 1;
607 }
608
Hung-Te Lind1739622013-01-28 14:23:49 +0800609 param.cbfs_name = argv[1];
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000610 char *cmd = argv[2];
Stefan Reinauer63217582012-10-29 16:52:36 -0700611 optind += 2;
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000612
613 for (i = 0; i < ARRAY_SIZE(commands); i++) {
614 if (strcmp(cmd, commands[i].name) != 0)
615 continue;
Stefan Reinauer63217582012-10-29 16:52:36 -0700616
617 while (1) {
618 char *suffix = NULL;
619 int option_index = 0;
620
621 c = getopt_long(argc, argv, commands[i].optstring,
622 long_options, &option_index);
623 if (c == -1)
624 break;
625
626 /* filter out illegal long options */
zbao062730d2013-01-08 10:10:16 +0800627 if (strchr(commands[i].optstring, c) == NULL) {
Stefan Reinauer63217582012-10-29 16:52:36 -0700628 /* TODO maybe print actual long option instead */
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800629 ERROR("%s: invalid option -- '%c'\n",
630 argv[0], c);
Stefan Reinauer63217582012-10-29 16:52:36 -0700631 c = '?';
632 }
633
634 switch(c) {
635 case 'n':
Hung-Te Lind1739622013-01-28 14:23:49 +0800636 param.name = optarg;
Stefan Reinauer63217582012-10-29 16:52:36 -0700637 break;
638 case 't':
639 if (intfiletype(optarg) != ((uint64_t) - 1))
Hung-Te Lind1739622013-01-28 14:23:49 +0800640 param.type = intfiletype(optarg);
Stefan Reinauer63217582012-10-29 16:52:36 -0700641 else
Hung-Te Lind1739622013-01-28 14:23:49 +0800642 param.type = strtoul(optarg, NULL, 0);
643 if (param.type == 0)
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800644 WARN("Unknown type '%s' ignored\n",
Stefan Reinauer63217582012-10-29 16:52:36 -0700645 optarg);
646 break;
647 case 'c':
648 if (!strncasecmp(optarg, "lzma", 5))
Hung-Te Lind1739622013-01-28 14:23:49 +0800649 param.algo = CBFS_COMPRESS_LZMA;
Stefan Reinauer63217582012-10-29 16:52:36 -0700650 else if (!strncasecmp(optarg, "none", 5))
Hung-Te Lind1739622013-01-28 14:23:49 +0800651 param.algo = CBFS_COMPRESS_NONE;
Stefan Reinauer63217582012-10-29 16:52:36 -0700652 else
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800653 WARN("Unknown compression '%s'"
654 " ignored.\n", optarg);
Stefan Reinauer63217582012-10-29 16:52:36 -0700655 break;
656 case 'b':
Hung-Te Lind1739622013-01-28 14:23:49 +0800657 param.baseaddress = strtoul(optarg, NULL, 0);
Hung-Te Linf56c73f2013-01-29 09:45:12 +0800658 // baseaddress may be zero on non-x86, so we
659 // need an explicit "baseaddress_assigned".
660 param.baseaddress = strtoul(optarg, NULL, 0);
661 param.baseaddress_assigned = 1;
Stefan Reinauer63217582012-10-29 16:52:36 -0700662 break;
663 case 'l':
Hung-Te Lind1739622013-01-28 14:23:49 +0800664 param.loadaddress = strtoul(optarg, NULL, 0);
Stefan Reinauer63217582012-10-29 16:52:36 -0700665
666 break;
667 case 'e':
Hung-Te Lind1739622013-01-28 14:23:49 +0800668 param.entrypoint = strtoul(optarg, NULL, 0);
Stefan Reinauer63217582012-10-29 16:52:36 -0700669 break;
670 case 's':
Hung-Te Lind1739622013-01-28 14:23:49 +0800671 param.size = strtoul(optarg, &suffix, 0);
Stefan Reinauer63217582012-10-29 16:52:36 -0700672 if (tolower(suffix[0])=='k') {
Hung-Te Lind1739622013-01-28 14:23:49 +0800673 param.size *= 1024;
Stefan Reinauer63217582012-10-29 16:52:36 -0700674 }
675 if (tolower(suffix[0])=='m') {
Hung-Te Lind1739622013-01-28 14:23:49 +0800676 param.size *= 1024 * 1024;
Stefan Reinauer63217582012-10-29 16:52:36 -0700677 }
Patrick Georgie887ca52014-08-09 17:44:39 +0200678 break;
Stefan Reinauer63217582012-10-29 16:52:36 -0700679 case 'B':
Hung-Te Lind1739622013-01-28 14:23:49 +0800680 param.bootblock = optarg;
Stefan Reinauer63217582012-10-29 16:52:36 -0700681 break;
Hung-Te Linf56c73f2013-01-29 09:45:12 +0800682 case 'H':
683 param.headeroffset = strtoul(
684 optarg, NULL, 0);
685 param.headeroffset_assigned = 1;
686 break;
Stefan Reinauer63217582012-10-29 16:52:36 -0700687 case 'a':
Hung-Te Lind1739622013-01-28 14:23:49 +0800688 param.alignment = strtoul(optarg, NULL, 0);
Stefan Reinauer63217582012-10-29 16:52:36 -0700689 break;
Hung-Te Line9198372013-03-19 12:17:12 +0800690 case 'P':
691 param.pagesize = strtoul(optarg, NULL, 0);
692 break;
Stefan Reinauer63217582012-10-29 16:52:36 -0700693 case 'o':
Hung-Te Lind1739622013-01-28 14:23:49 +0800694 param.offset = strtoul(optarg, NULL, 0);
Stefan Reinauer63217582012-10-29 16:52:36 -0700695 break;
696 case 'f':
Hung-Te Lind1739622013-01-28 14:23:49 +0800697 param.filename = optarg;
Stefan Reinauer63217582012-10-29 16:52:36 -0700698 break;
Peter Stuge3bfd5b82013-07-09 19:39:13 +0200699 case 'i':
700 param.u64val = strtoull(optarg, NULL, 0);
701 break;
Hung-Te Lin215d1d72013-01-29 03:46:02 +0800702 case 'T':
703 param.top_aligned = 1;
704 break;
Aaron Durbin6b0d0d62012-12-14 17:16:21 -0600705 case 'x':
706 param.fit_empty_entries = strtol(optarg, NULL, 0);
707 break;
Stefan Reinauer63217582012-10-29 16:52:36 -0700708 case 'v':
709 verbose++;
710 break;
David Hendricks90ca3b62012-11-16 14:48:22 -0800711 case 'm':
Alexandru Gagniuc35850ae2014-02-02 22:37:28 -0600712 param.arch = string_to_arch(optarg);
David Hendricks90ca3b62012-11-16 14:48:22 -0800713 break;
Patrick Georgide36d332013-08-27 20:22:21 +0200714 case 'I':
715 param.initrd = optarg;
716 break;
717 case 'C':
718 param.cmdline = optarg;
719 break;
Furquan Shaikh405304a2014-10-30 11:44:20 -0700720 case 'S':
721 param.ignore_section = optarg;
722 break;
Stefan Reinauer63217582012-10-29 16:52:36 -0700723 case 'h':
724 case '?':
725 usage(argv[0]);
726 return 1;
727 default:
728 break;
729 }
730 }
731
732 return commands[i].function();
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000733 }
734
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800735 ERROR("Unknown command '%s'.\n", cmd);
Stefan Reinauer63217582012-10-29 16:52:36 -0700736 usage(argv[0]);
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000737 return 1;
738}