blob: b60f199f55207ee3c8efcee86d4936815123c2c2 [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;
Vadim Bendebury5e273a42014-12-23 19:26:54 -080050 uint32_t copyoffset;
51 uint32_t copyoffset_assigned;
Hung-Te Linf56c73f2013-01-29 09:45:12 +080052 uint32_t headeroffset;
53 uint32_t headeroffset_assigned;
Hung-Te Lind1739622013-01-28 14:23:49 +080054 uint32_t entrypoint;
55 uint32_t size;
56 uint32_t alignment;
Hung-Te Line9198372013-03-19 12:17:12 +080057 uint32_t pagesize;
Julius Wernerefcee762014-11-10 13:14:24 -080058 uint32_t cbfsoffset;
59 uint32_t cbfsoffset_assigned;
Hung-Te Lin215d1d72013-01-29 03:46:02 +080060 uint32_t top_aligned;
Alexandru Gagniuc35850ae2014-02-02 22:37:28 -060061 uint32_t arch;
Aaron Durbin6b0d0d62012-12-14 17:16:21 -060062 int fit_empty_entries;
Hung-Te Lind1739622013-01-28 14:23:49 +080063 comp_algo algo;
Patrick Georgide36d332013-08-27 20:22:21 +020064 /* for linux payloads */
65 char *initrd;
66 char *cmdline;
Hung-Te Lind1739622013-01-28 14:23:49 +080067} param = {
68 /* All variables not listed are initialized as zero. */
Alexandru Gagniuc35850ae2014-02-02 22:37:28 -060069 .arch = CBFS_ARCHITECTURE_UNKNOWN,
Hung-Te Lind1739622013-01-28 14:23:49 +080070 .algo = CBFS_COMPRESS_NONE,
Vadim Bendebury458a12e2014-12-23 15:10:12 -080071 .headeroffset = ~0,
Hung-Te Lind1739622013-01-28 14:23:49 +080072};
Stefan Reinauer63217582012-10-29 16:52:36 -070073
Hung-Te Linc13e4bf2013-01-29 15:22:11 +080074typedef int (*convert_buffer_t)(struct buffer *buffer, uint32_t *offset);
Stefan Reinauer63217582012-10-29 16:52:36 -070075
Peter Stuge3bfd5b82013-07-09 19:39:13 +020076static int cbfs_add_integer_component(const char *cbfs_name,
77 const char *name,
78 uint64_t u64val,
Vadim Bendebury458a12e2014-12-23 15:10:12 -080079 uint32_t offset,
80 uint32_t headeroffset) {
Peter Stuge3bfd5b82013-07-09 19:39:13 +020081 struct cbfs_image image;
82 struct buffer buffer;
83 int i, ret = 1;
84
85 if (!name) {
86 ERROR("You need to specify -n/--name.\n");
87 return 1;
88 }
89
90 if (buffer_create(&buffer, 8, name) != 0)
91 return 1;
92
93 for (i = 0; i < 8; i++)
94 buffer.data[i] = (u64val >> i*8) & 0xff;
95
Vadim Bendebury458a12e2014-12-23 15:10:12 -080096 if (cbfs_image_from_file(&image, cbfs_name, headeroffset) != 0) {
Peter Stuge3bfd5b82013-07-09 19:39:13 +020097 ERROR("Could not load ROM image '%s'.\n", cbfs_name);
98 buffer_delete(&buffer);
99 return 1;
100 }
101
102 if (cbfs_get_entry(&image, name)) {
103 ERROR("'%s' already in ROM image.\n", name);
104 goto done;
105 }
106
107 if (cbfs_add_entry(&image, &buffer, name, CBFS_COMPONENT_RAW, param.baseaddress) != 0) {
108 ERROR("Failed to add %llu into ROM image as '%s'.\n", (long long unsigned)u64val, name);
109 goto done;
110 }
111
112 if (cbfs_image_write_file(&image, cbfs_name) == 0)
113 ret = 0;
114
115done:
116 buffer_delete(&buffer);
117 cbfs_image_delete(&image);
118 return ret;
119}
120
Hung-Te Lin5f3eb262013-01-29 10:24:00 +0800121static int cbfs_add_component(const char *cbfs_name,
122 const char *filename,
123 const char *name,
124 uint32_t type,
125 uint32_t offset,
Vadim Bendebury458a12e2014-12-23 15:10:12 -0800126 uint32_t headeroffset,
Stefan Reinauer2dd161f2015-03-04 00:55:03 +0100127 convert_buffer_t convert)
128{
Hung-Te Lin5f3eb262013-01-29 10:24:00 +0800129 struct cbfs_image image;
130 struct buffer buffer;
131
132 if (!filename) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800133 ERROR("You need to specify -f/--filename.\n");
Stefan Reinauer63217582012-10-29 16:52:36 -0700134 return 1;
135 }
136
Hung-Te Lin5f3eb262013-01-29 10:24:00 +0800137 if (!name) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800138 ERROR("You need to specify -n/--name.\n");
Stefan Reinauer63217582012-10-29 16:52:36 -0700139 return 1;
140 }
141
Hung-Te Lin5f3eb262013-01-29 10:24:00 +0800142 if (type == 0) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800143 ERROR("You need to specify a valid -t/--type.\n");
Stefan Reinauer63217582012-10-29 16:52:36 -0700144 return 1;
145 }
146
Vadim Bendebury458a12e2014-12-23 15:10:12 -0800147 if (cbfs_image_from_file(&image, cbfs_name, headeroffset) != 0) {
Stefan Reinauer8f50e532013-11-13 14:34:57 -0800148 ERROR("Could not load ROM image '%s'.\n", cbfs_name);
149 return 1;
150 }
151
Hung-Te Lin5f3eb262013-01-29 10:24:00 +0800152 if (buffer_from_file(&buffer, filename) != 0) {
153 ERROR("Could not load file '%s'.\n", filename);
Stefan Reinauer8f50e532013-11-13 14:34:57 -0800154 cbfs_image_delete(&image);
Stefan Reinauer63217582012-10-29 16:52:36 -0700155 return 1;
156 }
157
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800158 if (convert && convert(&buffer, &offset) != 0) {
Hung-Te Lin5f3eb262013-01-29 10:24:00 +0800159 ERROR("Failed to parse file '%s'.\n", filename);
160 buffer_delete(&buffer);
Stefan Reinauer8f50e532013-11-13 14:34:57 -0800161 cbfs_image_delete(&image);
Patrick Georgi56f5fb72009-09-30 11:21:18 +0000162 return 1;
Stefan Reinauerfbadc492011-10-14 12:44:14 -0700163 }
Stefan Reinauer63217582012-10-29 16:52:36 -0700164
Hung-Te Lin5f3eb262013-01-29 10:24:00 +0800165 if (cbfs_get_entry(&image, name)) {
166 ERROR("'%s' already in ROM image.\n", name);
167 buffer_delete(&buffer);
168 cbfs_image_delete(&image);
169 return 1;
170 }
171
172 if (cbfs_add_entry(&image, &buffer, name, type, offset) != 0) {
173 ERROR("Failed to add '%s' into ROM image.\n", filename);
174 buffer_delete(&buffer);
175 cbfs_image_delete(&image);
176 return 1;
177 }
178
179 if (cbfs_image_write_file(&image, cbfs_name) != 0) {
180 buffer_delete(&buffer);
181 cbfs_image_delete(&image);
182 return 1;
183 }
184
185 buffer_delete(&buffer);
186 cbfs_image_delete(&image);
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000187 return 0;
188}
189
Alexandru Gagniuc35850ae2014-02-02 22:37:28 -0600190static int cbfstool_convert_mkstage(struct buffer *buffer, uint32_t *offset)
191{
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800192 struct buffer output;
Alexandru Gagniuc35850ae2014-02-02 22:37:28 -0600193 int ret;
194 ret = parse_elf_to_stage(buffer, &output, param.arch, param.algo,
Furquan Shaikh405304a2014-10-30 11:44:20 -0700195 offset, param.ignore_section);
Alexandru Gagniuc35850ae2014-02-02 22:37:28 -0600196 if (ret != 0)
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800197 return -1;
198 buffer_delete(buffer);
199 // direct assign, no dupe.
200 memcpy(buffer, &output, sizeof(*buffer));
201 return 0;
202}
203
Stefan Reinauer2dd161f2015-03-04 00:55:03 +0100204static int cbfstool_convert_mkpayload(struct buffer *buffer,
205 unused uint32_t *offset)
206{
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800207 struct buffer output;
Stefan Reinauer543a6822013-02-04 15:39:13 -0800208 int ret;
209 /* per default, try and see if payload is an ELF binary */
Alexandru Gagniuc35850ae2014-02-02 22:37:28 -0600210 ret = parse_elf_to_payload(buffer, &output, param.arch, param.algo);
Stefan Reinauer543a6822013-02-04 15:39:13 -0800211
212 /* If it's not an ELF, see if it's a UEFI FV */
213 if (ret != 0)
214 ret = parse_fv_to_payload(buffer, &output, param.algo);
215
Patrick Georgide36d332013-08-27 20:22:21 +0200216 /* If it's neither ELF nor UEFI Fv, try bzImage */
217 if (ret != 0)
218 ret = parse_bzImage_to_payload(buffer, &output,
219 param.initrd, param.cmdline, param.algo);
220
Stefan Reinauer543a6822013-02-04 15:39:13 -0800221 /* Not a supported payload type */
222 if (ret != 0) {
223 ERROR("Not a supported payload type (ELF / FV).\n");
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800224 return -1;
Stefan Reinauer543a6822013-02-04 15:39:13 -0800225 }
226
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800227 buffer_delete(buffer);
228 // direct assign, no dupe.
229 memcpy(buffer, &output, sizeof(*buffer));
230 return 0;
231}
232
233static int cbfstool_convert_mkflatpayload(struct buffer *buffer,
Stefan Reinauer2dd161f2015-03-04 00:55:03 +0100234 unused uint32_t *offset)
235{
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800236 struct buffer output;
237 if (parse_flat_binary_to_payload(buffer, &output,
238 param.loadaddress,
239 param.entrypoint,
240 param.algo) != 0) {
241 return -1;
242 }
243 buffer_delete(buffer);
244 // direct assign, no dupe.
245 memcpy(buffer, &output, sizeof(*buffer));
246 return 0;
247}
248
249
Hung-Te Lin5f3eb262013-01-29 10:24:00 +0800250static int cbfs_add(void)
251{
252 return cbfs_add_component(param.cbfs_name,
253 param.filename,
254 param.name,
255 param.type,
256 param.baseaddress,
Vadim Bendebury458a12e2014-12-23 15:10:12 -0800257 param.headeroffset,
Hung-Te Lin5f3eb262013-01-29 10:24:00 +0800258 NULL);
259}
260
Stefan Reinauer63217582012-10-29 16:52:36 -0700261static int cbfs_add_stage(void)
Stefan Reinauer20848ee2012-10-22 16:04:13 -0700262{
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800263 return cbfs_add_component(param.cbfs_name,
264 param.filename,
265 param.name,
266 CBFS_COMPONENT_STAGE,
267 param.baseaddress,
Vadim Bendebury458a12e2014-12-23 15:10:12 -0800268 param.headeroffset,
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800269 cbfstool_convert_mkstage);
270}
Stefan Reinauer20848ee2012-10-22 16:04:13 -0700271
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800272static int cbfs_add_payload(void)
273{
274 return cbfs_add_component(param.cbfs_name,
275 param.filename,
276 param.name,
277 CBFS_COMPONENT_PAYLOAD,
278 param.baseaddress,
Vadim Bendebury458a12e2014-12-23 15:10:12 -0800279 param.headeroffset,
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800280 cbfstool_convert_mkpayload);
Stefan Reinauer63217582012-10-29 16:52:36 -0700281}
282
283static int cbfs_add_flat_binary(void)
284{
Hung-Te Lind1739622013-01-28 14:23:49 +0800285 if (param.loadaddress == 0) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800286 ERROR("You need to specify a valid "
Stefan Reinauer63217582012-10-29 16:52:36 -0700287 "-l/--load-address.\n");
288 return 1;
289 }
Hung-Te Lind1739622013-01-28 14:23:49 +0800290 if (param.entrypoint == 0) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800291 ERROR("You need to specify a valid "
Stefan Reinauer63217582012-10-29 16:52:36 -0700292 "-e/--entry-point.\n");
293 return 1;
294 }
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800295 return cbfs_add_component(param.cbfs_name,
296 param.filename,
297 param.name,
298 CBFS_COMPONENT_PAYLOAD,
299 param.baseaddress,
Vadim Bendebury458a12e2014-12-23 15:10:12 -0800300 param.headeroffset,
Hung-Te Linc13e4bf2013-01-29 15:22:11 +0800301 cbfstool_convert_mkflatpayload);
Stefan Reinauer20848ee2012-10-22 16:04:13 -0700302}
303
Peter Stuge3bfd5b82013-07-09 19:39:13 +0200304static int cbfs_add_integer(void)
305{
306 return cbfs_add_integer_component(param.cbfs_name,
307 param.name,
308 param.u64val,
Vadim Bendebury458a12e2014-12-23 15:10:12 -0800309 param.baseaddress,
310 param.headeroffset);
Peter Stuge3bfd5b82013-07-09 19:39:13 +0200311}
312
Stefan Reinauer63217582012-10-29 16:52:36 -0700313static int cbfs_remove(void)
Gabe Blacke1bb49e2012-01-27 00:33:47 -0800314{
Hung-Te Linc03d9b02013-01-29 02:38:40 +0800315 struct cbfs_image image;
Gabe Blacke1bb49e2012-01-27 00:33:47 -0800316
Hung-Te Lind1739622013-01-28 14:23:49 +0800317 if (!param.name) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800318 ERROR("You need to specify -n/--name.\n");
Stefan Reinauer63217582012-10-29 16:52:36 -0700319 return 1;
320 }
321
Vadim Bendebury458a12e2014-12-23 15:10:12 -0800322 if (cbfs_image_from_file(&image, param.cbfs_name,
323 param.headeroffset) != 0) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800324 ERROR("Could not load ROM image '%s'.\n",
Hung-Te Lind1739622013-01-28 14:23:49 +0800325 param.cbfs_name);
Gabe Blacke1bb49e2012-01-27 00:33:47 -0800326 return 1;
327 }
328
Hung-Te Linc03d9b02013-01-29 02:38:40 +0800329 if (cbfs_remove_entry(&image, param.name) != 0) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800330 ERROR("Removing file '%s' failed.\n",
Hung-Te Linc03d9b02013-01-29 02:38:40 +0800331 param.name);
332 cbfs_image_delete(&image);
333 return 1;
334 }
335 if (cbfs_image_write_file(&image, param.cbfs_name) != 0) {
336 cbfs_image_delete(&image);
Gabe Blacke1bb49e2012-01-27 00:33:47 -0800337 return 1;
338 }
339
Hung-Te Linc03d9b02013-01-29 02:38:40 +0800340 cbfs_image_delete(&image);
Gabe Blacke1bb49e2012-01-27 00:33:47 -0800341 return 0;
342}
343
Stefan Reinauer63217582012-10-29 16:52:36 -0700344static int cbfs_create(void)
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000345{
Hung-Te Linf56c73f2013-01-29 09:45:12 +0800346 struct cbfs_image image;
347 struct buffer bootblock;
348
Hung-Te Lind1739622013-01-28 14:23:49 +0800349 if (param.size == 0) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800350 ERROR("You need to specify a valid -s/--size.\n");
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000351 return 1;
352 }
353
Alexandru Gagniuc35850ae2014-02-02 22:37:28 -0600354 if (param.arch == CBFS_ARCHITECTURE_UNKNOWN) {
Stefan Reinauer60a4a732013-03-28 16:46:07 -0700355 ERROR("You need to specify -m/--machine arch.\n");
David Hendricks90ca3b62012-11-16 14:48:22 -0800356 return 1;
357 }
358
Julius Wernerefcee762014-11-10 13:14:24 -0800359 if (!param.bootblock) {
360 DEBUG("-B not given, creating image without bootblock.\n");
361 buffer_create(&bootblock, 0, "(dummy)");
362 } else if (buffer_from_file(&bootblock, param.bootblock)) {
Hung-Te Linf56c73f2013-01-29 09:45:12 +0800363 return 1;
364 }
365
Julius Wernerefcee762014-11-10 13:14:24 -0800366 if (!param.alignment)
367 param.alignment = 64; // default CBFS entry alignment
368
369 // Set default offsets. x86, as usual, needs to be a special snowflake.
Hung-Te Linf56c73f2013-01-29 09:45:12 +0800370 if (!param.baseaddress_assigned) {
Julius Wernerefcee762014-11-10 13:14:24 -0800371 if (param.arch == CBFS_ARCHITECTURE_X86) {
372 // Make sure there's at least enough room for rel_offset
373 param.baseaddress = param.size - (
374 bootblock.size > sizeof(int32_t) ?
375 bootblock.size : sizeof(int32_t));
376 DEBUG("x86 -> bootblock lies at end of ROM (%#x).\n",
377 param.baseaddress);
378 } else {
379 param.baseaddress = 0;
380 DEBUG("bootblock starts at address 0x0.\n");
381 }
Hung-Te Linf56c73f2013-01-29 09:45:12 +0800382 }
383 if (!param.headeroffset_assigned) {
Julius Wernerefcee762014-11-10 13:14:24 -0800384 if (param.arch == CBFS_ARCHITECTURE_X86) {
385 param.headeroffset = param.baseaddress -
386 sizeof(struct cbfs_header);
387 DEBUG("x86 -> CBFS header before bootblock (%#x).\n",
388 param.headeroffset);
389 } else {
390 param.headeroffset = align_up(param.baseaddress +
391 bootblock.size, sizeof(uint32_t));
392 DEBUG("CBFS header placed behind bootblock (%#x).\n",
393 param.headeroffset);
394 }
395 }
396 if (!param.cbfsoffset_assigned) {
397 if (param.arch == CBFS_ARCHITECTURE_X86) {
398 param.cbfsoffset = 0;
399 DEBUG("x86 -> CBFS entries start at address 0x0.\n");
400 } else {
401 param.cbfsoffset = align_up(param.headeroffset +
402 sizeof(struct cbfs_header),
403 param.alignment);
404 DEBUG("CBFS entries start beind master header (%#x).\n",
405 param.cbfsoffset);
Hung-Te Linf56c73f2013-01-29 09:45:12 +0800406 }
407 }
408
409 if (cbfs_image_create(&image,
Alexandru Gagniuc35850ae2014-02-02 22:37:28 -0600410 param.arch,
Hung-Te Linf56c73f2013-01-29 09:45:12 +0800411 param.size,
412 param.alignment,
413 &bootblock,
414 param.baseaddress,
415 param.headeroffset,
Julius Wernerefcee762014-11-10 13:14:24 -0800416 param.cbfsoffset) != 0) {
Hung-Te Linf56c73f2013-01-29 09:45:12 +0800417 ERROR("Failed to create %s.\n", param.cbfs_name);
418 return 1;
419 }
420 buffer_delete(&bootblock);
421
422 if (cbfs_image_write_file(&image, param.cbfs_name) != 0) {
423 ERROR("Failed to write %s.\n", param.cbfs_name);
424 cbfs_image_delete(&image);
425 return 1;
426 }
427 cbfs_image_delete(&image);
428 return 0;
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000429}
430
Stefan Reinauer63217582012-10-29 16:52:36 -0700431static int cbfs_locate(void)
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000432{
Hung-Te Lin215d1d72013-01-29 03:46:02 +0800433 struct cbfs_image image;
434 struct buffer buffer;
435 int32_t address;
Stefan Reinauer63217582012-10-29 16:52:36 -0700436
Hung-Te Lind1739622013-01-28 14:23:49 +0800437 if (!param.filename) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800438 ERROR("You need to specify -f/--filename.\n");
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000439 return 1;
440 }
441
Hung-Te Lind1739622013-01-28 14:23:49 +0800442 if (!param.name) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800443 ERROR("You need to specify -n/--name.\n");
Stefan Reinauer63217582012-10-29 16:52:36 -0700444 return 1;
445 }
446
Vadim Bendebury458a12e2014-12-23 15:10:12 -0800447 if (cbfs_image_from_file(&image, param.cbfs_name,
448 param.headeroffset) != 0) {
Hung-Te Lin215d1d72013-01-29 03:46:02 +0800449 ERROR("Failed to load %s.\n", param.cbfs_name);
450 return 1;
451 }
Stefan Reinauer63217582012-10-29 16:52:36 -0700452
Hung-Te Lin215d1d72013-01-29 03:46:02 +0800453 if (cbfs_get_entry(&image, param.name))
454 WARN("'%s' already in CBFS.\n", param.name);
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000455
Hung-Te Lin215d1d72013-01-29 03:46:02 +0800456 if (buffer_from_file(&buffer, param.filename) != 0) {
457 ERROR("Cannot load %s.\n", param.filename);
458 cbfs_image_delete(&image);
459 return 1;
460 }
461
462 address = cbfs_locate_entry(&image, param.name, buffer.size,
Hung-Te Line4ea2ca2013-03-19 12:24:43 +0800463 param.pagesize, param.alignment);
Hung-Te Lin215d1d72013-01-29 03:46:02 +0800464 buffer_delete(&buffer);
465
466 if (address == -1) {
Hung-Te Line4ea2ca2013-03-19 12:24:43 +0800467 ERROR("'%s' can't fit in CBFS for page-size %#x, align %#x.\n",
468 param.name, param.pagesize, param.alignment);
Hung-Te Lin215d1d72013-01-29 03:46:02 +0800469 cbfs_image_delete(&image);
470 return 1;
471 }
472
473 if (param.top_aligned)
Alexandru Gagniucc1d1fd82014-02-05 01:10:08 -0600474 address = address - image.header->romsize;
Hung-Te Lin215d1d72013-01-29 03:46:02 +0800475
476 cbfs_image_delete(&image);
477 printf("0x%x\n", address);
478 return 0;
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000479}
480
Stefan Reinauer63217582012-10-29 16:52:36 -0700481static int cbfs_print(void)
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000482{
Hung-Te Lin3bb035b2013-01-29 02:15:49 +0800483 struct cbfs_image image;
Vadim Bendebury458a12e2014-12-23 15:10:12 -0800484 if (cbfs_image_from_file(&image, param.cbfs_name,
485 param.headeroffset) != 0) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800486 ERROR("Could not load ROM image '%s'.\n",
Hung-Te Lind1739622013-01-28 14:23:49 +0800487 param.cbfs_name);
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000488 return 1;
489 }
Hung-Te Lin3bb035b2013-01-29 02:15:49 +0800490 cbfs_print_directory(&image);
491 cbfs_image_delete(&image);
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000492 return 0;
493}
494
Stefan Reinauer63217582012-10-29 16:52:36 -0700495static int cbfs_extract(void)
Aurelien Guillaumefe7d6b92011-01-13 09:09:21 +0000496{
Hung-Te Lin0f8af712013-01-29 02:29:49 +0800497 int result = 0;
498 struct cbfs_image image;
Aurelien Guillaumefe7d6b92011-01-13 09:09:21 +0000499
Hung-Te Lind1739622013-01-28 14:23:49 +0800500 if (!param.filename) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800501 ERROR("You need to specify -f/--filename.\n");
Stefan Reinauer63217582012-10-29 16:52:36 -0700502 return 1;
503 }
504
Hung-Te Lind1739622013-01-28 14:23:49 +0800505 if (!param.name) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800506 ERROR("You need to specify -n/--name.\n");
Stefan Reinauer63217582012-10-29 16:52:36 -0700507 return 1;
508 }
509
Vadim Bendebury458a12e2014-12-23 15:10:12 -0800510 if (cbfs_image_from_file(&image, param.cbfs_name,
511 param.headeroffset) != 0) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800512 ERROR("Could not load ROM image '%s'.\n",
Hung-Te Lind1739622013-01-28 14:23:49 +0800513 param.cbfs_name);
Hung-Te Lin0f8af712013-01-29 02:29:49 +0800514 result = 1;
515 } else if (cbfs_export_entry(&image, param.name,
516 param.filename) != 0) {
517 result = 1;
Aurelien Guillaumefe7d6b92011-01-13 09:09:21 +0000518 }
519
Hung-Te Lin0f8af712013-01-29 02:29:49 +0800520 cbfs_image_delete(&image);
521 return result;
Aurelien Guillaumefe7d6b92011-01-13 09:09:21 +0000522}
523
Aaron Durbin6b0d0d62012-12-14 17:16:21 -0600524static int cbfs_update_fit(void)
525{
526 int ret = 0;
527 struct cbfs_image image;
528
529 if (!param.name) {
530 ERROR("You need to specify -n/--name.\n");
531 return 1;
532 }
533
534 if (param.fit_empty_entries <= 0) {
535 ERROR("Invalid number of fit entries "
536 "(-x/--empty-fits): %d\n", param.fit_empty_entries);
537 return 1;
538 }
539
Vadim Bendebury458a12e2014-12-23 15:10:12 -0800540 if (cbfs_image_from_file(&image, param.cbfs_name,
541 param.headeroffset) != 0) {
Aaron Durbin6b0d0d62012-12-14 17:16:21 -0600542 ERROR("Could not load ROM image '%s'.\n",
543 param.cbfs_name);
544 return 1;
545 }
546
547 ret = fit_update_table(&image, param.fit_empty_entries, param.name);
548 if (!ret)
549 ret = cbfs_image_write_file(&image, param.cbfs_name);
550
551 cbfs_image_delete(&image);
552 return ret;
553}
554
Vadim Bendebury5e273a42014-12-23 19:26:54 -0800555static int cbfs_copy(void)
556{
557 struct cbfs_image image;
558
559 if (!param.copyoffset_assigned) {
560 ERROR("You need to specify -D/--copy_offset.\n");
561 return 1;
562 }
563
564 if (!param.size) {
565 ERROR("You need to specify -s/--size.\n");
566 return 1;
567 }
568
569 if (cbfs_image_from_file(&image, param.cbfs_name,
570 param.headeroffset) != 0)
571 return 1;
572
573 if (cbfs_copy_instance(&image, param.copyoffset, param.size))
574 return 1;
575
576 /* Save the new image. */
577 return buffer_write_file(&image.buffer, param.cbfs_name);
578
579}
580
Stefan Reinauera1e48242011-10-21 14:24:57 -0700581static const struct command commands[] = {
Vadim Bendebury458a12e2014-12-23 15:10:12 -0800582 {"add", "H;f:n:t:b:vh?", cbfs_add},
583 {"add-payload", "H:f:n:t:c:b:vh?C:I:", cbfs_add_payload},
584 {"add-stage", "H:f:n:t:c:b:S:vh?", cbfs_add_stage},
585 {"add-flat-binary", "H:f:n:l:e:c:b:vh?", cbfs_add_flat_binary},
586 {"add-int", "H:i:n:b:vh?", cbfs_add_integer},
587 {"remove", "H:n:vh?", cbfs_remove},
Vadim Bendebury5e273a42014-12-23 19:26:54 -0800588 {"copy", "H:D:s:", cbfs_copy},
Hung-Te Linf56c73f2013-01-29 09:45:12 +0800589 {"create", "s:B:b:H:a:o:m:vh?", cbfs_create},
Vadim Bendebury458a12e2014-12-23 15:10:12 -0800590 {"locate", "H:f:n:P:a:Tvh?", cbfs_locate},
591 {"print", "H:vh?", cbfs_print},
592 {"extract", "H:n:f:vh?", cbfs_extract},
593 {"update-fit", "H:n:x:vh?", cbfs_update_fit},
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000594};
595
Stefan Reinauer63217582012-10-29 16:52:36 -0700596static struct option long_options[] = {
Julius Wernerefcee762014-11-10 13:14:24 -0800597 {"name", required_argument, 0, 'n' },
598 {"type", required_argument, 0, 't' },
599 {"compression", required_argument, 0, 'c' },
600 {"base-address", required_argument, 0, 'b' },
601 {"load-address", required_argument, 0, 'l' },
602 {"top-aligned", required_argument, 0, 'T' },
Vadim Bendebury5e273a42014-12-23 19:26:54 -0800603 {"copy-offset", required_argument, 0, 'D' },
Julius Wernerefcee762014-11-10 13:14:24 -0800604 {"entry-point", required_argument, 0, 'e' },
605 {"size", required_argument, 0, 's' },
606 {"bootblock", required_argument, 0, 'B' },
607 {"header-offset", required_argument, 0, 'H' },
608 {"alignment", required_argument, 0, 'a' },
609 {"page-size", required_argument, 0, 'P' },
610 {"offset", required_argument, 0, 'o' },
611 {"file", required_argument, 0, 'f' },
612 {"int", required_argument, 0, 'i' },
613 {"machine", required_argument, 0, 'm' },
614 {"empty-fits", required_argument, 0, 'x' },
615 {"initrd", required_argument, 0, 'I' },
616 {"cmdline", required_argument, 0, 'C' },
617 {"ignore-sec", required_argument, 0, 'S' },
618 {"verbose", no_argument, 0, 'v' },
619 {"help", no_argument, 0, 'h' },
620 {NULL, 0, 0, 0 }
Stefan Reinauer63217582012-10-29 16:52:36 -0700621};
622
623static void usage(char *name)
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000624{
625 printf
Stefan Reinauer07040582010-04-24 21:24:06 +0000626 ("cbfstool: Management utility for CBFS formatted ROM images\n\n"
Stefan Reinauer63217582012-10-29 16:52:36 -0700627 "USAGE:\n" " %s [-h]\n"
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800628 " %s FILE COMMAND [-v] [PARAMETERS]...\n\n" "OPTIONs:\n"
Vadim Bendebury458a12e2014-12-23 15:10:12 -0800629 " -H header_offset Do not search for header, use this offset\n"
630 " -T Output top-aligned memory address\n"
631 " -v Provide verbose output\n"
632 " -h Display this help message\n\n"
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000633 "COMMANDs:\n"
David Hendricks90ca3b62012-11-16 14:48:22 -0800634 " add -f FILE -n NAME -t TYPE [-b base-address] "
Stefan Reinauer63217582012-10-29 16:52:36 -0700635 "Add a component\n"
David Hendricks90ca3b62012-11-16 14:48:22 -0800636 " add-payload -f FILE -n NAME [-c compression] [-b base] "
Stefan Reinauer63217582012-10-29 16:52:36 -0700637 "Add a payload to the ROM\n"
Patrick Georgide36d332013-08-27 20:22:21 +0200638 " (linux specific: [-C cmdline] [-I initrd])\n"
Furquan Shaikh405304a2014-10-30 11:44:20 -0700639 " add-stage -f FILE -n NAME [-c compression] [-b base] \\\n"
640 " [-S section-to-ignore] "
Stefan Reinauer63217582012-10-29 16:52:36 -0700641 "Add a stage to the ROM\n"
642 " add-flat-binary -f FILE -n NAME -l load-address \\\n"
David Hendricks90ca3b62012-11-16 14:48:22 -0800643 " -e entry-point [-c compression] [-b base] "
Stefan Reinauer63217582012-10-29 16:52:36 -0700644 "Add a 32bit flat mode binary\n"
Peter Stuge3bfd5b82013-07-09 19:39:13 +0200645 " add-int -i INTEGER -n NAME [-b base] "
646 "Add a raw 64-bit integer value\n"
David Hendricks90ca3b62012-11-16 14:48:22 -0800647 " remove -n NAME "
Stefan Reinauer63217582012-10-29 16:52:36 -0700648 "Remove a component\n"
Vadim Bendebury5e273a42014-12-23 19:26:54 -0800649 " copy -D new_header_offset -s region size \\\n"
650 " [-H source header offset] "
651 "Create a copy (duplicate) cbfs instance\n"
Julius Wernerefcee762014-11-10 13:14:24 -0800652 " create -s size -m ARCH [-B bootblock] [-b bootblock offset] \\\n"
653 " [-o CBFS offset] [-H header offset] [-a align] "
Stefan Reinauer63217582012-10-29 16:52:36 -0700654 "Create a ROM file\n"
Hung-Te Line4ea2ca2013-03-19 12:24:43 +0800655 " locate -f FILE -n NAME [-P page-size] [-a align] [-T] "
Stefan Reinauer63217582012-10-29 16:52:36 -0700656 "Find a place for a file of that size\n"
David Hendricks90ca3b62012-11-16 14:48:22 -0800657 " print "
Stefan Reinauer63217582012-10-29 16:52:36 -0700658 "Show the contents of the ROM\n"
David Hendricks90ca3b62012-11-16 14:48:22 -0800659 " extract -n NAME -f FILE "
Stefan Reinauer63217582012-10-29 16:52:36 -0700660 "Extracts a raw payload from ROM\n"
Aaron Durbin6b0d0d62012-12-14 17:16:21 -0600661 " update-fit -n MICROCODE_BLOB_NAME -x EMTPY_FIT_ENTRIES\n "
662 "Updates the FIT table with microcode entries\n"
Peter Stugeb347e0d2011-01-17 05:02:09 +0000663 "\n"
David Hendricks90ca3b62012-11-16 14:48:22 -0800664 "ARCHes:\n"
Paul Burton33186922014-06-13 23:56:45 +0100665 " arm64, arm, mips, x86\n"
Stefan Reinauer63217582012-10-29 16:52:36 -0700666 "TYPEs:\n", name, name
667 );
Stefan Reinauer07040582010-04-24 21:24:06 +0000668 print_supported_filetypes();
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000669}
670
671int main(int argc, char **argv)
672{
Mathias Krause41c229c2012-07-17 21:17:15 +0200673 size_t i;
Stefan Reinauer63217582012-10-29 16:52:36 -0700674 int c;
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000675
676 if (argc < 3) {
Stefan Reinauer63217582012-10-29 16:52:36 -0700677 usage(argv[0]);
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000678 return 1;
679 }
680
Hung-Te Lind1739622013-01-28 14:23:49 +0800681 param.cbfs_name = argv[1];
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000682 char *cmd = argv[2];
Stefan Reinauer63217582012-10-29 16:52:36 -0700683 optind += 2;
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000684
685 for (i = 0; i < ARRAY_SIZE(commands); i++) {
686 if (strcmp(cmd, commands[i].name) != 0)
687 continue;
Stefan Reinauer63217582012-10-29 16:52:36 -0700688
689 while (1) {
690 char *suffix = NULL;
691 int option_index = 0;
692
693 c = getopt_long(argc, argv, commands[i].optstring,
694 long_options, &option_index);
695 if (c == -1)
696 break;
697
698 /* filter out illegal long options */
zbao062730d2013-01-08 10:10:16 +0800699 if (strchr(commands[i].optstring, c) == NULL) {
Stefan Reinauer63217582012-10-29 16:52:36 -0700700 /* TODO maybe print actual long option instead */
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800701 ERROR("%s: invalid option -- '%c'\n",
702 argv[0], c);
Stefan Reinauer63217582012-10-29 16:52:36 -0700703 c = '?';
704 }
705
706 switch(c) {
707 case 'n':
Hung-Te Lind1739622013-01-28 14:23:49 +0800708 param.name = optarg;
Stefan Reinauer63217582012-10-29 16:52:36 -0700709 break;
710 case 't':
711 if (intfiletype(optarg) != ((uint64_t) - 1))
Hung-Te Lind1739622013-01-28 14:23:49 +0800712 param.type = intfiletype(optarg);
Stefan Reinauer63217582012-10-29 16:52:36 -0700713 else
Hung-Te Lind1739622013-01-28 14:23:49 +0800714 param.type = strtoul(optarg, NULL, 0);
715 if (param.type == 0)
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800716 WARN("Unknown type '%s' ignored\n",
Stefan Reinauer63217582012-10-29 16:52:36 -0700717 optarg);
718 break;
719 case 'c':
720 if (!strncasecmp(optarg, "lzma", 5))
Hung-Te Lind1739622013-01-28 14:23:49 +0800721 param.algo = CBFS_COMPRESS_LZMA;
Stefan Reinauer63217582012-10-29 16:52:36 -0700722 else if (!strncasecmp(optarg, "none", 5))
Hung-Te Lind1739622013-01-28 14:23:49 +0800723 param.algo = CBFS_COMPRESS_NONE;
Stefan Reinauer63217582012-10-29 16:52:36 -0700724 else
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800725 WARN("Unknown compression '%s'"
726 " ignored.\n", optarg);
Stefan Reinauer63217582012-10-29 16:52:36 -0700727 break;
728 case 'b':
Hung-Te Lind1739622013-01-28 14:23:49 +0800729 param.baseaddress = strtoul(optarg, NULL, 0);
Hung-Te Linf56c73f2013-01-29 09:45:12 +0800730 // baseaddress may be zero on non-x86, so we
731 // need an explicit "baseaddress_assigned".
732 param.baseaddress = strtoul(optarg, NULL, 0);
733 param.baseaddress_assigned = 1;
Stefan Reinauer63217582012-10-29 16:52:36 -0700734 break;
735 case 'l':
Hung-Te Lind1739622013-01-28 14:23:49 +0800736 param.loadaddress = strtoul(optarg, NULL, 0);
Stefan Reinauer63217582012-10-29 16:52:36 -0700737 break;
738 case 'e':
Hung-Te Lind1739622013-01-28 14:23:49 +0800739 param.entrypoint = strtoul(optarg, NULL, 0);
Stefan Reinauer63217582012-10-29 16:52:36 -0700740 break;
741 case 's':
Hung-Te Lind1739622013-01-28 14:23:49 +0800742 param.size = strtoul(optarg, &suffix, 0);
Stefan Reinauer63217582012-10-29 16:52:36 -0700743 if (tolower(suffix[0])=='k') {
Hung-Te Lind1739622013-01-28 14:23:49 +0800744 param.size *= 1024;
Stefan Reinauer63217582012-10-29 16:52:36 -0700745 }
746 if (tolower(suffix[0])=='m') {
Hung-Te Lind1739622013-01-28 14:23:49 +0800747 param.size *= 1024 * 1024;
Stefan Reinauer63217582012-10-29 16:52:36 -0700748 }
Patrick Georgie887ca52014-08-09 17:44:39 +0200749 break;
Stefan Reinauer63217582012-10-29 16:52:36 -0700750 case 'B':
Hung-Te Lind1739622013-01-28 14:23:49 +0800751 param.bootblock = optarg;
Stefan Reinauer63217582012-10-29 16:52:36 -0700752 break;
Hung-Te Linf56c73f2013-01-29 09:45:12 +0800753 case 'H':
754 param.headeroffset = strtoul(
755 optarg, NULL, 0);
756 param.headeroffset_assigned = 1;
757 break;
Vadim Bendebury5e273a42014-12-23 19:26:54 -0800758 case 'D':
759 param.copyoffset = strtoul(optarg, NULL, 0);
760 param.copyoffset_assigned = 1;
Vadim Bendebury11614732015-01-08 16:36:35 -0800761 break;
Stefan Reinauer63217582012-10-29 16:52:36 -0700762 case 'a':
Hung-Te Lind1739622013-01-28 14:23:49 +0800763 param.alignment = strtoul(optarg, NULL, 0);
Stefan Reinauer63217582012-10-29 16:52:36 -0700764 break;
Hung-Te Line9198372013-03-19 12:17:12 +0800765 case 'P':
766 param.pagesize = strtoul(optarg, NULL, 0);
767 break;
Stefan Reinauer63217582012-10-29 16:52:36 -0700768 case 'o':
Julius Wernerefcee762014-11-10 13:14:24 -0800769 param.cbfsoffset = strtoul(optarg, NULL, 0);
770 param.cbfsoffset_assigned = 1;
Stefan Reinauer63217582012-10-29 16:52:36 -0700771 break;
772 case 'f':
Hung-Te Lind1739622013-01-28 14:23:49 +0800773 param.filename = optarg;
Stefan Reinauer63217582012-10-29 16:52:36 -0700774 break;
Peter Stuge3bfd5b82013-07-09 19:39:13 +0200775 case 'i':
776 param.u64val = strtoull(optarg, NULL, 0);
777 break;
Hung-Te Lin215d1d72013-01-29 03:46:02 +0800778 case 'T':
779 param.top_aligned = 1;
780 break;
Aaron Durbin6b0d0d62012-12-14 17:16:21 -0600781 case 'x':
782 param.fit_empty_entries = strtol(optarg, NULL, 0);
783 break;
Stefan Reinauer63217582012-10-29 16:52:36 -0700784 case 'v':
785 verbose++;
786 break;
David Hendricks90ca3b62012-11-16 14:48:22 -0800787 case 'm':
Alexandru Gagniuc35850ae2014-02-02 22:37:28 -0600788 param.arch = string_to_arch(optarg);
David Hendricks90ca3b62012-11-16 14:48:22 -0800789 break;
Patrick Georgide36d332013-08-27 20:22:21 +0200790 case 'I':
791 param.initrd = optarg;
792 break;
793 case 'C':
794 param.cmdline = optarg;
795 break;
Furquan Shaikh405304a2014-10-30 11:44:20 -0700796 case 'S':
797 param.ignore_section = optarg;
798 break;
Stefan Reinauer63217582012-10-29 16:52:36 -0700799 case 'h':
800 case '?':
801 usage(argv[0]);
802 return 1;
803 default:
804 break;
805 }
806 }
807
808 return commands[i].function();
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000809 }
810
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800811 ERROR("Unknown command '%s'.\n", cmd);
Stefan Reinauer63217582012-10-29 16:52:36 -0700812 usage(argv[0]);
Stefan Reinauer3fec29c2009-09-22 15:58:19 +0000813 return 1;
814}