summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorGabe Black <gabeblack@chromium.org>2011-07-15 02:18:54 -0700
committerSimon Glass <sjg@chromium.org>2011-08-29 10:58:59 -0700
commit5f2b6463e5a9d75fc8893986f1d12fb3bd15ea11 (patch)
tree7ffdc231c305c65d946306c548ec933059f9f50d /fs
parentc4675722c32de5bf58bf2e77bf4ba91ccc8b3788 (diff)
Add a CBFS driver and commands to u-boot.
This change adds CBFS support and some commands to use it to u-boot. These commands are: cbfsinit - Initialize CBFS support and pull all metadata into RAM. The end of the ROM is an optional parameter which defaults to the standard 0xffffffff and can be used to support multiple CBFSes in a system. The last one set up with cbfsinit is the one that will be used. cbfsinfo - Print information from the CBFS header. cbfsls - Print out the size, type, and name of all the files in the current CBFS. Recognized types are translated into symbolic names. cbfsload - Load a file from CBFS into memory. Like the similar command for fat filesystems, you can optionally provide a maximum size. Support for CBFS is compiled in when the CONFIG_CMD_CBFS option is specified. BUG=chrome-os-partner:3910 TEST=Built and booted on an Alex. Initialized with and without specifying the end of the ROM, and with a bad end of ROM. Ran the commands before CBFS was initialized. Ran cbfsinfo and saw reasonable output. Ran cbfsls and saw output that matched what was printed when the CBFS was put together by the coreboot ebuild. Used cbfsload to load a test text file into memory and verified that it was the correct size and had the correct contents. Ran with a max size and saw the file was truncated in memory. Change-Id: I64d06d49633cef3cffac1d571519eae38c7d267f Signed-off-by: Gabe Black <gabeblack@google.com> Reviewed-on: http://gerrit.chromium.org/gerrit/4167 Reviewed-by: Gabe Black <gabeblack@chromium.org> Tested-by: Gabe Black <gabeblack@chromium.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/Makefile1
-rw-r--r--fs/cbfs/Makefile44
-rw-r--r--fs/cbfs/cbfs.c296
3 files changed, 341 insertions, 0 deletions
diff --git a/fs/Makefile b/fs/Makefile
index 22aad126bc..ca2146407f 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -23,6 +23,7 @@
#
subdirs-$(CONFIG_CMD_CRAMFS) := cramfs
+subdirs-$(CONFIG_CMD_CBFS) += cbfs
subdirs-$(CONFIG_CMD_EXT2) += ext2
subdirs-$(CONFIG_CMD_FAT) += fat
subdirs-$(CONFIG_CMD_FDOS) += fdos
diff --git a/fs/cbfs/Makefile b/fs/cbfs/Makefile
new file mode 100644
index 0000000000..864fdf9f87
--- /dev/null
+++ b/fs/cbfs/Makefile
@@ -0,0 +1,44 @@
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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; either version 2 of
+# the License, or (at your option) any later version.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)libcbfs.o
+
+AOBJS =
+COBJS-$(CONFIG_CMD_CBFS) := cbfs.o
+
+SRCS := $(AOBJS:.o=.S) $(COBJS-y:.o=.c)
+OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS-y))
+
+all: $(LIB) $(AOBJS)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/fs/cbfs/cbfs.c b/fs/cbfs/cbfs.c
new file mode 100644
index 0000000000..d1b03c7e1a
--- /dev/null
+++ b/fs/cbfs/cbfs.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+#include <cbfs.h>
+#include <malloc.h>
+#include <asm/byteorder.h>
+
+#define CBFS_TYPE_STAGE 0x10
+#define CBFS_TYPE_PAYLOAD 0x20
+#define CBFS_TYPE_OPTIONROM 0x30
+#define CBFS_TYPE_BOOTSPLASH 0x40
+#define CBFS_TYPE_RAW 0x50
+#define CBFS_TYPE_VSA 0x51
+#define CBFS_TYPE_MBI 0x52
+#define CBFS_TYPE_MICROCODE 0x53
+#define CBFS_COMPONENT_CMOS_DEFAULT 0xaa
+#define CBFS_COMPONENT_CMOS_LAYOUT 0x01aa
+
+typedef struct CbfsHeader {
+ u32 magic;
+ u32 version;
+ u32 romSize;
+ u32 bootBlockSize;
+ u32 align;
+ u32 offset;
+ u32 pad[2];
+} __attribute__((packed)) CbfsHeader;
+
+typedef struct CbfsFileHeader {
+ u8 magic[8];
+ u32 len;
+ u32 type;
+ u32 checksum;
+ u32 offset;
+} __attribute__((packed)) CbfsFileHeader;
+
+typedef struct CbfsCacheNode {
+ CbfsFileHeader header;
+ struct CbfsCacheNode *next;
+ void *data;
+ char *name;
+} __attribute__((packed)) CbfsCacheNode;
+
+
+static const u32 goodMagic = 0x4f524243;
+static const u8 goodFileMagic[] = "LARCHIVE";
+
+
+static int initialized;
+static struct CbfsHeader header;
+static CbfsCacheNode *fileCache;
+
+static void swap_header(CbfsHeader *dest, CbfsHeader *src)
+{
+ dest->magic = be32_to_cpu(src->magic);
+ dest->version = be32_to_cpu(src->version);
+ dest->romSize = be32_to_cpu(src->romSize);
+ dest->bootBlockSize = be32_to_cpu(src->bootBlockSize);
+ dest->align = be32_to_cpu(src->align);
+ dest->offset = be32_to_cpu(src->offset);
+}
+
+static void swap_file_header(CbfsFileHeader *dest, CbfsFileHeader *src)
+{
+ memcpy(&dest->magic, &src->magic, sizeof(dest->magic));
+ dest->len = be32_to_cpu(src->len);
+ dest->type = be32_to_cpu(src->type);
+ dest->checksum = be32_to_cpu(src->checksum);
+ dest->offset = be32_to_cpu(src->offset);
+}
+
+static int init_check(void)
+{
+ if (!initialized) {
+ printf("CBFS not initialized.\n");
+ return 1;
+ }
+ return 0;
+}
+
+static int file_cbfs_fill_cache(u8 *start, u32 size, u32 align)
+{
+ CbfsCacheNode *cacheNode;
+ CbfsCacheNode *newNode;
+ CbfsCacheNode **cacheTail = &fileCache;
+
+ /* Clear out old information. */
+ cacheNode = fileCache;
+ while (cacheNode) {
+ CbfsCacheNode *oldNode = cacheNode;
+ cacheNode = cacheNode->next;
+ free(oldNode->name);
+ free(oldNode);
+ }
+ fileCache = NULL;
+
+ while (size >= align) {
+ CbfsFileHeader *fileHeader = (CbfsFileHeader *)start;
+ u32 nameLen;
+ u32 step;
+
+ /* Check if there's a file here. */
+ if (memcmp(goodFileMagic, &(fileHeader->magic),
+ sizeof(fileHeader->magic))) {
+ size -= align;
+ start += align;
+ continue;
+ }
+
+ newNode = (CbfsCacheNode *)malloc(sizeof(CbfsCacheNode));
+ swap_file_header(&newNode->header, fileHeader);
+ if (newNode->header.offset < sizeof(CbfsFileHeader) ||
+ newNode->header.offset > newNode->header.len) {
+ printf("Bad file in CBFS.\n");
+ return 1;
+ }
+ newNode->next = NULL;
+ newNode->data = start + newNode->header.offset;
+ nameLen = newNode->header.offset - sizeof(CbfsFileHeader);
+ /* Add a byte for a NULL terminator. */
+ newNode->name = (char *)malloc(nameLen + 1);
+ strncpy(newNode->name,
+ ((char *)fileHeader) + sizeof(CbfsFileHeader),
+ nameLen);
+ newNode->name[nameLen] = 0;
+ *cacheTail = newNode;
+ cacheTail = &newNode->next;
+
+ step = newNode->header.len;
+ if (step % align)
+ step = step + align - step % align;
+
+ size -= step;
+ start += step;
+ }
+ return 0;
+}
+
+int file_cbfs_init(uintptr_t endOfRom)
+{
+ CbfsHeader *headerInRom;
+ u8 *startOfRom;
+ initialized = 0;
+
+ headerInRom = (CbfsHeader *)(uintptr_t)*(u32 *)(endOfRom - 3);
+ swap_header(&header, headerInRom);
+
+ if (header.magic != goodMagic || header.offset >
+ header.romSize - header.bootBlockSize) {
+ printf("Bad CBFS header.\n");
+ return 1;
+ }
+
+ startOfRom = (u8 *)(endOfRom + 1 - header.romSize);
+
+ if (file_cbfs_fill_cache(startOfRom + header.offset,
+ header.romSize, header.align)) {
+ return 1;
+ }
+
+ initialized = 1;
+ return 0;
+}
+
+long file_cbfs_read(const char *filename, void *buffer, unsigned long maxsize)
+{
+ struct CbfsCacheNode *cacheNode = fileCache;
+ u32 size;
+
+ if (init_check())
+ return 1;
+
+ while (cacheNode) {
+ if (!strcmp(filename, cacheNode->name))
+ break;
+ cacheNode = cacheNode->next;
+ }
+ if (!cacheNode) {
+ printf("File %s not found.\n", filename);
+ return -1;
+ }
+
+ printf("reading %s\n", filename);
+
+ size = cacheNode->header.len;
+ if (maxsize && size > maxsize)
+ size = maxsize;
+
+ memcpy(buffer, cacheNode->data, size);
+
+ return size;
+}
+
+int file_cbfs_ls(void)
+{
+ struct CbfsCacheNode *cacheNode = fileCache;
+ int files = 0;
+
+ if (init_check())
+ return 1;
+
+ printf(" size type name\n");
+ printf("------------------------------------------\n");
+ while (cacheNode) {
+ char *typeName = NULL;
+ printf(" %8d", cacheNode->header.len);
+
+ switch (cacheNode->header.type) {
+ case CBFS_TYPE_STAGE:
+ typeName = "stage";
+ break;
+ case CBFS_TYPE_PAYLOAD:
+ typeName = "payload";
+ break;
+ case CBFS_TYPE_OPTIONROM:
+ typeName = "option rom";
+ break;
+ case CBFS_TYPE_BOOTSPLASH:
+ typeName = "boot splash";
+ break;
+ case CBFS_TYPE_RAW:
+ typeName = "raw";
+ break;
+ case CBFS_TYPE_VSA:
+ typeName = "vsa";
+ break;
+ case CBFS_TYPE_MBI:
+ typeName = "mbi";
+ break;
+ case CBFS_TYPE_MICROCODE:
+ typeName = "microcode";
+ break;
+ case CBFS_COMPONENT_CMOS_DEFAULT:
+ typeName = "cmos default";
+ break;
+ case CBFS_COMPONENT_CMOS_LAYOUT:
+ typeName = "cmos layout";
+ break;
+ case -1UL:
+ typeName = "null";
+ break;
+ }
+ if (typeName)
+ printf(" %16s", typeName);
+ else
+ printf(" %16d", cacheNode->header.type);
+
+ if (cacheNode->name[0])
+ printf(" %s\n", cacheNode->name);
+ else
+ printf(" %s\n", "(empty)");
+ cacheNode = cacheNode->next;
+ files++;
+ }
+
+ printf("\n%d file(s)\n\n", files);
+ return 0;
+}
+
+int file_cbfs_fsinfo(void)
+{
+ if (init_check())
+ return 1;
+
+ printf("\n");
+ printf("CBFS version: %#x\n", header.version);
+ printf("ROM size: %#x\n", header.romSize);
+ printf("Boot block size: %#x\n", header.bootBlockSize);
+ printf("CBFS size: %#x\n",
+ header.romSize - header.bootBlockSize - header.offset);
+ printf("Alignment: %d\n", header.align);
+ printf("Offset: %#x\n", header.offset);
+ printf("\n");
+ return 0;
+}