blob: 3394b7b5368a634987c9f23a797686f31265e9fe [file] [log] [blame]
Patrick Georgib7b56dd82009-09-14 13:29:27 +00001/*
2 * common utility functions for cbfstool
3 *
4 * 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.
Patrick Georgib7b56dd82009-09-14 13:29:27 +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
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
Uwe Hermann942a40d2010-02-10 19:52:35 +000025#include <libgen.h>
Patrick Georgib7b56dd82009-09-14 13:29:27 +000026#include "common.h"
27#include "cbfs.h"
28#include "elf.h"
29
Stefan Reinauer63217582012-10-29 16:52:36 -070030size_t getfilesize(const char *filename)
Patrick Georgi0da38dd2009-11-09 17:18:02 +000031{
Stefan Reinauer63217582012-10-29 16:52:36 -070032 size_t size;
Patrick Georgi0da38dd2009-11-09 17:18:02 +000033 FILE *file = fopen(filename, "rb");
Stefan Reinauer63217582012-10-29 16:52:36 -070034 if (file == NULL)
35 return -1;
36
Patrick Georgi0da38dd2009-11-09 17:18:02 +000037 fseek(file, 0, SEEK_END);
38 size = ftell(file);
39 fclose(file);
40 return size;
41}
42
Patrick Georgib7b56dd82009-09-14 13:29:27 +000043void *loadfile(const char *filename, uint32_t * romsize_p, void *content,
44 int place)
45{
46 FILE *file = fopen(filename, "rb");
Patrick Georgi45d8a832009-09-15 08:21:46 +000047 if (file == NULL)
48 return NULL;
Stefan Reinauer63217582012-10-29 16:52:36 -070049
Patrick Georgib7b56dd82009-09-14 13:29:27 +000050 fseek(file, 0, SEEK_END);
51 *romsize_p = ftell(file);
52 fseek(file, 0, SEEK_SET);
Stefan Reinauer853270a2009-09-22 15:55:01 +000053 if (!content) {
Patrick Georgib7b56dd82009-09-14 13:29:27 +000054 content = malloc(*romsize_p);
Stefan Reinauer853270a2009-09-22 15:55:01 +000055 if (!content) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +080056 ERROR("Could not get %d bytes for file %s\n",
57 *romsize_p, filename);
Stefan Reinauer853270a2009-09-22 15:55:01 +000058 exit(1);
59 }
60 } else if (place == SEEK_END)
Patrick Georgib7b56dd82009-09-14 13:29:27 +000061 content -= *romsize_p;
Stefan Reinauer853270a2009-09-22 15:55:01 +000062
Patrick Georgib7b56dd82009-09-14 13:29:27 +000063 if (!fread(content, *romsize_p, 1, file)) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +080064 ERROR("Failed to read %s\n", filename);
Patrick Georgib7b56dd82009-09-14 13:29:27 +000065 return NULL;
66 }
67 fclose(file);
68 return content;
69}
70
Stefan Reinauer63217582012-10-29 16:52:36 -070071static struct cbfs_header *master_header;
72static uint32_t phys_start, phys_end, align;
73uint32_t romsize;
Patrick Georgib7b56dd82009-09-14 13:29:27 +000074void *offset;
David Hendricks90ca3b62012-11-16 14:48:22 -080075uint32_t arch = CBFS_ARCHITECTURE_UNKNOWN;
76
77static struct {
78 uint32_t arch;
79 const char *name;
80} arch_names[] = {
81 { CBFS_ARCHITECTURE_ARMV7, "armv7" },
82 { CBFS_ARCHITECTURE_X86, "x86" },
83 { CBFS_ARCHITECTURE_UNKNOWN, "unknown" }
84};
85
86uint32_t string_to_arch(const char *arch_string)
87{
88 int i;
89 uint32_t ret = CBFS_ARCHITECTURE_UNKNOWN;
90
91 for (i = 0; i < ARRAY_SIZE(arch_names); i++) {
92 if (!strcasecmp(arch_string, arch_names[i].name)) {
93 ret = arch_names[i].arch;
94 break;
95 }
96 }
97
98 return ret;
99}
100
101const char *arch_to_string(uint32_t a)
102{
103 int i;
104 const char *ret = NULL;
105
106 for (i = 0; i < ARRAY_SIZE(arch_names); i++) {
107 if (a == arch_names[i].arch) {
108 ret = arch_names[i].name;
109 break;
110 }
111 }
112
113 return ret;
114
115}
116
117int find_master_header(void *romarea, size_t size)
118{
119 size_t offset;
120
121 if (master_header)
122 return 0;
123
124 for (offset = 0; offset < size - sizeof(struct cbfs_header); offset++) {
125 struct cbfs_header *tmp = romarea + offset;
126
127 if (tmp->magic == ntohl(CBFS_HEADER_MAGIC)) {
128 master_header = tmp;
129 break;
130 }
131 }
132
133 return master_header ? 0 : 1;
134}
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000135
136void recalculate_rom_geometry(void *romarea)
137{
David Hendricks90ca3b62012-11-16 14:48:22 -0800138 if (find_master_header(romarea, romsize)) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800139 ERROR("Cannot find master header\n");
David Hendricks90ca3b62012-11-16 14:48:22 -0800140 exit(1);
141 }
142
143 /* Update old headers */
Hung-Te Lin086842a2013-01-04 12:33:03 +0800144 if (master_header->version == CBFS_HEADER_VERSION1 &&
David Hendricks90ca3b62012-11-16 14:48:22 -0800145 ntohl(master_header->architecture) == CBFS_ARCHITECTURE_UNKNOWN) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800146 DEBUG("Updating CBFS master header to version 2\n");
David Hendricks90ca3b62012-11-16 14:48:22 -0800147 master_header->architecture = htonl(CBFS_ARCHITECTURE_X86);
148 }
149
150 arch = ntohl(master_header->architecture);
151
152 switch (arch) {
153 case CBFS_ARCHITECTURE_ARMV7:
154 offset = romarea;
155 phys_start = (0 + ntohl(master_header->offset)) & 0xffffffff;
156 phys_end = romsize & 0xffffffff;
157 break;
158 case CBFS_ARCHITECTURE_X86:
159 offset = romarea + romsize - 0x100000000ULL;
160 phys_start = (0 - romsize + ntohl(master_header->offset)) &
161 0xffffffff;
162 phys_end = (0 - ntohl(master_header->bootblocksize) -
163 sizeof(struct cbfs_header)) & 0xffffffff;
164 break;
165 default:
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800166 ERROR("Unknown architecture\n");
David Hendricks90ca3b62012-11-16 14:48:22 -0800167 exit(1);
168 }
169
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000170 align = ntohl(master_header->align);
171}
172
173void *loadrom(const char *filename)
174{
175 void *romarea = loadfile(filename, &romsize, 0, SEEK_SET);
Patrick Georgi45d8a832009-09-15 08:21:46 +0000176 if (romarea == NULL)
177 return NULL;
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000178 recalculate_rom_geometry(romarea);
179 return romarea;
180}
181
Stefan Reinauer9bb043852010-06-24 13:37:59 +0000182int writerom(const char *filename, void *start, uint32_t size)
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000183{
184 FILE *file = fopen(filename, "wb");
Stefan Reinauer9bb043852010-06-24 13:37:59 +0000185 if (!file) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800186 ERROR("Could not open '%s' for writing: ", filename);
Stefan Reinauer9bb043852010-06-24 13:37:59 +0000187 perror("");
188 return 1;
189 }
190
191 if (fwrite(start, size, 1, file) != 1) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800192 ERROR("Could not write to '%s': ", filename);
Stefan Reinauer9bb043852010-06-24 13:37:59 +0000193 perror("");
194 return 1;
195 }
196
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000197 fclose(file);
Stefan Reinauer9bb043852010-06-24 13:37:59 +0000198 return 0;
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000199}
200
David Hendricks90ca3b62012-11-16 14:48:22 -0800201int cbfs_file_header(unsigned long physaddr)
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000202{
203 /* maybe improve this test */
204 return (strncmp(phys_to_virt(physaddr), "LARCHIVE", 8) == 0);
205}
206
207struct cbfs_file *cbfs_create_empty_file(uint32_t physaddr, uint32_t size)
208{
209 struct cbfs_file *nextfile = (struct cbfs_file *)phys_to_virt(physaddr);
Stefan Reinauera1e48242011-10-21 14:24:57 -0700210 strncpy((char *)(nextfile->magic), "LARCHIVE", 8);
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000211 nextfile->len = htonl(size);
212 nextfile->type = htonl(0xffffffff);
213 nextfile->checksum = 0; // FIXME?
214 nextfile->offset = htonl(sizeof(struct cbfs_file) + 16);
215 memset(((void *)nextfile) + sizeof(struct cbfs_file), 0, 16);
216 return nextfile;
217}
218
219int iself(unsigned char *input)
220{
221 Elf32_Ehdr *ehdr = (Elf32_Ehdr *) input;
222 return !memcmp(ehdr->e_ident, ELFMAG, 4);
223}
224
Mathias Krause941158f2012-04-12 21:36:23 +0200225static struct filetypes_t {
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000226 uint32_t type;
227 const char *name;
228} filetypes[] = {
229 {CBFS_COMPONENT_STAGE, "stage"},
230 {CBFS_COMPONENT_PAYLOAD, "payload"},
231 {CBFS_COMPONENT_OPTIONROM, "optionrom"},
Stefan Reinauer800379f2010-03-01 08:34:19 +0000232 {CBFS_COMPONENT_BOOTSPLASH, "bootsplash"},
233 {CBFS_COMPONENT_RAW, "raw"},
234 {CBFS_COMPONENT_VSA, "vsa"},
235 {CBFS_COMPONENT_MBI, "mbi"},
236 {CBFS_COMPONENT_MICROCODE, "microcode"},
Patrick Georgia865b172011-01-14 07:40:24 +0000237 {CBFS_COMPONENT_CMOS_DEFAULT, "cmos default"},
Mathias Krause941158f2012-04-12 21:36:23 +0200238 {CBFS_COMPONENT_CMOS_LAYOUT, "cmos layout"},
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000239 {CBFS_COMPONENT_DELETED, "deleted"},
240 {CBFS_COMPONENT_NULL, "null"}
241};
242
Stefan Reinauer07040582010-04-24 21:24:06 +0000243void print_supported_filetypes(void)
244{
245 int i, number = ARRAY_SIZE(filetypes);
246
247 for (i=0; i<number; i++) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800248 LOG(" %s%c", filetypes[i].name, (i==(number-1))?'\n':',');
Stefan Reinauer07040582010-04-24 21:24:06 +0000249 if ((i%8) == 7)
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800250 LOG("\n");
Stefan Reinauer07040582010-04-24 21:24:06 +0000251 }
252}
253
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000254const char *strfiletype(uint32_t number)
255{
Mathias Krause41c229c2012-07-17 21:17:15 +0200256 size_t i;
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000257 for (i = 0; i < (sizeof(filetypes) / sizeof(struct filetypes_t)); i++)
258 if (filetypes[i].type == number)
259 return filetypes[i].name;
260 return "unknown";
261}
262
263uint64_t intfiletype(const char *name)
264{
Mathias Krause41c229c2012-07-17 21:17:15 +0200265 size_t i;
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000266 for (i = 0; i < (sizeof(filetypes) / sizeof(struct filetypes_t)); i++)
267 if (strcmp(filetypes[i].name, name) == 0)
268 return filetypes[i].type;
269 return -1;
270}
271
272void print_cbfs_directory(const char *filename)
273{
Hung-Te Lin5a9f45c2013-01-28 23:42:25 +0800274 char *name = strdup(filename);
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000275 printf
Stefan Reinauerdb5b8932013-01-18 15:53:22 -0800276 ("%s: %d kB, bootblocksize %d, romsize %d, offset 0x%x\n"
277 "alignment: %d bytes, architecture: %s\n\n",
Hung-Te Lin5a9f45c2013-01-28 23:42:25 +0800278 basename(name), romsize / 1024, ntohl(master_header->bootblocksize),
Stefan Reinauerdb5b8932013-01-18 15:53:22 -0800279 romsize, ntohl(master_header->offset), align, arch_to_string(arch));
Hung-Te Lin5a9f45c2013-01-28 23:42:25 +0800280 free(name);
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000281 printf("%-30s %-10s %-12s Size\n", "Name", "Offset", "Type");
282 uint32_t current = phys_start;
283 while (current < phys_end) {
284 if (!cbfs_file_header(current)) {
285 current += align;
286 continue;
287 }
288 struct cbfs_file *thisfile =
Stefan Reinauerdb5b8932013-01-18 15:53:22 -0800289 (struct cbfs_file *)phys_to_virt(current);
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000290 uint32_t length = ntohl(thisfile->len);
Maciej Pijankaf44eb782010-01-07 21:37:18 +0000291 char *fname = (char *)(phys_to_virt(current) + sizeof(struct cbfs_file));
Stefan Reinauer14e22772010-04-27 06:56:47 +0000292 if (strlen(fname) == 0)
Maciej Pijankaf44eb782010-01-07 21:37:18 +0000293 fname = "(empty)";
294
Stefan Reinauer14e22772010-04-27 06:56:47 +0000295 printf("%-30s 0x%-8x %-12s %d\n", fname,
David Hendricks90ca3b62012-11-16 14:48:22 -0800296 current - phys_start + ntohl(master_header->offset),
297 strfiletype(ntohl(thisfile->type)), length);
Stefan Reinauerdb5b8932013-01-18 15:53:22 -0800298
299 /* note the components of the subheader are in host order ... */
300 switch (ntohl(thisfile->type)) {
301 case CBFS_COMPONENT_STAGE:
302 {
303 struct cbfs_stage *stage = CBFS_SUBHEADER(thisfile);
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800304 INFO(" %s compression, entry: 0x%llx, load: 0x%llx, length: %d/%d\n",
Stefan Reinauerdb5b8932013-01-18 15:53:22 -0800305 stage->compression == CBFS_COMPRESS_LZMA ? "LZMA" : "no",
306 (unsigned long long)stage->entry,
307 (unsigned long long)stage->load,
308 stage->len,
309 stage->memlen);
310 break;
311 }
312 case CBFS_COMPONENT_PAYLOAD:
313 {
314 struct cbfs_payload_segment *payload = CBFS_SUBHEADER(thisfile);
315 while(payload) {
316 switch(payload->type) {
317 case PAYLOAD_SEGMENT_CODE:
318 case PAYLOAD_SEGMENT_DATA:
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800319 INFO(" %s (%s compression, offset: 0x%x, load: 0x%llx, length: %d/%d)\n",
Stefan Reinauerdb5b8932013-01-18 15:53:22 -0800320 payload->type == PAYLOAD_SEGMENT_CODE ? "code " : "data" ,
321 payload->compression == CBFS_COMPRESS_LZMA ? "LZMA" : "no",
322 ntohl(payload->offset),
323 (unsigned long long)ntohll(payload->load_addr),
324 ntohl(payload->len), ntohl(payload->mem_len));
325 break;
326 case PAYLOAD_SEGMENT_ENTRY:
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800327 INFO(" entry (0x%llx)\n", (unsigned long long)ntohll(payload->load_addr));
Stefan Reinauerdb5b8932013-01-18 15:53:22 -0800328 break;
329 case PAYLOAD_SEGMENT_BSS:
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800330 INFO(" BSS (address 0x%016llx, length 0x%x)\n", (unsigned long long)ntohll(payload->load_addr), ntohl(payload->len));
Stefan Reinauerdb5b8932013-01-18 15:53:22 -0800331 break;
332 case PAYLOAD_SEGMENT_PARAMS:
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800333 INFO(" parameters\n");
Stefan Reinauerdb5b8932013-01-18 15:53:22 -0800334 break;
335 default:
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800336 INFO(" %x (%s compression, offset: 0x%x, load: 0x%llx, length: %d/%d\n",
Stefan Reinauerdb5b8932013-01-18 15:53:22 -0800337 payload->type,
338 payload->compression == CBFS_COMPRESS_LZMA ? "LZMA" : "no",
339 ntohl(payload->offset),
340 (unsigned long long)ntohll(payload->load_addr),
341 ntohl(payload->len),
342 ntohl(payload->mem_len));
343 break;
344 }
345
346 if(payload->type == PAYLOAD_SEGMENT_ENTRY)
347 payload=NULL;
348 else
349 payload++;
350 }
351 break;
352 }
353 default:
354 break;
355 }
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000356 current =
357 ALIGN(current + ntohl(thisfile->len) +
358 ntohl(thisfile->offset), align);
359 }
360}
361
Aurelien Guillaumefe7d6b92011-01-13 09:09:21 +0000362int extract_file_from_cbfs(const char *filename, const char *payloadname, const char *outpath)
363{
Aurelien Guillaumefe7d6b92011-01-13 09:09:21 +0000364 FILE *outfile = NULL;
365 uint32_t current = phys_start;
366 while (current < phys_end) {
367 if (!cbfs_file_header(current)) {
368 current += align;
369 continue;
370 }
371
372 // Locate the file start struct
373 struct cbfs_file *thisfile =
374 (struct cbfs_file *)phys_to_virt(current);
375 // And its length
376 uint32_t length = ntohl(thisfile->len);
377 // Locate the file name
378 char *fname = (char *)(phys_to_virt(current) + sizeof(struct cbfs_file));
Stefan Reinauera1e48242011-10-21 14:24:57 -0700379
Aurelien Guillaumefe7d6b92011-01-13 09:09:21 +0000380 // It's not the file we are looking for..
381 if (strcmp(fname, payloadname) != 0)
382 {
383 current =
384 ALIGN(current + ntohl(thisfile->len) +
385 ntohl(thisfile->offset), align);
386 continue;
387 }
388
389 // Else, it's our file.
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800390 LOG("Found file %.30s at 0x%x, type %.12s, size %d\n", fname,
Aurelien Guillaumefe7d6b92011-01-13 09:09:21 +0000391 current - phys_start, strfiletype(ntohl(thisfile->type)),
392 length);
393
394 // If we are not dumping to stdout, open the out file.
395 outfile = fopen(outpath, "wb");
396 if (!outfile)
397 {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800398 ERROR("Could not open the file %s for writing.\n", outpath);
Aurelien Guillaumefe7d6b92011-01-13 09:09:21 +0000399 return 1;
400 }
401
402 if (ntohl(thisfile->type) != CBFS_COMPONENT_RAW)
403 {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800404 WARN("Only 'raw' files are safe to extract.\n");
Aurelien Guillaumefe7d6b92011-01-13 09:09:21 +0000405 }
406
407 fwrite(((char *)thisfile)
408 + ntohl(thisfile->offset), length, 1, outfile);
409
410 fclose(outfile);
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800411 LOG("Successfully dumped the file.\n");
Aurelien Guillaumefe7d6b92011-01-13 09:09:21 +0000412
413 // We'll only dump one file.
414 return 0;
415 }
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800416 ERROR("File %s not found.\n", payloadname);
Stefan Reinauera1e48242011-10-21 14:24:57 -0700417 return 1;
Aurelien Guillaumefe7d6b92011-01-13 09:09:21 +0000418}
419
420
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000421int add_file_to_cbfs(void *content, uint32_t contentsize, uint32_t location)
422{
423 uint32_t current = phys_start;
424 while (current < phys_end) {
425 if (!cbfs_file_header(current)) {
426 current += align;
427 continue;
428 }
429 struct cbfs_file *thisfile =
430 (struct cbfs_file *)phys_to_virt(current);
431 uint32_t length = ntohl(thisfile->len);
432
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800433 DEBUG("at %x, %x bytes\n", current, length);
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000434 /* Is this a free chunk? */
435 if ((thisfile->type == CBFS_COMPONENT_DELETED)
436 || (thisfile->type == CBFS_COMPONENT_NULL)) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800437 DEBUG("null||deleted at %x, %x bytes\n", current,
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000438 length);
439 /* if this is the right size, and if specified, the right location, use it */
440 if ((contentsize <= length)
441 && ((location == 0) || (current == location))) {
442 if (contentsize < length) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800443 DEBUG("this chunk is %x bytes, we need %x. create a new chunk at %x with %x bytes\n",
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000444 length, contentsize,
445 ALIGN(current + contentsize,
446 align),
447 length - contentsize);
448 uint32_t start =
449 ALIGN(current + contentsize, align);
450 uint32_t size =
451 current + ntohl(thisfile->offset)
452 + length - start - 16 -
453 sizeof(struct cbfs_file);
454 cbfs_create_empty_file(start, size);
455 }
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800456 DEBUG("copying data\n");
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000457 memcpy(phys_to_virt(current), content,
458 contentsize);
Patrick Georgi56f5fb72009-09-30 11:21:18 +0000459 return 0;
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000460 }
Patrick Georgi56f5fb72009-09-30 11:21:18 +0000461 if (location != 0) {
462 /* CBFS has the constraint that the chain always moves up in memory. so once
463 we're past the place we seek, we don't need to look any further */
464 if (current > location) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800465 ERROR("The requested space is not available\n");
Patrick Georgi56f5fb72009-09-30 11:21:18 +0000466 return 1;
467 }
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000468
Patrick Georgi56f5fb72009-09-30 11:21:18 +0000469 /* Is the requested location inside the current chunk? */
470 if ((current < location)
471 && ((location + contentsize) <=
472 (current + length))) {
473 /* Split it up. In the next iteration the code will be at the right place. */
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800474 DEBUG("split up. new length: %x\n",
Patrick Georgi56f5fb72009-09-30 11:21:18 +0000475 location - current -
476 ntohl(thisfile->offset));
477 thisfile->len =
478 htonl(location - current -
479 ntohl(thisfile->offset));
Stefan Reinauera1e48242011-10-21 14:24:57 -0700480 cbfs_create_empty_file(location,
Patrick Georgi56f5fb72009-09-30 11:21:18 +0000481 length -
482 (location -
483 current));
484 }
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000485 }
486 }
487 current =
488 ALIGN(current + ntohl(thisfile->len) +
489 ntohl(thisfile->offset), align);
490 }
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800491 ERROR("Could not add the file to CBFS, it's probably too big.\n");
492 ERROR("File size: %d bytes (%d KB).\n", contentsize, contentsize/1024);
Patrick Georgi56f5fb72009-09-30 11:21:18 +0000493 return 1;
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000494}
495
Gabe Blacke1bb49e2012-01-27 00:33:47 -0800496
497static struct cbfs_file *merge_adjacent_files(struct cbfs_file *first,
498 struct cbfs_file *second)
499{
500 uint32_t new_length =
501 ntohl(first->len) + ntohl(second->len) + ntohl(second->offset);
502 first->len = htonl(new_length);
503 first->checksum = 0; // FIXME?
504 return first;
505}
506
507static struct cbfs_file *next_file(struct cbfs_file *prev)
508{
509 uint32_t pos = (prev == NULL) ? phys_start :
510 ALIGN(virt_to_phys(prev) + ntohl(prev->len) + ntohl(prev->offset),
511 align);
512
513 for (; pos < phys_end; pos += align) {
514 if (cbfs_file_header(pos))
515 return (struct cbfs_file *)phys_to_virt(pos);
516 }
517 return NULL;
518}
519
520
521int remove_file_from_cbfs(const char *filename)
522{
523 struct cbfs_file *prev = NULL;
524 struct cbfs_file *cur = next_file(prev);
525 struct cbfs_file *next = next_file(cur);
526 for (; cur; prev = cur, cur = next, next = next_file(next)) {
527
528 /* Check if this is the file to remove. */
529 char *name = (char *)cur + sizeof(*cur);
530 if (strcmp(name, filename))
531 continue;
532
533 /* Mark the file as free space and erase its name. */
534 cur->type = CBFS_COMPONENT_NULL;
535 name[0] = '\0';
536
537 /* Merge it with the previous file if possible. */
538 if (prev && prev->type == CBFS_COMPONENT_NULL)
539 cur = merge_adjacent_files(prev, cur);
540
541 /* Merge it with the next file if possible. */
542 if (next && next->type == CBFS_COMPONENT_NULL)
543 merge_adjacent_files(cur, next);
544
545 return 0;
546 }
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800547 ERROR("CBFS file %s not found.\n", filename);
Gabe Blacke1bb49e2012-01-27 00:33:47 -0800548 return 1;
549}
550
551
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000552/* returns new data block with cbfs_file header, suitable to dump into the ROM. location returns
553 the new location that points to the cbfs_file header */
554void *create_cbfs_file(const char *filename, void *data, uint32_t * datasize,
555 uint32_t type, uint32_t * location)
556{
557 uint32_t filename_len = ALIGN(strlen(filename) + 1, 16);
558 uint32_t headersize = sizeof(struct cbfs_file) + filename_len;
559 if ((location != 0) && (*location != 0)) {
560 uint32_t offset = *location % align;
561 /* If offset >= (headersize % align), we can stuff the header into the offset.
562 Otherwise the header has to be aligned itself, and put before the offset data */
563 if (offset >= (headersize % align)) {
564 offset -= (headersize % align);
565 } else {
566 offset += align - (headersize % align);
567 }
568 headersize += offset;
569 *location -= headersize;
570 }
571 void *newdata = malloc(*datasize + headersize);
Stefan Reinauer853270a2009-09-22 15:55:01 +0000572 if (!newdata) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800573 ERROR("Could not get %d bytes for CBFS file.\n", *datasize +
Patrick Georgi56f5fb72009-09-30 11:21:18 +0000574 headersize);
Stefan Reinauer853270a2009-09-22 15:55:01 +0000575 exit(1);
576 }
Peter Stugef4aca1d2009-12-06 12:14:39 +0000577 memset(newdata, 0xff, *datasize + headersize);
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000578 struct cbfs_file *nextfile = (struct cbfs_file *)newdata;
Stefan Reinauera1e48242011-10-21 14:24:57 -0700579 strncpy((char *)(nextfile->magic), "LARCHIVE", 8);
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000580 nextfile->len = htonl(*datasize);
581 nextfile->type = htonl(type);
582 nextfile->checksum = 0; // FIXME?
583 nextfile->offset = htonl(headersize);
584 strcpy(newdata + sizeof(struct cbfs_file), filename);
585 memcpy(newdata + headersize, data, *datasize);
586 *datasize += headersize;
587 return newdata;
588}
589
590int create_cbfs_image(const char *romfile, uint32_t _romsize,
David Hendricks90ca3b62012-11-16 14:48:22 -0800591 const char *bootblock, uint32_t align, uint32_t offs)
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000592{
Stefan Reinauer63217582012-10-29 16:52:36 -0700593 uint32_t bootblocksize = 0;
594 struct cbfs_header *master_header;
595 unsigned char *romarea, *bootblk;
596
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000597 romsize = _romsize;
Stefan Reinauer63217582012-10-29 16:52:36 -0700598 romarea = malloc(romsize);
Stefan Reinauer853270a2009-09-22 15:55:01 +0000599 if (!romarea) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800600 ERROR("Could not get %d bytes of memory"
Stefan Reinauer63217582012-10-29 16:52:36 -0700601 " for CBFS image.\n", romsize);
Stefan Reinauer853270a2009-09-22 15:55:01 +0000602 exit(1);
603 }
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000604 memset(romarea, 0xff, romsize);
Stefan Reinauer853270a2009-09-22 15:55:01 +0000605
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000606 if (align == 0)
607 align = 64;
608
Stefan Reinauer63217582012-10-29 16:52:36 -0700609 bootblk = loadfile(bootblock, &bootblocksize,
610 romarea + romsize, SEEK_END);
611 if (!bootblk) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800612 ERROR("Could not load bootblock %s.\n",
Stefan Reinauer63217582012-10-29 16:52:36 -0700613 bootblock);
614 free(romarea);
615 return 1;
616 }
617
David Hendricks90ca3b62012-11-16 14:48:22 -0800618 // TODO(hungte) Replace magic numbers by named constants.
619 switch (arch) {
620 case CBFS_ARCHITECTURE_ARMV7:
621 /* Set up physical/virtual mapping */
622 offset = romarea;
Stefan Reinauer853270a2009-09-22 15:55:01 +0000623
David Hendricks90ca3b62012-11-16 14:48:22 -0800624 /*
David Hendricks0b23d472013-01-14 20:58:50 -0800625 * The initial jump instruction and bootblock will be placed
626 * before and after the master header, respectively. The
627 * bootblock image must contain a blank, aligned region large
628 * enough for the master header to fit.
David Hendricks90ca3b62012-11-16 14:48:22 -0800629 *
David Hendricks0b23d472013-01-14 20:58:50 -0800630 * An anchor string must be left such that when cbfstool is run
631 * we can find it and insert the master header at the next
632 * aligned boundary.
David Hendricks90ca3b62012-11-16 14:48:22 -0800633 */
David Hendricks0b23d472013-01-14 20:58:50 -0800634 loadfile(bootblock, &bootblocksize, romarea + offs, SEEK_SET);
635
636 unsigned char *p = romarea + offs;
637 while (1) {
638 /* FIXME: assumes little endian... */
639 if (*(uint32_t *)p == 0xdeadbeef)
640 break;
641 if (p >= (romarea + _romsize)) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800642 ERROR("Could not determine CBFS "
643 "header location.\n");
David Hendricks0b23d472013-01-14 20:58:50 -0800644 return 1;
645 }
646 p += (sizeof(unsigned int));
647 }
648 unsigned int u = ALIGN((unsigned int)(p - romarea), align);
649 master_header = (struct cbfs_header *)(romarea + u);
Stefan Reinauer853270a2009-09-22 15:55:01 +0000650
David Hendricks90ca3b62012-11-16 14:48:22 -0800651 master_header->magic = ntohl(CBFS_HEADER_MAGIC);
Hung-Te Lin086842a2013-01-04 12:33:03 +0800652 master_header->version = ntohl(CBFS_HEADER_VERSION);
David Hendricks90ca3b62012-11-16 14:48:22 -0800653 master_header->romsize = htonl(romsize);
654 master_header->bootblocksize = htonl(bootblocksize);
655 master_header->align = htonl(align);
656 master_header->offset = htonl(
657 ALIGN((0x40 + bootblocksize), align));
658 master_header->architecture = htonl(CBFS_ARCHITECTURE_ARMV7);
659
David Hendricks454856b2013-01-02 17:29:00 -0800660 ((uint32_t *) phys_to_virt(0x4 + offs))[0] =
David Hendricks90ca3b62012-11-16 14:48:22 -0800661 virt_to_phys(master_header);
662
663 recalculate_rom_geometry(romarea);
664
665 cbfs_create_empty_file(
David Hendricks454856b2013-01-02 17:29:00 -0800666 offs + ALIGN((0x40 + bootblocksize), align),
667 romsize - offs - sizeof(struct cbfs_file) -
668 ALIGN((bootblocksize + 0x40), align));
David Hendricks90ca3b62012-11-16 14:48:22 -0800669 break;
670
671 case CBFS_ARCHITECTURE_X86:
672 // Set up physical/virtual mapping
673 offset = romarea + romsize - 0x100000000ULL;
674
675 loadfile(bootblock, &bootblocksize, romarea + romsize,
676 SEEK_END);
677 master_header = (struct cbfs_header *)(romarea + romsize -
678 bootblocksize - sizeof(struct cbfs_header));
679
680 master_header->magic = ntohl(CBFS_HEADER_MAGIC);
Hung-Te Lin086842a2013-01-04 12:33:03 +0800681 master_header->version = ntohl(CBFS_HEADER_VERSION);
David Hendricks90ca3b62012-11-16 14:48:22 -0800682 master_header->romsize = htonl(romsize);
683 master_header->bootblocksize = htonl(bootblocksize);
684 master_header->align = htonl(align);
685 master_header->offset = htonl(offs);
686 master_header->architecture = htonl(CBFS_ARCHITECTURE_X86);
687
688 ((uint32_t *) phys_to_virt(CBFS_HEADPTR_ADDR_X86))[0] =
689 virt_to_phys(master_header);
690
691 recalculate_rom_geometry(romarea);
692
693 cbfs_create_empty_file((0 - romsize + offs) & 0xffffffff,
694 romsize - offs - bootblocksize -
695 sizeof(struct cbfs_header) -
696 sizeof(struct cbfs_file) - 16);
697 break;
698
699 default:
700 // Should not happen.
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800701 ERROR("You found a bug in cbfstool.\n");
David Hendricks90ca3b62012-11-16 14:48:22 -0800702 exit(1);
703 }
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000704
705 writerom(romfile, romarea, romsize);
Stefan Reinauer63217582012-10-29 16:52:36 -0700706 free(romarea);
Patrick Georgib7b56dd82009-09-14 13:29:27 +0000707 return 0;
708}
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000709
710static int in_segment(int addr, int size, int gran)
711{
712 return ((addr & ~(gran - 1)) == ((addr + size) & ~(gran - 1)));
713}
714
715uint32_t cbfs_find_location(const char *romfile, uint32_t filesize,
716 const char *filename, uint32_t alignment)
717{
Stefan Reinauer63217582012-10-29 16:52:36 -0700718 void *rom;
719 size_t filename_size, headersize, totalsize;
720 int ret = 0;
721 uint32_t current;
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000722
Stefan Reinauer63217582012-10-29 16:52:36 -0700723 rom = loadrom(romfile);
724 if (rom == NULL) {
Hung-Te Lin4d87d4e2013-01-28 14:39:43 +0800725 ERROR("Could not load ROM image '%s'.\n", romfile);
Stefan Reinauer63217582012-10-29 16:52:36 -0700726 return 0;
727 }
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000728
Stefan Reinauer63217582012-10-29 16:52:36 -0700729 filename_size = strlen(filename);
730 headersize = sizeof(struct cbfs_file) + ALIGN(filename_size + 1, 16) +
731 sizeof(struct cbfs_stage);
732 totalsize = headersize + filesize;
733
734 current = phys_start;
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000735 while (current < phys_end) {
Stefan Reinauer63217582012-10-29 16:52:36 -0700736 uint32_t top;
737 struct cbfs_file *thisfile;
738
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000739 if (!cbfs_file_header(current)) {
740 current += align;
741 continue;
742 }
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000743
Stefan Reinauer63217582012-10-29 16:52:36 -0700744 thisfile = (struct cbfs_file *)phys_to_virt(current);
745
746 top = current + ntohl(thisfile->len) + ntohl(thisfile->offset);
747
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000748 if (((ntohl(thisfile->type) == 0x0)
749 || (ntohl(thisfile->type) == 0xffffffff))
750 && (ntohl(thisfile->len) + ntohl(thisfile->offset) >=
751 totalsize)) {
752 if (in_segment
Stefan Reinauer63217582012-10-29 16:52:36 -0700753 (current + headersize, filesize, alignment)) {
754 ret = current + headersize;
755 break;
756 }
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000757 if ((ALIGN(current, alignment) + filesize < top)
758 && (ALIGN(current, alignment) - headersize >
759 current)
760 && in_segment(ALIGN(current, alignment), filesize,
Stefan Reinauer63217582012-10-29 16:52:36 -0700761 alignment)) {
762 ret = ALIGN(current, alignment);
763 break;
764 }
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000765 if ((ALIGN(current, alignment) + alignment + filesize <
766 top)
767 && (ALIGN(current, alignment) + alignment -
768 headersize > current)
769 && in_segment(ALIGN(current, alignment) + alignment,
Stefan Reinauer63217582012-10-29 16:52:36 -0700770 filesize, alignment)) {
771 ret = ALIGN(current, alignment) + alignment;
772 break;
773 }
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000774 }
775 current =
776 ALIGN(current + ntohl(thisfile->len) +
777 ntohl(thisfile->offset), align);
778 }
Stefan Reinauer63217582012-10-29 16:52:36 -0700779
780 free(rom);
781 return ret;
Patrick Georgi0da38dd2009-11-09 17:18:02 +0000782}