diff options
-rw-r--r-- | src/include/cbfs.h | 123 | ||||
-rw-r--r-- | src/include/cbfs_core.h | 180 | ||||
-rw-r--r-- | src/lib/cbfs.c | 118 | ||||
-rw-r--r-- | src/lib/cbfs_core.c | 174 |
4 files changed, 369 insertions, 226 deletions
diff --git a/src/include/cbfs.h b/src/include/cbfs.h index c1c1e33743..148317702a 100644 --- a/src/include/cbfs.h +++ b/src/include/cbfs.h @@ -49,130 +49,13 @@ #ifndef _CBFS_H_ #define _CBFS_H_ +#include "cbfs_core.h" #include <boot/coreboot_tables.h> -/** These are standard values for the known compression - alogrithms that coreboot knows about for stages and - payloads. Of course, other CBFS users can use whatever - values they want, as long as they understand them. */ -#define CBFS_COMPRESS_NONE 0 -#define CBFS_COMPRESS_LZMA 1 - -/** These are standard component types for well known - components (i.e - those that coreboot needs to consume. - Users are welcome to use any other value for their - components */ - -#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 - - -/** this is the master cbfs header - it need to be - located somewhere in the bootblock. Where it - actually lives is up to coreboot. A pointer to - this header will live at 0xFFFFFFFc, so we can - easily find it. */ - -#define CBFS_HEADER_MAGIC 0x4F524243 -#define CBFS_HEADPTR_ADDR 0xFFFFFFFc -#define VERSION1 0x31313131 - -struct cbfs_header { - u32 magic; - u32 version; - u32 romsize; - u32 bootblocksize; - u32 align; - u32 offset; - u32 pad[2]; -} __attribute__((packed)); - -/** This is a component header - every entry in the CBFS - will have this header. - - This is how the component is arranged in the ROM: - - -------------- <- 0 - component header - -------------- <- sizeof(struct component) - component name - -------------- <- offset - data - ... - -------------- <- offset + len -*/ - -#define CBFS_FILE_MAGIC "LARCHIVE" - -struct cbfs_file { - char magic[8]; - u32 len; - u32 type; - u32 checksum; - u32 offset; -} __attribute__((packed)); - -/*** Component sub-headers ***/ - -/* Following are component sub-headers for the "standard" - component types */ - -/** This is the sub-header for stage components. Stages are - loaded by coreboot during the normal boot process */ - -struct cbfs_stage { - u32 compression; /** Compression type */ - u64 entry; /** entry point */ - u64 load; /** Where to load in memory */ - u32 len; /** length of data to load */ - u32 memlen; /** total length of object in memory */ -} __attribute__((packed)); - -/** this is the sub-header for payload components. Payloads - are loaded by coreboot at the end of the boot process */ - -struct cbfs_payload_segment { - u32 type; - u32 compression; - u32 offset; - u64 load_addr; - u32 len; - u32 mem_len; -} __attribute__((packed)); - -struct cbfs_payload { - struct cbfs_payload_segment segments; -}; - -#define PAYLOAD_SEGMENT_CODE 0x45444F43 -#define PAYLOAD_SEGMENT_DATA 0x41544144 -#define PAYLOAD_SEGMENT_BSS 0x20535342 -#define PAYLOAD_SEGMENT_PARAMS 0x41524150 -#define PAYLOAD_SEGMENT_ENTRY 0x52544E45 - -struct cbfs_optionrom { - u32 compression; - u32 len; -} __attribute__((packed)); - -#define CBFS_NAME(_c) (((char *) (_c)) + sizeof(struct cbfs_file)) -#define CBFS_SUBHEADER(_p) ( (void *) ((((u8 *) (_p)) + ntohl((_p)->offset))) ) - -void * cbfs_load_payload(struct lb_memory *lb_mem, const char *name); -void * cbfs_load_stage(const char *name); +void *cbfs_load_payload(struct lb_memory *lb_mem, const char *name); +void *cbfs_load_stage(const char *name); int cbfs_execute_stage(const char *name); -void * cbfs_get_file(const char *name); void *cbfs_load_optionrom(u16 vendor, u16 device, void * dest); int run_address(void *f); -struct cbfs_file *cbfs_find(const char *name); -void *cbfs_find_file(const char *name, int type); #endif diff --git a/src/include/cbfs_core.h b/src/include/cbfs_core.h new file mode 100644 index 0000000000..fbe0081517 --- /dev/null +++ b/src/include/cbfs_core.h @@ -0,0 +1,180 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Jordan Crouse <jordan@cosmicpenguin.net> + * + * This file is dual-licensed. You can choose between: + * - The GNU GPL, version 2, as published by the Free Software Foundation + * - The revised BSD license (without advertising clause) + * + * --------------------------------------------------------------------------- + * 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 + * --------------------------------------------------------------------------- + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * --------------------------------------------------------------------------- + */ + +#ifndef _CBFS_CORE_H_ +#define _CBFS_CORE_H_ + +/** These are standard values for the known compression + alogrithms that coreboot knows about for stages and + payloads. Of course, other CBFS users can use whatever + values they want, as long as they understand them. */ + +#define CBFS_COMPRESS_NONE 0 +#define CBFS_COMPRESS_LZMA 1 + +/** These are standard component types for well known + components (i.e - those that coreboot needs to consume. + Users are welcome to use any other value for their + components */ + +#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 + + +/** this is the master cbfs header - it need to be + located somewhere in the bootblock. Where it + actually lives is up to coreboot. A pointer to + this header will live at 0xFFFFFFFc, so we can + easily find it. */ + +#define CBFS_HEADER_MAGIC 0x4F524243 +#define CBFS_HEADPTR_ADDR 0xFFFFFFFc +#define VERSION1 0x31313131 + +struct cbfs_header { + uint32_t magic; + uint32_t version; + uint32_t romsize; + uint32_t bootblocksize; + uint32_t align; + uint32_t offset; + uint32_t pad[2]; +} __attribute__((packed)); + +/** This is a component header - every entry in the CBFS + will have this header. + + This is how the component is arranged in the ROM: + + -------------- <- 0 + component header + -------------- <- sizeof(struct component) + component name + -------------- <- offset + data + ... + -------------- <- offset + len +*/ + +#define CBFS_FILE_MAGIC "LARCHIVE" + +struct cbfs_file { + char magic[8]; + uint32_t len; + uint32_t type; + uint32_t checksum; + uint32_t offset; +} __attribute__((packed)); + +/*** Component sub-headers ***/ + +/* Following are component sub-headers for the "standard" + component types */ + +/** This is the sub-header for stage components. Stages are + loaded by coreboot during the normal boot process */ + +struct cbfs_stage { + uint32_t compression; /** Compression type */ + uint64_t entry; /** entry point */ + uint64_t load; /** Where to load in memory */ + uint32_t len; /** length of data to load */ + uint32_t memlen; /** total length of object in memory */ +} __attribute__((packed)); + +/** this is the sub-header for payload components. Payloads + are loaded by coreboot at the end of the boot process */ + +struct cbfs_payload_segment { + uint32_t type; + uint32_t compression; + uint32_t offset; + uint64_t load_addr; + uint32_t len; + uint32_t mem_len; +} __attribute__((packed)); + +struct cbfs_payload { + struct cbfs_payload_segment segments; +}; + +#define PAYLOAD_SEGMENT_CODE 0x45444F43 +#define PAYLOAD_SEGMENT_DATA 0x41544144 +#define PAYLOAD_SEGMENT_BSS 0x20535342 +#define PAYLOAD_SEGMENT_PARAMS 0x41524150 +#define PAYLOAD_SEGMENT_ENTRY 0x52544E45 + +struct cbfs_optionrom { + uint32_t compression; + uint32_t len; +} __attribute__((packed)); + +#define CBFS_NAME(_c) (((char *) (_c)) + sizeof(struct cbfs_file)) +#define CBFS_SUBHEADER(_p) ( (void *) ((((uint8_t *) (_p)) + ntohl((_p)->offset))) ) + +/* returns pointer to file inside CBFS or NULL */ +struct cbfs_file *cbfs_find(const char *name); + +/* returns pointer to file data inside CBFS */ +void *cbfs_get_file(const char *name); + +/* returns pointer to file data inside CBFS after if type is correct */ +void *cbfs_find_file(const char *name, int type); + +/* returns 0 on success, -1 on failure */ +int cbfs_decompress(int algo, void *src, void *dst, int len); +#endif + diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c index 7cfa3e2a40..20c9d4957a 100644 --- a/src/lib/cbfs.c +++ b/src/lib/cbfs.c @@ -24,85 +24,19 @@ #include <lib.h> #include <arch/byteorder.h> +// use CBFS core +#ifndef __SMM__ +#define CBFS_CORE_WITH_LZMA +#endif +#define phys_to_virt(x) (void*)(x) +#define virt_to_phys(x) (uint32_t)(x) +#define ERROR(x...) printk(BIOS_ERR, x) +#define LOG(x...) printk(BIOS_INFO, x) +// FIXME: romstart/romend are fine on x86, but not on ARM +#define romstart() 0xffffffff +#define romend() 0 -static int cbfs_check_magic(struct cbfs_file *file) -{ - return !strcmp(file->magic, CBFS_FILE_MAGIC) ? 1 : 0; -} - -static struct cbfs_header *cbfs_master_header(void) -{ - struct cbfs_header *header; - - void *ptr = (void *)*((unsigned long *) CBFS_HEADPTR_ADDR); - printk(BIOS_SPEW, "Check CBFS header at %p\n", ptr); - header = (struct cbfs_header *) ptr; - - printk(BIOS_SPEW, "magic is %08x\n", ntohl(header->magic)); - if (ntohl(header->magic) != CBFS_HEADER_MAGIC) { - printk(BIOS_ERR, "ERROR: No valid CBFS header found!\n"); - if (header->magic == 0xffffffff) { - printk(BIOS_ERR, "Maybe the ROM isn't entirely mapped yet?\n" - "See (and report to) http://www.coreboot.org/Infrastructure_Projects#CBFS\n"); - } - return NULL; - } - - printk(BIOS_SPEW, "Found CBFS header at %p\n", ptr); - return header; -} - -struct cbfs_file *cbfs_find(const char *name) -{ - struct cbfs_header *header = cbfs_master_header(); - unsigned long offset; - - if (header == NULL) - return NULL; - offset = 0 - ntohl(header->romsize) + ntohl(header->offset); - - int align= ntohl(header->align); - - while(1) { - struct cbfs_file *file = (struct cbfs_file *) offset; - if (!cbfs_check_magic(file)) return NULL; - printk(BIOS_SPEW, "Check %s\n", CBFS_NAME(file)); - if (!strcmp(CBFS_NAME(file), name)) - return file; - - int flen = ntohl(file->len); - int foffset = ntohl(file->offset); - printk(BIOS_SPEW, "CBFS: follow chain: %p + %x + %x + align -> ", (void *)offset, foffset, flen); - - unsigned long oldoffset = offset; - offset = ALIGN(offset + foffset + flen, align); - printk(BIOS_SPEW, "%p\n", (void *)offset); - if (offset <= oldoffset) return NULL; - - if (offset < 0xFFFFFFFF - ntohl(header->romsize)) - return NULL; - } -} - -void *cbfs_find_file(const char *name, int type) -{ - struct cbfs_file *file = cbfs_find(name); - - if (file == NULL) { - printk(BIOS_INFO, "CBFS: Could not find file %s\n", - name); - return NULL; - } - - if (ntohl(file->type) != type) { - printk(BIOS_INFO, "CBFS: File %s is of type %x instead of" - "type %x\n", name, file->type, type); - - return NULL; - } - - return (void *) CBFS_SUBHEADER(file); -} +#include "cbfs_core.c" #ifndef __SMM__ static inline int tohex4(unsigned int c) @@ -118,34 +52,6 @@ static void tohex16(unsigned int val, char* dest) dest[3]=tohex4(val & 0xf); } -/** - * Decompression wrapper for CBFS - * @param algo - * @param src - * @param dst - * @param len - * @return 0 on success, -1 on failure - */ -static int cbfs_decompress(int algo, void *src, void *dst, int len) -{ - switch(algo) { - case CBFS_COMPRESS_NONE: - memcpy(dst, src, len); - return 0; - - case CBFS_COMPRESS_LZMA: - if (!ulzma(src, dst)) { - printk(BIOS_ERR, "CBFS: LZMA decompression failed!\n"); - return -1; - } - return 0; - default: - printk(BIOS_INFO, "CBFS: Unknown compression type %d\n", algo); - return -1; - } -} - - void *cbfs_load_optionrom(u16 vendor, u16 device, void * dest) { char name[17]="pciXXXX,XXXX.rom"; diff --git a/src/lib/cbfs_core.c b/src/lib/cbfs_core.c new file mode 100644 index 0000000000..52ba58ded7 --- /dev/null +++ b/src/lib/cbfs_core.c @@ -0,0 +1,174 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2011 secunet Security Networks AG + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* The CBFS core requires a couple of #defines or functions to adapt it to the target environment: + * + * CBFS_CORE_WITH_LZMA (must be #define) + * if defined, ulzma() must exist for decompression of data streams + * + * phys_to_virt(x), virt_to_phys(x) + * translate physical addresses to virtual and vice versa + * can be idempotent if no mapping is necessary. + * + * ERROR(x...) + * print an error message x (in printf format) + * + * LOG(x...) + * print a debug message x (in printf format) + * + * romstart() + * returns the start address of the ROM image, or 0xffffffff if ROM is + * top-aligned. This is a physical address. + * + * romend() + * returns the highest address of the ROM image + 1, for use if + * romstart() == 0xffffffff. This is a physical address. + */ + +#include <cbfs_core.h> + + +/* returns pointer to master header or 0xffffffff if not found */ +static struct cbfs_header *get_cbfs_header(void) +{ + struct cbfs_header *header; + + /* find header */ + if (romstart() == 0xffffffff) { + header = (struct cbfs_header*)phys_to_virt(*(uint32_t*)phys_to_virt(romend() + CBFS_HEADPTR_ADDR)); + } else { + // FIXME: where's the master header on ARM (our current bottom-aligned platform)? + header = NULL; + } + if (CBFS_HEADER_MAGIC != ntohl(header->magic)) { + ERROR("Could not find valid CBFS master header at %p: %x vs %x.\n", header, CBFS_HEADER_MAGIC, ntohl(header->magic)); + if (header->magic == 0xffffffff) { + ERROR("Maybe ROM is not mapped properly?\n"); + } + return (void*)0xffffffff; + } + return header; +} + +// by must be power-of-two +#define CBFS_ALIGN(val, by) (typeof(val))((uint32_t)(val + by - 1) & (uint32_t)~(by - 1)) +#define CBFS_ALIGN_UP(val, by) CBFS_ALIGN(val + 1, by) + +/* public API starts here*/ +struct cbfs_file *cbfs_find(const char *name) +{ + struct cbfs_header *header = get_cbfs_header(); + if (header == (void*)0xffffffff) return NULL; + + LOG("Searching for %s\n", name); + + void *data, *dataend, *origdata; + /* find first entry */ + if (romstart() == 0xffffffff) { + data = (void*)phys_to_virt(romend()) - ntohl(header->romsize) + ntohl(header->offset); + dataend = (void*)phys_to_virt(romend()); + } else { + data = (void*)phys_to_virt(romstart()) + ntohl(header->offset); + dataend = (void*)phys_to_virt(romstart()) + ntohl(header->romsize); + } + + int align = ntohl(header->align); + + origdata = data; + while ((data < (dataend - 1)) && (data >= origdata)) { + struct cbfs_file *file = data; + if (memcmp(CBFS_FILE_MAGIC, file->magic, strlen(CBFS_FILE_MAGIC)) != 0) { + // no file header found. corruption? + // proceed in aligned steps to resynchronize + LOG("No file header found at %p, searching for header\n", data); + data = phys_to_virt(CBFS_ALIGN_UP(virt_to_phys(data), align)); + continue; + } + LOG("Check %s\n", CBFS_NAME(file)); + if (strcmp(CBFS_NAME(file), name) == 0) { + return file; + } + void *olddata = data; + data = phys_to_virt(CBFS_ALIGN(virt_to_phys(data) + ntohl(file->len) + ntohl(file->offset), align)); + if (olddata > data) { + LOG("Something is wrong here. File chain moved from %p to %p\n", olddata, data); + return NULL; + } + } + return NULL; +} + +void *cbfs_get_file(const char *name) +{ + struct cbfs_file *file = cbfs_find(name); + + if (file == NULL) { + ERROR("Could not find file '%s'.\n", name); + return NULL; + } + + return (void*)CBFS_SUBHEADER(file); +} + +void *cbfs_find_file(const char *name, int type) +{ + struct cbfs_file *file = cbfs_find(name); + + if (file == NULL) { + ERROR("Could not find file '%s'.\n", name); + return NULL; + } + + if (ntohl(file->type) != type) { + ERROR("File '%s' is of type %x, but we requested %x.\n", name, ntohl(file->type), type); + return NULL; + } + + return (void*)CBFS_SUBHEADER(file); +} + +int cbfs_decompress(int algo, void *src, void *dst, int len) +{ + switch (algo) { + case CBFS_COMPRESS_NONE: + memcpy(dst, src, len); + return 0; +#ifdef CBFS_CORE_WITH_LZMA + case CBFS_COMPRESS_LZMA: + if (ulzma(src, dst) != 0) { + return 0; + } + return -1; +#endif + default: + ERROR("tried to decompress %d bytes with algorithm #%x, but that algorithm id is unsupported.\n", len, algo); + return -1; + } +} + |