summaryrefslogtreecommitdiff
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
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>
-rw-r--r--Makefile6
-rw-r--r--README1
-rw-r--r--common/Makefile1
-rw-r--r--common/cmd_cbfs.c118
-rw-r--r--fs/Makefile1
-rw-r--r--fs/cbfs/Makefile44
-rw-r--r--fs/cbfs/cbfs.c296
-rw-r--r--include/cbfs.h61
8 files changed, 525 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index 74c48d1d16..6cb7ce85a6 100644
--- a/Makefile
+++ b/Makefile
@@ -234,9 +234,9 @@ ifeq ($(CONFIG_OF_EMBED),y)
LIBS += dts/libdts.o
endif
LIBS += arch/$(ARCH)/lib/lib$(ARCH).o
-LIBS += fs/cramfs/libcramfs.o fs/fat/libfat.o fs/fdos/libfdos.o fs/jffs2/libjffs2.o \
- fs/reiserfs/libreiserfs.o fs/ext2/libext2fs.o fs/yaffs2/libyaffs2.o \
- fs/ubifs/libubifs.o
+LIBS += fs/cramfs/libcramfs.o fs/fat/libfat.o fs/fdos/libfdos.o \
+ fs/jffs2/libjffs2.o fs/reiserfs/libreiserfs.o fs/ext2/libext2fs.o \
+ fs/yaffs2/libyaffs2.o fs/ubifs/libubifs.o fs/cbfs/libcbfs.o
LIBS += net/libnet.o
LIBS += disk/libdisk.o
LIBS += drivers/bios_emulator/libatibiosemu.o
diff --git a/README b/README
index 3468db04cb..9cef0b2604 100644
--- a/README
+++ b/README
@@ -653,6 +653,7 @@ The following options need to be configured:
CONFIG_CMD_BSP * Board specific commands
CONFIG_CMD_BOOTD bootd
CONFIG_CMD_CACHE * icache, dcache
+ CONFIG_CMD_CBFS * Support for coreboot's CBFS
CONFIG_CMD_CONSOLE coninfo
CONFIG_CMD_CRC32 * crc32
CONFIG_CMD_DATE * support for RTC, date/time...
diff --git a/common/Makefile b/common/Makefile
index 02bea72adf..5beec0067e 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -95,6 +95,7 @@ COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += cmd_eeprom.o
COBJS-$(CONFIG_CMD_EEPROM) += cmd_eeprom.o
COBJS-$(CONFIG_CMD_ELF) += cmd_elf.o
COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_exit.o
+COBJS-$(CONFIG_CMD_CBFS) += cmd_cbfs.o
COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o
COBJS-$(CONFIG_CMD_FAT) += cmd_fat.o
COBJS-$(CONFIG_CMD_FDC)$(CONFIG_CMD_FDOS) += cmd_fdc.o
diff --git a/common/cmd_cbfs.c b/common/cmd_cbfs.c
new file mode 100644
index 0000000000..8fce99e155
--- /dev/null
+++ b/common/cmd_cbfs.c
@@ -0,0 +1,118 @@
+/*
+ * 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
+ */
+
+/*
+ * CBFS commands
+ */
+#include <common.h>
+#include <command.h>
+#include <cbfs.h>
+
+int do_cbfs_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+ uintptr_t end_of_rom = 0xffffffff;
+ char *ep;
+
+ if (argc > 2) {
+ printf("usage: cbfsls [end of rom]>\n");
+ return 0;
+ }
+ if (argc == 2) {
+ end_of_rom = (int)simple_strtoul(argv[1], &ep, 16);
+ if (*ep) {
+ puts("\n** Invalid end of ROM **\n");
+ return 1;
+ }
+ }
+ return file_cbfs_init(end_of_rom);
+}
+
+U_BOOT_CMD(
+ cbfsinit, 2, 0, do_cbfs_init,
+ "initialize the cbfs driver",
+ "[end of rom]\n"
+ " - Initialize the cbfs driver. The optional 'end of rom'\n"
+ " parameter specifies where the end of the ROM is that the\n"
+ " CBFS is in. It defaults to 0xFFFFFFFF\n"
+);
+
+int do_cbfs_fsload (cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+ long size;
+ unsigned long offset;
+ unsigned long count;
+ char buf[12];
+
+ if (argc < 3) {
+ printf("usage: cbfsload <addr> <filename> [bytes]\n");
+ return 1;
+ }
+
+ /* parse offset and count */
+ offset = simple_strtoul(argv[1], NULL, 16);
+ if (argc == 4)
+ count = simple_strtoul(argv[3], NULL, 16);
+ else
+ count = 0;
+
+ size = file_cbfs_read(argv[2], (void *)offset, count);
+ if (size < 0) {
+ printf("\n** Unable to read \"%s\" from cbfs **\n", argv[2]);
+ return 1;
+ }
+
+ printf("\n%ld bytes read\n", size);
+
+ sprintf(buf, "%lX", size);
+ setenv("filesize", buf);
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ cbfsload, 4, 0, do_cbfs_fsload,
+ "load binary file from a cbfs filesystem",
+ "<addr> <filename> [bytes]\n"
+ " - load binary file 'filename' from the cbfs to address 'addr'\n"
+);
+
+int do_cbfs_ls (cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+ return file_cbfs_ls();
+}
+
+U_BOOT_CMD(
+ cbfsls, 1, 1, do_cbfs_ls,
+ "list files",
+ " - list the files in the cbfs\n"
+);
+
+int do_cbfs_fsinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+ return file_cbfs_fsinfo();
+}
+
+U_BOOT_CMD(
+ cbfsinfo, 1, 1, do_cbfs_fsinfo,
+ "print information about filesystem",
+ " - print information about the cbfs filesystem\n"
+);
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;
+}
diff --git a/include/cbfs.h b/include/cbfs.h
new file mode 100644
index 0000000000..7a4d0c6550
--- /dev/null
+++ b/include/cbfs.h
@@ -0,0 +1,61 @@
+/*
+ * 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
+ */
+
+#ifndef __CBFS_H
+#define __CBFS_H
+
+/*
+ * Initialize the CBFS driver and load metadata into RAM.
+ *
+ * @param end_of_rom Points to the end of the ROM the CBFS should be read
+ * from.
+ *
+ * @return Zero on success, non-zero on failure
+ */
+int file_cbfs_init(uintptr_t end_of_rom);
+
+/*
+ * Read a file from CBFS into RAM
+ *
+ * @param filename The name of the file to read.
+ * @param buffer Where to read it into memory.
+ *
+ * @return If positive or zero, the number of characters read. If negative, an
+ * error occurred.
+ */
+long file_cbfs_read(const char *filename, void *buffer, unsigned long maxsize);
+
+/*
+ * List the files names, types, and sizes in the current CBFS.
+ *
+ * @return Zero on success, non-zero on failure.
+ */
+int file_cbfs_ls(void);
+
+/*
+ * Print information from the CBFS header.
+ *
+ * @return Zero on success, non-zero on failure.
+ */
+int file_cbfs_fsinfo(void);
+
+#endif /* __CBFS_H */