diff options
author | Gabe Black <gabeblack@chromium.org> | 2011-07-15 02:18:54 -0700 |
---|---|---|
committer | Simon Glass <sjg@chromium.org> | 2011-08-29 10:58:59 -0700 |
commit | 5f2b6463e5a9d75fc8893986f1d12fb3bd15ea11 (patch) | |
tree | 7ffdc231c305c65d946306c548ec933059f9f50d /fs | |
parent | c4675722c32de5bf58bf2e77bf4ba91ccc8b3788 (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/Makefile | 1 | ||||
-rw-r--r-- | fs/cbfs/Makefile | 44 | ||||
-rw-r--r-- | fs/cbfs/cbfs.c | 296 |
3 files changed, 341 insertions, 0 deletions
diff --git a/fs/Makefile b/fs/Makefile index 22aad126bc2..ca2146407fa 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 00000000000..864fdf9f87a --- /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 00000000000..d1b03c7e1a0 --- /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; +} |