cbfstool: Add cbfs_image new CBFS image manipulation API.
Current cbfstool implementation is relying on global variables to pass processed
data, and the calculation of address is based on x86 architecture (ex, always
assuming 0x0000 as invalid address), not easy to be used on platforms without
top-aligned memory mapping. This CL is a first step to start a new cbfstool
without global variables, and to prevent assuming memory layout in x86 mode.
The first published APIs are for reading and writing existing CBFS ROM image
files (and to find file entries in a ROM file).
Read cbfs_image.h for detail usage of each API function.
Change-Id: I28c737c8f290e51332119188248ac9e28042024c
Signed-off-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-on: http://review.coreboot.org/2194
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
diff --git a/util/cbfstool/Makefile b/util/cbfstool/Makefile
index 17b00a7..3ace744 100644
--- a/util/cbfstool/Makefile
+++ b/util/cbfstool/Makefile
@@ -7,7 +7,7 @@
BINARY:=$(obj)/cbfstool
-COMMON:=cbfstool.o common.o compress.o
+COMMON:=cbfstool.o common.o cbfs_image.o compress.o
COMMON+=cbfs-mkstage.o cbfs-mkpayload.o
# LZMA
COMMON+=lzma/lzma.o
diff --git a/util/cbfstool/Makefile.inc b/util/cbfstool/Makefile.inc
index 5795507..2cee794 100644
--- a/util/cbfstool/Makefile.inc
+++ b/util/cbfstool/Makefile.inc
@@ -2,6 +2,7 @@
cbfsobj += cbfstool.o
cbfsobj += common.o
cbfsobj += compress.o
+cbfsobj += cbfs_image.o
cbfsobj += cbfs-mkstage.o
cbfsobj += cbfs-mkpayload.o
# LZMA
diff --git a/util/cbfstool/cbfs.h b/util/cbfstool/cbfs.h
index 3dbeefd..4a3ff94 100644
--- a/util/cbfstool/cbfs.h
+++ b/util/cbfstool/cbfs.h
@@ -42,6 +42,8 @@
#define CBFS_ARCHITECTURE_X86 0x00000001
#define CBFS_ARCHITECTURE_ARMV7 0x00000010
+#define CBFS_FILE_MAGIC "LARCHIVE"
+
struct cbfs_file {
uint8_t magic[8];
uint32_t len;
diff --git a/util/cbfstool/cbfs_image.c b/util/cbfstool/cbfs_image.c
new file mode 100644
index 0000000..5754453
--- /dev/null
+++ b/util/cbfstool/cbfs_image.c
@@ -0,0 +1,128 @@
+/*
+ * CBFS Image Manipulation
+ *
+ * Copyright (C) 2013 The Chromium OS Authors. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common.h"
+#include "cbfs_image.h"
+
+/* The file name align is not defined in CBFS spec -- only a preference by
+ * (old) cbfstool. */
+#define CBFS_FILENAME_ALIGN (16)
+
+/* To make CBFS more friendly to ROM, fill -1 (0xFF) instead of zero. */
+#define CBFS_CONTENT_DEFAULT_VALUE (-1)
+
+static uint32_t align_up(uint32_t value, uint32_t align) {
+ if (value % align)
+ value += align - (value % align);
+ return value;
+}
+
+int cbfs_image_from_file(struct cbfs_image *image, const char *filename) {
+ if (buffer_from_file(&image->buffer, filename) != 0)
+ return -1;
+ DEBUG("read_cbfs_image: %s (%zd bytes)\n", image->buffer.name,
+ image->buffer.size);
+ image->header = cbfs_find_header(image->buffer.data,
+ image->buffer.size);
+ if (!image->header) {
+ ERROR("%s does not have CBFS master header.\n", filename);
+ cbfs_image_delete(image);
+ return -1;
+ }
+
+ return 0;
+}
+
+int cbfs_image_write_file(struct cbfs_image *image, const char *filename) {
+ assert(image && image->buffer.data);
+ return buffer_write_file(&image->buffer, filename);
+}
+
+int cbfs_image_delete(struct cbfs_image *image) {
+ buffer_delete(&image->buffer);
+ image->header = NULL;
+ return 0;
+}
+
+struct cbfs_header *cbfs_find_header(char *data, size_t size) {
+ size_t offset;
+ int found = 0;
+ uint32_t x86sig;
+ struct cbfs_header *header, *result = NULL;
+
+ // Try x86 style (check signature in bottom) header first.
+ x86sig = *(uint32_t *)(data + size - sizeof(uint32_t));
+ offset = (x86sig + (uint32_t)size);
+ DEBUG("x86sig: 0x%x, offset: 0x%zx\n", x86sig, offset);
+ if (offset >= size - sizeof(*header) ||
+ ntohl(((struct cbfs_header *)(data + offset))->magic) !=
+ CBFS_HEADER_MAGIC)
+ offset = 0;
+
+ for (; offset + sizeof(*header) < size; offset++) {
+ header = (struct cbfs_header *)(data + offset);
+ if (ntohl(header->magic) !=(CBFS_HEADER_MAGIC))
+ continue;
+ if (ntohl(header->version) != CBFS_HEADER_VERSION1 &&
+ ntohl(header->version) != CBFS_HEADER_VERSION2) {
+ // Probably not a real CBFS header?
+ continue;
+ }
+ found++;
+ result = header;
+ }
+ if (found > 1) {
+ ERROR("multiple (%d) CBFS headers found!\n",
+ found);
+ result = NULL;
+ }
+ return result;
+}
+
+
+struct cbfs_file *cbfs_find_first_entry(struct cbfs_image *image) {
+ assert(image && image->header);
+ return (struct cbfs_file *)(image->buffer.data +
+ ntohl(image->header->offset));
+}
+
+struct cbfs_file *cbfs_find_next_entry(struct cbfs_image *image,
+ struct cbfs_file *entry) {
+ uint32_t addr = cbfs_get_entry_addr(image, entry);
+ int align = ntohl(image->header->align);
+ assert(entry && cbfs_is_valid_entry(entry));
+ addr += ntohl(entry->offset) + ntohl(entry->len);
+ addr = align_up(addr, align);
+ return (struct cbfs_file *)(image->buffer.data + addr);
+}
+
+uint32_t cbfs_get_entry_addr(struct cbfs_image *image, struct cbfs_file *entry) {
+ assert(image && image->buffer.data && entry);
+ return (int32_t)((char *)entry - image->buffer.data);
+}
+
+int cbfs_is_valid_entry(struct cbfs_file *entry) {
+ return (entry &&memcmp(entry->magic, CBFS_FILE_MAGIC,
+ sizeof(entry->magic)) == 0);
+}
+
diff --git a/util/cbfstool/cbfs_image.h b/util/cbfstool/cbfs_image.h
new file mode 100644
index 0000000..9535c2d
--- /dev/null
+++ b/util/cbfstool/cbfs_image.h
@@ -0,0 +1,65 @@
+/*
+ * CBFS Image Manipulation
+ *
+ * Copyright (C) 2013 The Chromium OS Authors. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ */
+
+#ifndef __CBFS_IMAGE_H
+#define __CBFS_IMAGE_H
+#include "common.h"
+#include "cbfs.h"
+
+/* CBFS image processing */
+
+struct cbfs_image {
+ struct buffer buffer;
+ struct cbfs_header *header;
+};
+
+/* Loads a CBFS image from file. Returns 0 on success, otherwise non-zero. */
+int cbfs_image_from_file(struct cbfs_image *image, const char *filename);
+
+/* Writes a CBFS image into file. Returns 0 on success, otherwise non-zero. */
+int cbfs_image_write_file(struct cbfs_image *image, const char *filename);
+
+/* Releases the CBFS image. Returns 0 on success, otherwise non-zero. */
+int cbfs_image_delete(struct cbfs_image *image);
+
+/* Primitive CBFS utilities */
+
+/* Returns a pointer to the only valid CBFS header in give buffer, otherwise
+ * NULL (including when multiple headers were found). If there is a X86 ROM
+ * style signature (pointer at 0xfffffffc) found in ROM, it will be selected as
+ * the only header.*/
+struct cbfs_header *cbfs_find_header(char *data, size_t size);
+
+/* Returns the first cbfs_file entry in CBFS image by CBFS header (no matter if
+ * the entry has valid content or not), otherwise NULL. */
+struct cbfs_file *cbfs_find_first_entry(struct cbfs_image *image);
+
+/* Returns next cbfs_file entry (no matter if its content is valid or not), or
+ * NULL on failure. */
+struct cbfs_file *cbfs_find_next_entry(struct cbfs_image *image,
+ struct cbfs_file *entry);
+
+/* Returns ROM address (offset) of entry.
+ * This is different from entry->offset (pointer to content). */
+uint32_t cbfs_get_entry_addr(struct cbfs_image *image, struct cbfs_file *entry);
+
+/* Returns 1 if entry has valid data (by checking magic number), otherwise 0. */
+int cbfs_is_valid_entry(struct cbfs_file *entry);
+
+#endif