diff --git a/payloads/libpayload/Config.in b/payloads/libpayload/Config.in index 028dd332f9..0ce4ae539f 100644 --- a/payloads/libpayload/Config.in +++ b/payloads/libpayload/Config.in @@ -129,7 +129,14 @@ config CBFS bool "CBFS support" default y help - CBFS is the archive format of (obsolete) coreboot v3 + CBFS is the archive format of coreboot + +config LZMA + bool "LZMA decoder" + default y + help + LZMA decoder implementation, usable eg. by CBFS, + but also externally. endmenu menu "Console Options" diff --git a/payloads/libpayload/Makefile.inc b/payloads/libpayload/Makefile.inc index 5a7d142b1b..9e40d0f5f2 100644 --- a/payloads/libpayload/Makefile.inc +++ b/payloads/libpayload/Makefile.inc @@ -41,6 +41,8 @@ classes-$(CONFIG_PCI) += libpci classes-$(CONFIG_LIBC) += libc classes-$(CONFIG_CURSES) += libcurses classes-$(CONFIG_PDCURSES) += libmenu libform libpanel +classes-$(CONFIG_CBFS) += libcbfs +classes-$(CONFIG_LZMA) += liblzma libraries := $(classes-y) classes-y += head.o @@ -52,6 +54,8 @@ head.o-S-deps = $(obj)/libpayload-config.h subdirs-y := arch/$(ARCHDIR-y) subdirs-y += crypto libc drivers libpci subdirs-$(CONFIG_CURSES) += curses +subdirs-$(CONFIG_CBFS) += libcbfs +subdirs-$(CONFIG_LZMA) += liblzma INCLUDES := -Iinclude -Iinclude/$(ARCHDIR-y) -I$(obj) CFLAGS = $(INCLUDES) -O2 -pipe -g diff --git a/payloads/libpayload/configs/defconfig b/payloads/libpayload/configs/defconfig index 6d514d6b0f..8d50f56208 100644 --- a/payloads/libpayload/configs/defconfig +++ b/payloads/libpayload/configs/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # libpayload version: 0.2.0 -# Tue Jul 12 15:54:09 2011 +# Thu Jul 21 15:45:38 2011 # # @@ -23,8 +23,11 @@ CONFIG_TARGET_I386=y # Standard Libraries # CONFIG_LIBC=y +CONFIG_CURSES=y +# CONFIG_TINYCURSES is not set CONFIG_PDCURSES=y -# CONFIG_CBFS is not set +CONFIG_CBFS=y +CONFIG_LZMA=y # # Console Options diff --git a/payloads/libpayload/include/cbfs.h b/payloads/libpayload/include/cbfs.h new file mode 100644 index 0000000000..681caeb493 --- /dev/null +++ b/payloads/libpayload/include/cbfs.h @@ -0,0 +1,2 @@ +#include +#include "cbfs_core.h" diff --git a/payloads/libpayload/include/cbfs_core.h b/payloads/libpayload/include/cbfs_core.h new file mode 100644 index 0000000000..fbe0081517 --- /dev/null +++ b/payloads/libpayload/include/cbfs_core.h @@ -0,0 +1,180 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Jordan Crouse + * + * 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/payloads/libpayload/include/lzma.h b/payloads/libpayload/include/lzma.h new file mode 100644 index 0000000000..35f4c02c46 --- /dev/null +++ b/payloads/libpayload/include/lzma.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#ifndef _LZMA_H +#define _LZMA_H + +/* decompresses the data stream at src to dst, determining its length from + * the data stream itself. + * + * returns the decompressed size, or 0 on error + */ +unsigned long ulzma(unsigned char *src, unsigned char *dst); + +#endif diff --git a/payloads/libpayload/libc/Makefile.inc b/payloads/libpayload/libc/Makefile.inc index 0dab8c1abe..eef4f46a7e 100644 --- a/payloads/libpayload/libc/Makefile.inc +++ b/payloads/libpayload/libc/Makefile.inc @@ -38,4 +38,3 @@ libc-$(CONFIG_LIBC) += qsort.c # should be moved to coreboot directory libc-$(CONFIG_LAR) += lar.c -#libc-$(CONFIG_CBFS) += cbfs.c diff --git a/payloads/libpayload/libcbfs/Makefile.inc b/payloads/libpayload/libcbfs/Makefile.inc new file mode 100644 index 0000000000..50f4821732 --- /dev/null +++ b/payloads/libpayload/libcbfs/Makefile.inc @@ -0,0 +1,31 @@ +## +## 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. +## + +libcbfs-$(CONFIG_CBFS) += cbfs.c + diff --git a/payloads/libpayload/libcbfs/cbfs.c b/payloads/libpayload/libcbfs/cbfs.c new file mode 100644 index 0000000000..c7173e0cb3 --- /dev/null +++ b/payloads/libpayload/libcbfs/cbfs.c @@ -0,0 +1,78 @@ +/* + * 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. + */ + +#include +#include +#include +#include + +#ifdef CONFIG_LZMA +#define CBFS_CORE_WITH_LZMA +#include +#endif + +#define ERROR(x...) printf(x) +#define LOG(x...) + +uint32_t host_virt_to_phys(void *addr); +void *host_phys_to_virt(uint32_t addr); + +uint32_t romstart(void); +uint32_t romend(void); + +#include +uint32_t host_virt_to_phys(void *addr) { + return virt_to_phys(addr); +} + +void *host_phys_to_virt(uint32_t addr) { + return phys_to_virt(addr); +} +#undef virt_to_phys +#undef phys_to_virt + +uint32_t (*virt_to_phys)(void *) = host_virt_to_phys; +void* (*phys_to_virt)(uint32_t) = host_phys_to_virt; + + +uint32_t _romstart = 0xffffffff; +uint32_t _romend = 0; + +uint32_t romstart(void) +{ + return _romstart; +} + +uint32_t romend(void) +{ + return _romend; +} + +#include "cbfs_core.c" + diff --git a/payloads/libpayload/libcbfs/cbfs_core.c b/payloads/libpayload/libcbfs/cbfs_core.c new file mode 100644 index 0000000000..52ba58ded7 --- /dev/null +++ b/payloads/libpayload/libcbfs/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 + + +/* 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; + } +} + diff --git a/payloads/libpayload/liblzma/Makefile.inc b/payloads/libpayload/liblzma/Makefile.inc new file mode 100644 index 0000000000..2dd4a2d900 --- /dev/null +++ b/payloads/libpayload/liblzma/Makefile.inc @@ -0,0 +1,31 @@ +## +## 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. +## + +liblzma-$(CONFIG_LZMA) += lzma.c + diff --git a/payloads/libpayload/liblzma/lzma.c b/payloads/libpayload/liblzma/lzma.c new file mode 100644 index 0000000000..fdda30d8c4 --- /dev/null +++ b/payloads/libpayload/liblzma/lzma.c @@ -0,0 +1,47 @@ +/* + * coreboot interface to memory-saving variant of LZMA decoder + * + * Copyright (C) 2006 Carl-Daniel Hailfinger + * Released under the BSD license + * + * Parts of this file are based on C/7zip/Compress/LZMA_C/LzmaTest.c from the LZMA + * SDK 4.42, which is written and distributed to public domain by Igor Pavlov. + * + */ + +#include +#include +#include +#include "lzmadecode.c" + +unsigned long ulzma(unsigned char * src, unsigned char * dst) +{ + unsigned char properties[LZMA_PROPERTIES_SIZE]; + UInt32 outSize; + SizeT inProcessed; + SizeT outProcessed; + int res; + CLzmaDecoderState state; + SizeT mallocneeds; + unsigned char scratchpad[15980]; + + memcpy(properties, src, LZMA_PROPERTIES_SIZE); + outSize = *(UInt32 *)(src + LZMA_PROPERTIES_SIZE); + if (LzmaDecodeProperties(&state.Properties, properties, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK) { + printf("lzma: Incorrect stream properties.\n"); + return 0; + } + mallocneeds = (LzmaGetNumProbs(&state.Properties) * sizeof(CProb)); + if (mallocneeds > 15980) { + printf("lzma: Decoder scratchpad too small!\n"); + return 0; + } + state.Probs = (CProb *)scratchpad; + res = LzmaDecode(&state, src + LZMA_PROPERTIES_SIZE + 8, (SizeT)0xffffffff, &inProcessed, + dst, outSize, &outProcessed); + if (res != 0) { + printf("lzma: Decoding error = %d\n", res); + return 0; + } + return outSize; +} diff --git a/payloads/libpayload/liblzma/lzmadecode.c b/payloads/libpayload/liblzma/lzmadecode.c new file mode 100644 index 0000000000..1cf647d27b --- /dev/null +++ b/payloads/libpayload/liblzma/lzmadecode.c @@ -0,0 +1,398 @@ +/* + LzmaDecode.c + LZMA Decoder (optimized for Speed version) + + LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01) + http://www.7-zip.org/ + + LZMA SDK is licensed under two licenses: + 1) GNU Lesser General Public License (GNU LGPL) + 2) Common Public License (CPL) + It means that you can select one of these two licenses and + follow rules of that license. + + SPECIAL EXCEPTION: + Igor Pavlov, as the author of this Code, expressly permits you to + statically or dynamically link your Code (or bind by name) to the + interfaces of this file without subjecting your linked Code to the + terms of the CPL or GNU LGPL. Any modifications or additions + to this file, however, are subject to the LGPL or CPL terms. +*/ + +#include "lzmadecode.h" + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_READ_BYTE (*Buffer++) + +#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \ + { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }} + + +#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; } + +#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2 + + +#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; } + +#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound) +#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits; +#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits; + +#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \ + { UpdateBit0(p); mi <<= 1; A0; } else \ + { UpdateBit1(p); mi = (mi + mi) + 1; A1; } + +#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;) + +#define RangeDecoderBitTreeDecode(probs, numLevels, res) \ + { int i = numLevels; res = 1; \ + do { CProb *cp = probs + res; RC_GET_BIT(cp, res) } while(--i != 0); \ + res -= (1 << numLevels); } + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + + +#define kNumStates 12 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#if Literal != LZMA_BASE_SIZE +StopCompilingDueBUG +#endif + +int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size) +{ + unsigned char prop0; + if (size < LZMA_PROPERTIES_SIZE) + return LZMA_RESULT_DATA_ERROR; + prop0 = propsData[0]; + if (prop0 >= (9 * 5 * 5)) + return LZMA_RESULT_DATA_ERROR; + { + for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5)); + for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9); + propsRes->lc = prop0; + /* + unsigned char remainder = (unsigned char)(prop0 / 9); + propsRes->lc = prop0 % 9; + propsRes->pb = remainder / 5; + propsRes->lp = remainder % 5; + */ + } + + return LZMA_RESULT_OK; +} + +#define kLzmaStreamWasFinishedId (-1) + +int LzmaDecode(CLzmaDecoderState *vs, + const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, + unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed) +{ + CProb *p = vs->Probs; + SizeT nowPos = 0; + Byte previousByte = 0; + UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1; + UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1; + int lc = vs->Properties.lc; + + + int state = 0; + UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; + int len = 0; + const Byte *Buffer; + const Byte *BufferLim; + UInt32 Range; + UInt32 Code; + + *inSizeProcessed = 0; + *outSizeProcessed = 0; + + { + UInt32 i; + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); + for (i = 0; i < numProbs; i++) + p[i] = kBitModelTotal >> 1; + } + + RC_INIT(inStream, inSize); + + + while(nowPos < outSize) + { + CProb *prob; + UInt32 bound; + int posState = (int)( + (nowPos + ) + & posStateMask); + + prob = p + IsMatch + (state << kNumPosBitsMax) + posState; + IfBit0(prob) + { + int symbol = 1; + UpdateBit0(prob) + prob = p + Literal + (LZMA_LIT_SIZE * + ((( + (nowPos + ) + & literalPosMask) << lc) + (previousByte >> (8 - lc)))); + + if (state >= kNumLitStates) + { + int matchByte; + matchByte = outStream[nowPos - rep0]; + do + { + int bit; + CProb *probLit; + matchByte <<= 1; + bit = (matchByte & 0x100); + probLit = prob + 0x100 + bit + symbol; + RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break) + } + while (symbol < 0x100); + } + while (symbol < 0x100) + { + CProb *probLit = prob + symbol; + RC_GET_BIT(probLit, symbol) + } + previousByte = (Byte)symbol; + + outStream[nowPos++] = previousByte; + if (state < 4) state = 0; + else if (state < 10) state -= 3; + else state -= 6; + } + else + { + UpdateBit1(prob); + prob = p + IsRep + state; + IfBit0(prob) + { + UpdateBit0(prob); + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + state = state < kNumLitStates ? 0 : 3; + prob = p + LenCoder; + } + else + { + UpdateBit1(prob); + prob = p + IsRepG0 + state; + IfBit0(prob) + { + UpdateBit0(prob); + prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState; + IfBit0(prob) + { + UpdateBit0(prob); + + if (nowPos == 0) + return LZMA_RESULT_DATA_ERROR; + + state = state < kNumLitStates ? 9 : 11; + previousByte = outStream[nowPos - rep0]; + outStream[nowPos++] = previousByte; + + continue; + } + else + { + UpdateBit1(prob); + } + } + else + { + UInt32 distance; + UpdateBit1(prob); + prob = p + IsRepG1 + state; + IfBit0(prob) + { + UpdateBit0(prob); + distance = rep1; + } + else + { + UpdateBit1(prob); + prob = p + IsRepG2 + state; + IfBit0(prob) + { + UpdateBit0(prob); + distance = rep2; + } + else + { + UpdateBit1(prob); + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = p + RepLenCoder; + } + { + int numBits, offset; + CProb *probLen = prob + LenChoice; + IfBit0(probLen) + { + UpdateBit0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + numBits = kLenNumLowBits; + } + else + { + UpdateBit1(probLen); + probLen = prob + LenChoice2; + IfBit0(probLen) + { + UpdateBit0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + numBits = kLenNumMidBits; + } + else + { + UpdateBit1(probLen); + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + numBits = kLenNumHighBits; + } + } + RangeDecoderBitTreeDecode(probLen, numBits, len); + len += offset; + } + + if (state < 4) + { + int posSlot; + state += kNumLitStates; + prob = p + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot); + if (posSlot >= kStartPosModelIndex) + { + int numDirectBits = ((posSlot >> 1) - 1); + rep0 = (2 | ((UInt32)posSlot & 1)); + if (posSlot < kEndPosModelIndex) + { + rep0 <<= numDirectBits; + prob = p + SpecPos + rep0 - posSlot - 1; + } + else + { + numDirectBits -= kNumAlignBits; + do + { + RC_NORMALIZE + Range >>= 1; + rep0 <<= 1; + if (Code >= Range) + { + Code -= Range; + rep0 |= 1; + } + } + while (--numDirectBits != 0); + prob = p + Align; + rep0 <<= kNumAlignBits; + numDirectBits = kNumAlignBits; + } + { + int i = 1; + int mi = 1; + do + { + CProb *prob3 = prob + mi; + RC_GET_BIT2(prob3, mi, ; , rep0 |= i); + i <<= 1; + } + while(--numDirectBits != 0); + } + } + else + rep0 = posSlot; + if (++rep0 == (UInt32)(0)) + { + /* it's for stream version */ + len = kLzmaStreamWasFinishedId; + break; + } + } + + len += kMatchMinLen; + if (rep0 > nowPos) + return LZMA_RESULT_DATA_ERROR; + + + do + { + previousByte = outStream[nowPos - rep0]; + len--; + outStream[nowPos++] = previousByte; + } + while(len != 0 && nowPos < outSize); + } + } + RC_NORMALIZE; + + + *inSizeProcessed = (SizeT)(Buffer - inStream); + *outSizeProcessed = nowPos; + return LZMA_RESULT_OK; +} diff --git a/payloads/libpayload/liblzma/lzmadecode.h b/payloads/libpayload/liblzma/lzmadecode.h new file mode 100644 index 0000000000..34c9f14c33 --- /dev/null +++ b/payloads/libpayload/liblzma/lzmadecode.h @@ -0,0 +1,67 @@ +/* + LzmaDecode.h + LZMA Decoder interface + + LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01) + http://www.7-zip.org/ + + LZMA SDK is licensed under two licenses: + 1) GNU Lesser General Public License (GNU LGPL) + 2) Common Public License (CPL) + It means that you can select one of these two licenses and + follow rules of that license. + + SPECIAL EXCEPTION: + Igor Pavlov, as the author of this code, expressly permits you to + statically or dynamically link your code (or bind by name) to the + interfaces of this file without subjecting your linked code to the + terms of the CPL or GNU LGPL. Any modifications or additions + to this file, however, are subject to the LGPL or CPL terms. +*/ + +#ifndef __LZMADECODE_H +#define __LZMADECODE_H + +typedef unsigned char Byte; +typedef unsigned short UInt16; +typedef unsigned int UInt32; +typedef UInt32 SizeT; + +#define CProb UInt16 + +#define LZMA_RESULT_OK 0 +#define LZMA_RESULT_DATA_ERROR 1 + + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +#define LZMA_PROPERTIES_SIZE 5 + +typedef struct _CLzmaProperties +{ + int lc; + int lp; + int pb; +}CLzmaProperties; + +int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size); + +#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp))) + +#define kLzmaNeedInitId (-2) + +typedef struct _CLzmaDecoderState +{ + CLzmaProperties Properties; + CProb *Probs; + + +} CLzmaDecoderState; + + +int LzmaDecode(CLzmaDecoderState *vs, + const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, + unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed); + +#endif