diff options
-rw-r--r-- | util/cbfstool/Makefile | 2 | ||||
-rw-r--r-- | util/cbfstool/Makefile.inc | 1 | ||||
-rw-r--r-- | util/cbfstool/cbfs.h | 2 | ||||
-rw-r--r-- | util/cbfstool/cbfs_image.c | 128 | ||||
-rw-r--r-- | util/cbfstool/cbfs_image.h | 65 |
5 files changed, 197 insertions, 1 deletions
diff --git a/util/cbfstool/Makefile b/util/cbfstool/Makefile index 17b00a77f2..3ace744905 100644 --- a/util/cbfstool/Makefile +++ b/util/cbfstool/Makefile @@ -7,7 +7,7 @@ CFLAGS += -D_7ZIP_ST 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 5795507377..2cee794572 100644 --- a/util/cbfstool/Makefile.inc +++ b/util/cbfstool/Makefile.inc @@ -2,6 +2,7 @@ cbfsobj := 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 3dbeefd38d..4a3ff94f20 100644 --- a/util/cbfstool/cbfs.h +++ b/util/cbfstool/cbfs.h @@ -42,6 +42,8 @@ struct cbfs_header { #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 0000000000..5754453b1c --- /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 0000000000..9535c2d95f --- /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 |