diff options
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | README | 1 | ||||
-rw-r--r-- | common/Makefile | 1 | ||||
-rw-r--r-- | common/cmd_cbfs.c | 118 | ||||
-rw-r--r-- | fs/Makefile | 1 | ||||
-rw-r--r-- | fs/cbfs/Makefile | 44 | ||||
-rw-r--r-- | fs/cbfs/cbfs.c | 296 | ||||
-rw-r--r-- | include/cbfs.h | 61 |
8 files changed, 525 insertions, 3 deletions
@@ -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 @@ -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 02bea72adfe..5beec0067e0 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 00000000000..8fce99e1550 --- /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 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; +} diff --git a/include/cbfs.h b/include/cbfs.h new file mode 100644 index 00000000000..7a4d0c65500 --- /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 */ |