diff options
Diffstat (limited to 'payloads/bayou')
25 files changed, 3227 insertions, 0 deletions
diff --git a/payloads/bayou/Makefile b/payloads/bayou/Makefile new file mode 100644 index 0000000000..648d68a28c --- /dev/null +++ b/payloads/bayou/Makefile @@ -0,0 +1,65 @@ +## +## This file is part of the bayou project. +## +## Copyright (C) 2008 Advanced Micro Devices, Inc. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## 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 +## + +CONFIG_LZMA=y +CONFIG_NRV2B=y +CONFIG_BUILTIN_LAR=y + +PBUILDER_CONFIG=bayou.xml +BUILTIN_LAR=builtin.lar + +LIBPAYLOAD_DIR := ../libpayload + +CC=gcc + +FFLAGS-y= +FFLAGS-$(CONFIG_BUILTIN_LAR) += -DCONFIG_BUILTIN_LAR +FFLAGS-$(CONFIG_LZMA) += -DCONFIG_LZMA +FFLAGS-$(CONFIG_NRV2B) += -DCONFIG_NRV2B + +OBJECTS-y=main.o payload.o config.o menu.o self.o +OBJECTS-$(CONFIG_LZMA) += lzma.o +OBJECTS-$(CONFIG_NRV2B) += nrv2b.o +OBJECTS-$(CONFIG_BUILTIN_LAR) += builtin-lar.o + +CFLAGS= -Wall -Werror -Os $(FFLAGS-y) +LDFLAGS=-Wl,-T,bayou.ldscript -static +LIBGCC=$(shell $(CC) -m32 -print-libgcc-file-name) + +LPCC=$(LIBPAYLOAD_DIR)/bin/lpgcc + +bayou.elf: $(OBJECTS-y) + $(LPCC) -ldscript bayou.ldscript -m32 -o $@ $(OBJECTS-y) + @ strip $@ + +builtin-lar.o: $(BUILTIN_LAR) + @ objcopy -I binary -B i386 -O elf32-i386 $(BUILTIN_LAR) $@ + +builtin.lar: util/pbuilder/pbuilder + @ rm -f $@ + util/pbuilder/pbuilder -c $(PBUILDER_CONFIG) create $@ + +util/pbuilder/pbuilder: + make -C util/pbuilder + +%.o: %.c + $(LPCC) $(CFLAGS) -c -o $@ $< + +clean: + rm -f *.o bayou.elf builtin.lar diff --git a/payloads/bayou/bayou.h b/payloads/bayou/bayou.h new file mode 100644 index 0000000000..d3d58a6dbd --- /dev/null +++ b/payloads/bayou/bayou.h @@ -0,0 +1,87 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + */ + +#ifndef BAYOU_H_ +#define BAYOU_H_ + +#include <libpayload.h> + +#define BAYOU_MAX_ENTRIES 10 + +struct bpt_config { + u32 id; + u8 timeout; + u8 entries; + u8 padding[10]; +}; + +struct bpt_pentry { + u8 index; + u8 parent; + u8 type; + u8 flags; + u8 title[64]; + u8 nlen; +}; + +#define BPT_ID 0x30545042 +#define BPT_TYPE_CHOOSER 0x01 +#define BPT_TYPE_CHAIN 0x02 +#define BPT_TYPE_SUBCHAIN 0x03 + +#define BPT_FLAG_DEFAULT 0x01 +#define BPT_FLAG_NOSHOW 0x02 + +enum bayou_params { + BAYOU_PARAM_NAME = 0, + BAYOU_PARAM_LIST, + BAYOU_PARAM_DESC, + BAYOU_PARAMS_COUNT +}; + +struct payload { + struct bpt_pentry pentry; + struct larstat stat; + u8 *fptr; + char *params[BAYOU_PARAMS_COUNT]; +}; + +struct bayoucfg { + u8 timeout; + int n_entries; + struct payload entries[BAYOU_MAX_ENTRIES]; +}; + +extern struct bayoucfg bayoucfg; + +int verify_self(u8 *ptr); +int self_get_params(u8 *fptr, u8 **params); +int self_load_and_run(struct payload *p, int *ret); + +void menu(void); + +void run_payload(struct payload *p); +char *payload_get_name(struct payload *p); +struct payload *payload_get_default(void); +void run_payload_timeout(struct payload *p, int timeout); +void payload_parse_params(struct payload *pload, u8 *params, int len); + +int get_configuration(struct LAR *lar); + +#endif diff --git a/payloads/bayou/bayou.ldscript b/payloads/bayou/bayou.ldscript new file mode 100644 index 0000000000..c4123a64cc --- /dev/null +++ b/payloads/bayou/bayou.ldscript @@ -0,0 +1,85 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * 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. + */ + +BASE_ADDRESS = 0x19000; + +OUTPUT_FORMAT(elf32-i386) +OUTPUT_ARCH(i386) + +ENTRY(_entry) + +HEAP_SIZE = 16384; +STACK_SIZE = 16384; + +SECTIONS +{ + . = BASE_ADDRESS; + + . = ALIGN(16); + _start = .; + + .text : { + *(.text._entry) + *(.text) + *(.text.*) + } + + .rodata : { + *(.rodata) + *(.rodata.*) + } + + .data : { + *(.data) + *(.data.*) + } + + .bss : { + *(.bss) + *(.bss.*) + *(COMMON) + + /* Stack and heap */ + + . = ALIGN(16); + _heap = .; + . += HEAP_SIZE; + . = ALIGN(16); + _eheap = .; + + _estack = .; + . += STACK_SIZE; + . = ALIGN(16); + _stack = .; + } + + _end = .; + + /DISCARD/ : { *(.comment) *(.note) *(.note.*) } +} diff --git a/payloads/bayou/config.c b/payloads/bayou/config.c new file mode 100644 index 0000000000..3aba88f9a4 --- /dev/null +++ b/payloads/bayou/config.c @@ -0,0 +1,165 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + */ + +#include "bayou.h" + +struct bayoucfg bayoucfg; + +static int add_payload(struct LAR *lar, struct larent *larent) +{ + struct payload *payload; + int plen; + u8 *params = NULL; + u8 *fptr; + + if (bayoucfg.n_entries == BAYOU_MAX_ENTRIES) + return -1; + + payload = &bayoucfg.entries[bayoucfg.n_entries]; + + if (strncmp((char *)larent->name, "payload/", 8)) + return -1; + + if (larstat(lar, (const char *)larent->name, &payload->stat)) + return -1; + + /* Make sure the LAR entry is valid. */ + if (!lfverify(lar, (const char *)larent->name)) + return -1; + + /* Get a pointer to the start of the file. */ + fptr = larfptr(lar, (const char *)larent->name); + + if (fptr == NULL) + return -1; + + if (!verify_self(fptr)) + return -1; + + payload->pentry.index = bayoucfg.n_entries; + payload->pentry.parent = 0; + payload->pentry.type = BPT_TYPE_CHOOSER; + payload->pentry.flags = 0; + + plen = self_get_params(fptr, ¶ms); + payload_parse_params(payload, params, plen); + + payload->fptr = fptr; + + bayoucfg.n_entries++; + + return 0; +} + +static int lar_walk_files(struct LAR *lar, + int (*cb) (struct LAR *, struct larent *)) +{ + struct larent *larent; + int ret = 0; + + rewindlar(lar); + + while ((larent = readlar(lar)) != NULL) { + if ((ret = cb(lar, larent))) + break; + } + + return ret; +} + +/** + * If reading the bayou_payload_table fails for some reason, then construct + * a dummy table. All valid payloads in the lar are added as chooser items. + */ +static void build_dummy_table(struct LAR *lar) +{ + bayoucfg.timeout = 0xFF; + bayoucfg.n_entries = 0; + + lar_walk_files(lar, add_payload); +} + +int get_configuration(struct LAR *lar) +{ + struct larstat stat; + struct bpt_config *bptcfg; + u8 *fptr, *ptr; + int i; + + /* + * If bayou_payload_table doesn't exist, then dummy up + * a table from the LAR contents. + */ + if (larstat(lar, "bayou_payload_table", &stat) || + !lfverify(lar, "bayou_payload_table")) + build_dummy_table(lar); + + /* Open up the BPT and get the creamy goodness within. */ + + fptr = larfptr(lar, "bayou_payload_table"); + + if (fptr == NULL) + build_dummy_table(lar); + + bptcfg = (struct bpt_config *)fptr; + bayoucfg.timeout = bptcfg->timeout; + + bayoucfg.n_entries = bptcfg->entries; + + if (bayoucfg.n_entries > BAYOU_MAX_ENTRIES) { + printf("W: Limiting the number of entries to %d\n", + BAYOU_MAX_ENTRIES); + bayoucfg.n_entries = BAYOU_MAX_ENTRIES; + } + + ptr = fptr + sizeof(struct bpt_config); + + for (i = 0; i < bayoucfg.n_entries; i++) { + struct bpt_pentry *entry = (struct bpt_pentry *)ptr; + struct payload *p = &(bayoucfg.entries[i]); + int plen; + u8 *params = NULL; + + memcpy(&p->pentry, entry, sizeof(struct bpt_pentry)); + + if (entry->type != BPT_TYPE_CHAIN) { + char *lname = (char *)ptr + sizeof(struct bpt_pentry); + + if (larstat(lar, (const char *)lname, &p->stat)) + build_dummy_table(lar); + + if (!lfverify(lar, (const char *)lname)) + build_dummy_table(lar); + + fptr = larfptr(lar, (const char *)lname); + + if (verify_self(fptr)) + p->fptr = fptr; + else + build_dummy_table(lar); + + plen = self_get_params(fptr, ¶ms); + payload_parse_params(p, params, plen); + } + + ptr += sizeof(struct bpt_pentry) + entry->nlen; + } + + return 0; +} diff --git a/payloads/bayou/lzma.c b/payloads/bayou/lzma.c new file mode 100644 index 0000000000..a7a8717c6a --- /dev/null +++ b/payloads/bayou/lzma.c @@ -0,0 +1,43 @@ +/* + +Coreboot interface to memory-saving variant of LZMA decoder + +(C)opyright 2006 Carl-Daniel Hailfinger +Released under the GNU GPL v2 or later + +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 <libpayload.h> +#include "lzmadecode.c" + +unsigned long ulzma(u8 *src, u8 *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("Incorrect stream properties\n"); + } + mallocneeds = (LzmaGetNumProbs(&state.Properties) * sizeof(CProb)); + if (mallocneeds > 15980) { + printf("Decoder scratchpad too small!\n"); + } + state.Probs = (CProb *)scratchpad; + res = LzmaDecode(&state, src + LZMA_PROPERTIES_SIZE + 8, (SizeT)0xffffffff, &inProcessed, + dst, outSize, &outProcessed); + if (res != 0) { + printf("Decoding error = %d\n", res); + } + return outSize; +} diff --git a/payloads/bayou/lzmadecode.c b/payloads/bayou/lzmadecode.c new file mode 100644 index 0000000000..1c96283fbb --- /dev/null +++ b/payloads/bayou/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 *p = probs + res; RC_GET_BIT(p, 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/bayou/lzmadecode.h b/payloads/bayou/lzmadecode.h new file mode 100644 index 0000000000..f885446ced --- /dev/null +++ b/payloads/bayou/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 /* LZMADECODE_H */ diff --git a/payloads/bayou/main.c b/payloads/bayou/main.c new file mode 100644 index 0000000000..a9e76d7c97 --- /dev/null +++ b/payloads/bayou/main.c @@ -0,0 +1,70 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + */ + +#include "bayou.h" + +static void print_banner(void) +{ + printf("\e[H\e[JBayou Payload Chooser v0.3\n"); +} + +int main(void) +{ + extern unsigned long _binary_builtin_lar_start; + struct LAR *lar; + + print_banner(); + + lar = openlar((void *)&_binary_builtin_lar_start); + + if (lar == NULL) { + printf("[CHOOSER]: Unable to scan the attached LAR file\n"); + return -1; + } + + get_configuration(lar); + + if (bayoucfg.n_entries == 0) { + printf("[CHOOSER]: No payloads were found in the LAR\n"); + return -1; + } + + /* + * If timeout == 0xFF, then show the menu immediately. + * If timeout is zero, then find and run the default item immediately. + * If there is no default item, then show the menu. + * If timeout is anything else, then show a message and wait for a + * keystroke. If there is no keystroke in time then run the default. + * If there is no default then show the menu. + */ + if (bayoucfg.timeout != 0xFF) { + struct payload *d = payload_get_default(); + + if (d != NULL) { + if (bayoucfg.timeout == 0) + run_payload(d); + else + run_payload_timeout(d, bayoucfg.timeout); + } + } + + menu(); + + return 0; +} diff --git a/payloads/bayou/menu.c b/payloads/bayou/menu.c new file mode 100644 index 0000000000..97f6c14d7d --- /dev/null +++ b/payloads/bayou/menu.c @@ -0,0 +1,155 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + */ + +#include <libpayload.h> +#include <curses.h> +#include "bayou.h" + +#define SCREEN_X 80 +#define SCREEN_Y 25 + +static int menu_width = 0; +static struct payload *mpayloads[BAYOU_MAX_ENTRIES]; +static int m_entries = 0; +static unsigned int selected = 0; +static WINDOW *menuwin, *status; + +void create_menu(void) +{ + int i; + + for (i = 0; i < bayoucfg.n_entries; i++) { + struct payload *p = &(bayoucfg.entries[i]); + char *name; + + if ((p->pentry.parent != 0) || + (p->pentry.flags & BPT_FLAG_NOSHOW)) + continue; + + mpayloads[m_entries++] = p; + + name = payload_get_name(p); + + if (strlen(name) > menu_width) + menu_width = strlen(name); + } + + menu_width += 4; + + if (menu_width < 30) + menu_width = 30; + + menuwin = newwin(m_entries + 3, menu_width, + (SCREEN_Y - (m_entries + 3)) / 2, + (SCREEN_X - menu_width) / 2); +} + +void draw_menu(void) +{ + struct payload *s; + int i; + + wattrset(menuwin, COLOR_PAIR(3)); + wclear(menuwin); + wborder(menuwin, '\263', '\263', '\304', '\304', '\332', + '\277', '\300', '\331'); + + wattrset(menuwin, COLOR_PAIR(4) | A_BOLD); + mvwprintw(menuwin, 0, (menu_width - 17) / 2, " Payload Chooser "); + + wattrset(menuwin, COLOR_PAIR(3)); + + for (i = 0; i < m_entries; i++) { + char *name = payload_get_name(mpayloads[i]); + int col = (menu_width - (2 + strlen(name))) / 2; + + if (i == selected) + wattrset(menuwin, COLOR_PAIR(5) | A_BOLD); + else + wattrset(menuwin, COLOR_PAIR(3)); + + mvwprintw(menuwin, 2 + i, col, name); + } + + s = mpayloads[selected]; + + wclear(status); + + if (s->params[BAYOU_PARAM_DESC] != NULL) { + char buf[66]; + int len = strnlen(s->params[BAYOU_PARAM_DESC], 65); + + snprintf(buf, 65, s->params[BAYOU_PARAM_DESC]); + buf[65] = 0; + + mvwprintw(status, 0, (80 - len) / 2, buf); + } + + wrefresh(menuwin); + wrefresh(status); +} + +void loop(void) +{ + int key; + + while (1) { + key = getch(); + + if (key == ERR) + continue; + + if (key == KEY_DOWN) + selected = (selected + 1) % m_entries; + else if (key == KEY_UP) + selected = (selected - 1) % m_entries; + else if (key == KEY_ENTER) { + run_payload(mpayloads[selected]); + refresh(); + } else + continue; + + draw_menu(); + } +} + +void menu(void) +{ + initscr(); + + init_pair(1, COLOR_WHITE, COLOR_RED); + init_pair(2, COLOR_BLACK, COLOR_WHITE); + init_pair(3, COLOR_BLACK, COLOR_WHITE); + init_pair(4, COLOR_CYAN, COLOR_WHITE); + init_pair(5, COLOR_WHITE, COLOR_RED); + + wattrset(stdscr, COLOR_PAIR(1)); + wclear(stdscr); + + status = newwin(1, 80, 24, 0); + wattrset(status, COLOR_PAIR(2)); + wclear(status); + + refresh(); + + create_menu(); + draw_menu(); + + loop(); +} diff --git a/payloads/bayou/nrv2b.c b/payloads/bayou/nrv2b.c new file mode 100644 index 0000000000..11f977e7e4 --- /dev/null +++ b/payloads/bayou/nrv2b.c @@ -0,0 +1,87 @@ +#include <libpayload.h> + +// This GETBIT is supposed to work on little endian +// 32bit systems. The algorithm will definitely need +// some fixing on other systems, but it might not be +// a problem since the nrv2b binary behaves the same.. + +#ifndef ENDIAN +#define ENDIAN 0 +#endif +#ifndef BITSIZE +#define BITSIZE 32 +#endif + +#define GETBIT_8(bb, src, ilen) \ + (((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1) + +#define GETBIT_LE16(bb, src, ilen) \ + (bb*=2,bb&0xffff ? (bb>>16)&1 : (ilen+=2,((bb=(src[ilen-2]+src[ilen-1]*256u)*2+1)>>16)&1)) +#define GETBIT_LE32(bb, src, ilen) \ + (bc > 0 ? ((bb>>--bc)&1) : (bc=31,\ + bb=*(const u32 *)((src)+ilen),ilen+=4,(bb>>31)&1)) + +#if ENDIAN == 0 && BITSIZE == 8 +#define GETBIT(bb, src, ilen) GETBIT_8(bb, src, ilen) +#endif +#if ENDIAN == 0 && BITSIZE == 16 +#define GETBIT(bb, src, ilen) GETBIT_LE16(bb, src, ilen) +#endif +#if ENDIAN == 0 && BITSIZE == 32 +#define GETBIT(bb, src, ilen) GETBIT_LE32(bb, src, ilen) +#endif + +unsigned long unrv2b(u8 *src, u8 *dst, unsigned long *ilen_p) +{ + unsigned long ilen = 0, olen = 0, last_m_off = 1; + u32 bb = 0; + unsigned bc = 0; + const u8 *m_pos; + + // skip length + src += 4; + /* FIXME: check olen with the length stored in first 4 bytes */ + + for (;;) { + unsigned int m_off, m_len; + while (GETBIT(bb, src, ilen)) { + dst[olen++] = src[ilen++]; + } + + m_off = 1; + do { + m_off = m_off * 2 + GETBIT(bb, src, ilen); + } while (!GETBIT(bb, src, ilen)); + if (m_off == 2) { + m_off = last_m_off; + } else { + m_off = (m_off - 3) * 256 + src[ilen++]; + if (m_off == 0xffffffffU) + break; + last_m_off = ++m_off; + } + + m_len = GETBIT(bb, src, ilen); + m_len = m_len * 2 + GETBIT(bb, src, ilen); + if (m_len == 0) { + m_len++; + do { + m_len = m_len * 2 + GETBIT(bb, src, ilen); + } while (!GETBIT(bb, src, ilen)); + m_len += 2; + } + m_len += (m_off > 0xd00); + + m_pos = dst + olen - m_off; + dst[olen++] = *m_pos++; + do { + dst[olen++] = *m_pos++; + } while (--m_len > 0); + } + + *ilen_p = ilen; + + return olen; + +} + diff --git a/payloads/bayou/payload.c b/payloads/bayou/payload.c new file mode 100644 index 0000000000..20ea74b3d4 --- /dev/null +++ b/payloads/bayou/payload.c @@ -0,0 +1,111 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + */ + +#include "bayou.h" + +#define TIMEOUT_MESSAGE "Press ESC for the menu (%2d)...\r" +#define TIMEOUT_KEY '\033' + +void run_payload(struct payload *p) +{ + int ret, i; + + /* For chooser entries, just run the payload. */ + if (p->pentry.type == BPT_TYPE_CHOOSER) { + self_load_and_run(p, &ret); + return; + } + + /* For chained entries, run all the sub-chain items. */ + for (i = 0; i < bayoucfg.n_entries; i++) { + struct payload *s = &(bayoucfg.entries[i]); + + if (s->pentry.parent == p->pentry.index) + self_load_and_run(s, &ret); + } +} + +char *payload_get_name(struct payload *p) +{ + if (p->pentry.type == BPT_TYPE_CHAIN) + return (char *)p->pentry.title; + else if (p->pentry.type == BPT_TYPE_CHOOSER) { + if (p->pentry.title[0] != 0) + return (char *)p->pentry.title; + return p->params[BAYOU_PARAM_DESC]; + } + + return NULL; +} + +struct payload *payload_get_default(void) +{ + int i; + + for (i = 0; i < bayoucfg.n_entries; i++) { + struct payload *s = &(bayoucfg.entries[i]); + + if (s->pentry.parent == 0 && s->pentry.flags & BPT_FLAG_DEFAULT) + return s; + } + + return NULL; +} + +void run_payload_timeout(struct payload *p, int timeout) +{ + int t, ch, tval; + + for (t = timeout; t >= 0; t--) { + printf(TIMEOUT_MESSAGE, t); + + tval = 1000; + ch = getchar_timeout(&tval); + + if (ch == TIMEOUT_KEY) + return; + } + + run_payload(p); +} + +void payload_parse_params(struct payload *pload, u8 *params, int len) +{ + char *ptr = (char *)params; + int i = 0; + + if (ptr == NULL) + return; + + while (ptr < ((char *)params + len)) { + + if (!strncmp(ptr, "name=", 5)) { + pload->params[BAYOU_PARAM_NAME] = ptr + 5; + } else if (!strncmp(ptr, "desc=", 5)) { + pload->params[BAYOU_PARAM_DESC] = ptr + 5; + } else if (!strncmp(ptr, "listname=", 9)) { + pload->params[BAYOU_PARAM_LIST] = ptr + 9; + } + + ptr += strnlen(ptr, len - i); + + if (ptr < ((char *)params + len) && *ptr == 0) + ptr++; + } +} diff --git a/payloads/bayou/self.c b/payloads/bayou/self.c new file mode 100644 index 0000000000..0de2a62260 --- /dev/null +++ b/payloads/bayou/self.c @@ -0,0 +1,147 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + */ + +#include "bayou.h" +#include "self.h" + +static int nop_decompress(void *dst, void *src, int len) +{ + memcpy(dst, src, len); + return len; +} + +#ifdef CONFIG_LZMA +extern int ulzma(u8 *, u8 *); + +static int lzma_decompress(void *dst, void *src, int len) +{ + return ulzma((u8 *) src, (u8 *) dst); +} +#endif + +#ifdef CONFIG_NRV2B +extern int unrv2b(u8 *, u8 *, unsigned long *); + +static int nrv2b_decompress(void *dst, void *src, int len) +{ + unsigned long l = (u32) len; + return unrv2b(src, dst, &l); +} +#endif + +static int zeros_decompress(void *dst, void *src, int len) +{ + memset(dst, 0, len); + return len; +} + +int self_get_params(u8 *fptr, u8 **params) +{ + struct self_segment *seg = (struct self_segment *)fptr; + + while (seg->type != SELF_TYPE_ENTRY) { + if (seg->type == 0) + return -1; + + if (seg->type == SELF_TYPE_PARAMS) { + *params = (u8 *) (fptr + seg->offset); + return seg->len; + } + + seg++; + } + + *params = NULL; + + return 0; +} + +int verify_self(u8 *ptr) +{ + struct self_segment *seg = (struct self_segment *)ptr; + + switch (seg->type) { + case SELF_TYPE_CODE: + case SELF_TYPE_DATA: + case SELF_TYPE_BSS: + case SELF_TYPE_PARAMS: + case SELF_TYPE_ENTRY: + return 1; + } + + return 0; +} + +int self_load_and_run(struct payload *p, int *ret) +{ + struct self_segment *seg = (struct self_segment *)p->fptr; + int (*dcmp) (void *, void *, int); + int dlen; + + switch (p->stat.compression) { +#ifdef CONFIG_LZMA + case ALGO_LZMA: + dcmp = lzma_decompress; + break; +#endif +#ifdef CONFIG_NRV2B + case ALGO_NRV2B: + dcmp = nrv2b_decompress; + break; +#endif + case ALGO_ZEROES: + dcmp = zeros_decompress; + break; + case ALGO_NONE: + dcmp = nop_decompress; + default: + printf("E: Unsupported decompression type\n"); + return -1; + } + + while (1) { + u32 laddr = (u32) (seg->load_addr & 0xFFFFFFFF); + + switch (seg->type) { + case SELF_TYPE_CODE: + case SELF_TYPE_DATA: + dlen = dcmp((void *)laddr, + (void *)p->fptr + seg->offset, seg->len); + + if (dlen < seg->mem_len) { + memset((void *)(laddr + dlen), 0, + seg->mem_len - dlen); + } + break; + + case SELF_TYPE_BSS: + memset((void *)laddr, 0, seg->len); + break; + case SELF_TYPE_ENTRY: + *ret = exec(laddr, 0, NULL); + return 0; + default: + break; + } + + seg++; + } + + return -1; +} diff --git a/payloads/bayou/self.h b/payloads/bayou/self.h new file mode 100644 index 0000000000..3c5552e6b7 --- /dev/null +++ b/payloads/bayou/self.h @@ -0,0 +1,44 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + */ + +#ifndef SELF_H_ +#define SELF_H_ + +#include <libpayload.h> + +struct self_segment { + u32 type; + u32 offset; + u64 load_addr; + u32 len; + u32 mem_len; +}; + +struct self { + struct larstat stat; + void *fptr; +}; + +#define SELF_TYPE_CODE 0x45444F43 +#define SELF_TYPE_DATA 0x41544144 +#define SELF_TYPE_BSS 0x20535342 +#define SELF_TYPE_PARAMS 0x41524150 +#define SELF_TYPE_ENTRY 0x52544E45 + +#endif diff --git a/payloads/bayou/util/pbuilder/Makefile b/payloads/bayou/util/pbuilder/Makefile new file mode 100644 index 0000000000..8483935cc6 --- /dev/null +++ b/payloads/bayou/util/pbuilder/Makefile @@ -0,0 +1,38 @@ +## +## This file is part of the bayou project. +## +## Copyright (C) 2008 Advanced Micro Devices, Inc. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## 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 +## + +CC=gcc +PBUILDOBJS := config.o create.o show.o main.o +INCLUDES := -Iliblar/ +CFLAGS=-Wall -Werror -g + +pbuilder: $(PBUILDOBJS) $(LZMA_OBJ) liblar/liblar.a + $(CXX) -o $@ $(PBUILDOBJS) $(LZMA_OBJ) -L ./liblar -llar -lexpat + +liblar/liblar.a: + make -C liblar + +include lzma/Makefile + +%.o: %.c + $(CC) -c $(CFLAGS) $(INCLUDES) -o $@ $< + +clean: + rm -f pbuilder *.o + make -C liblar clean diff --git a/payloads/bayou/util/pbuilder/config.c b/payloads/bayou/util/pbuilder/config.c new file mode 100644 index 0000000000..7b517335e3 --- /dev/null +++ b/payloads/bayou/util/pbuilder/config.c @@ -0,0 +1,265 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + */ + +#define _GNU_SOURCE + +#include <stdlib.h> +#include <string.h> +#include <expat.h> +#include <ctype.h> +#include "pbuilder.h" + +#define STATE_NONE 0x00 +#define STATE_BAYOUCONFIG 0x01 +#define STATE_GLOBAL 0x02 +#define STATE_GLOBAL_TIMEOUT 0x03 +#define STATE_PAYLOADS 0x04 +#define STATE_PAYLOAD 0x05 +#define STATE_PAYLOAD_TITLE 0x06 +#define STATE_PAYLOAD_FILE 0x07 +#define STATE_PAYLOAD_LARNAME 0x08 +#define STATE_PAYLOAD_CHAIN 0x09 +#define STATE_PAYLOAD_CHAIN_FILE 0x0A +#define STATE_PAYLOAD_CHAIN_LARNAME 0x0B + +static struct userdata { + struct config *config; + struct pentry *payload; + struct pentry *chain; + int state; +} userdata; + +static char buffer[8192]; + +static struct { + char *element; + int pstate; + int state; +} states[] = { + {"BayouConfig", STATE_NONE, STATE_BAYOUCONFIG}, + {"global", STATE_BAYOUCONFIG, STATE_GLOBAL}, + {"timeout", STATE_GLOBAL, STATE_GLOBAL_TIMEOUT}, + {"payloads", STATE_BAYOUCONFIG, STATE_PAYLOADS}, + {"payload", STATE_PAYLOADS, STATE_PAYLOAD}, + {"title", STATE_PAYLOAD, STATE_PAYLOAD_TITLE}, + {"lar", STATE_PAYLOAD, STATE_PAYLOAD_LARNAME}, + {"file", STATE_PAYLOAD, STATE_PAYLOAD_FILE}, + {"chain", STATE_PAYLOAD, STATE_PAYLOAD_CHAIN}, + {"file", STATE_PAYLOAD_CHAIN, STATE_PAYLOAD_CHAIN_FILE}, + {"lar", STATE_PAYLOAD_CHAIN, STATE_PAYLOAD_CHAIN_LARNAME}, + {NULL}, +}; + +static struct pentry *newPayload(struct config *config) +{ + struct pentry **tmp, *ret; + + tmp = realloc(config->entries, + (config->n_entries + 1) * sizeof(struct pentry *)); + + if (tmp == NULL) + return NULL; + + config->entries = tmp; + + ret = config->entries[config->n_entries] = calloc(sizeof(*ret), 1); + + if (ret == NULL) + return NULL; + + /* Yes, I want this to be ++config->n_entries (the index is 1 based). */ + ret->index = ++config->n_entries; + + return ret; +} + +static void parseFlags(struct pentry *entry, const char *flags) +{ + char *p = (char *)flags; + char *n; + + while (*p) { + n = strchr(p, ','); + + if (n) + *(n++) = 0; + + if (!strcmp(p, "default")) + entry->flags |= BPT_FLAG_DEFAULT; + else if (!strcmp(p, "nolist")) + entry->flags |= BPT_FLAG_NOSHOW; + else + warn("W: Unknown payload flag %s\n", p); + + if (!n) + break; + + for (p = n; *p && isspace(*p); p++) ; + } +} + +static struct pentry *addPayload(struct config *config, const char **attr) +{ + struct pentry *ret = newPayload(config); + int i = 0; + + if (ret == NULL) + die("E: Could not allocate memory for a new payload\n"); + + while (attr[i] != NULL) { + if (!strcmp(attr[i], "type")) { + if (!strcmp(attr[i + 1], "chain")) + ret->type = BPT_TYPE_CHAIN; + else if (!strcmp(attr[i + 1], "chooser")) + ret->type = BPT_TYPE_CHOOSER; + else + die("E: Invalid payload type %s\n", + attr[i + 1]); + } else if (!strcmp(attr[i], "flags")) + parseFlags(ret, attr[i + 1]); + + i += 2; + } + + return ret; +} + +static struct pentry *addChain(struct config *config, struct pentry *parent) +{ + struct pentry *ret = newPayload(config); + + if (ret == NULL) + die("E: Could not allocate memory for a new payload\n"); + + ret->parent = parent->index; + ret->type = BPT_TYPE_SUBCHAIN; + + return ret; +} + +static void start(void *data, const char *el, const char **attr) +{ + int i; + struct userdata *d = (struct userdata *)data; + + for (i = 0; states[i].element != NULL; i++) { + if (d->state != states[i].pstate) + continue; + + if (!strcmp(el, states[i].element)) { + d->state = states[i].state; + break; + } + } + + if (states[i].element == NULL) + die("E: Unknown element %s\n", el); + + if (d->state == STATE_PAYLOAD) + d->payload = addPayload(d->config, attr); + + if (d->state == STATE_PAYLOAD_CHAIN) + d->chain = addChain(d->config, d->payload); +} + +static void data(void *data, const char *val, int len) +{ + struct userdata *d = (struct userdata *)data; + int l; + + switch (d->state) { + case STATE_GLOBAL_TIMEOUT: + d->config->timeout = atoi(val); + break; + case STATE_PAYLOAD_TITLE: + l = sizeof(d->payload->title) - 1 > len ? + len : sizeof(d->payload->title) - 1; + + strncpy((char *)d->payload->title, (char *)val, l); + d->payload->title[l] = '\0'; + break; + case STATE_PAYLOAD_FILE: + d->payload->file = strndup(val, len); + break; + case STATE_PAYLOAD_LARNAME: + d->payload->larname = strndup(val, len); + break; + case STATE_PAYLOAD_CHAIN_FILE: + d->chain->file = strndup(val, len); + break; + case STATE_PAYLOAD_CHAIN_LARNAME: + d->chain->larname = strndup(val, len); + break; + default: + break; + } +} + +static void end(void *data, const char *el) +{ + struct userdata *d = (struct userdata *)data; + int i; + + if (d->state == STATE_PAYLOAD_CHAIN) + d->chain = NULL; + + if (d->state == STATE_PAYLOAD) + d->payload = NULL; + + for (i = 0; states[i].element != NULL; i++) { + if (d->state != states[i].state) + continue; + + if (!strcmp(el, states[i].element)) { + d->state = states[i].pstate; + break; + } + } + + if (states[i].element == NULL) + die("E: Unable to find the reverse state for %s\n", el); +} + +void parseconfig(FILE *stream, struct config *config) +{ + XML_Parser p = XML_ParserCreate(NULL); + int eof = 0; + + if (p == NULL) + die("E: Could not create the parser\n"); + + XML_SetElementHandler(p, start, end); + XML_SetCharacterDataHandler(p, data); + + userdata.config = config; + + XML_SetUserData(p, &userdata); + + while (!eof) { + int len = fread(buffer, 1, 8192, stream); + + eof = feof(stream); + + if (ferror(stream)) + die("E: Error reading the stream\n"); + + if (!XML_Parse(p, buffer, len, eof)) + die("E: Error parsing the XML data\n"); + } +} diff --git a/payloads/bayou/util/pbuilder/create.c b/payloads/bayou/util/pbuilder/create.c new file mode 100644 index 0000000000..313283c302 --- /dev/null +++ b/payloads/bayou/util/pbuilder/create.c @@ -0,0 +1,200 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + */ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <libgen.h> +#include "liblar.h" +#include "pbuilder.h" + +void do_lzma_compress(char *in, int in_len, char *out, int *out_len); + +int add_bpt_to_lar(struct LAR *lar, struct config *config) +{ + char *buffer; + int ret, i, len = sizeof(struct bpt_config); + struct bpt_config *cfg; + struct LARAttr attr; + char *ptr; + + for (i = 0; i < config->n_entries; i++) { + len += sizeof(struct bpt_pentry); + + if (config->entries[i]->type != BPT_TYPE_CHAIN) + len += ((strlen(config->entries[i]->larname) + + 15) & ~0x0F); + } + + buffer = calloc(len, 1); + + if (buffer == NULL) + return -1; + + cfg = (struct bpt_config *)buffer; + + cfg->id = BPT_ID; + cfg->timeout = config->timeout; + cfg->entries = config->n_entries; + + ptr = buffer + sizeof(struct bpt_config); + + for (i = 0; i < config->n_entries; i++) { + int nlen = 0; + struct bpt_pentry *pentry = (struct bpt_pentry *)ptr; + + pentry->index = config->entries[i]->index; + pentry->parent = config->entries[i]->parent; + pentry->type = config->entries[i]->type; + pentry->flags = config->entries[i]->flags; + + strncpy((char *)pentry->title, + (char *)config->entries[i]->title, + sizeof(pentry->title)); + + if (config->entries[i]->type != BPT_TYPE_CHAIN) { + nlen = strlen(config->entries[i]->larname); + nlen = (nlen + 15) & ~0x0F; + + strcpy((char *)(ptr + sizeof(struct bpt_pentry)), + config->entries[i]->larname); + + pentry->nlen = nlen; + } + + ptr += sizeof(struct bpt_pentry); + + if (config->entries[i]->type != BPT_TYPE_CHAIN) + ptr += nlen; + } + + LAR_SetAttrs(&attr, "bayou_payload_table", ALGO_NONE); + + ret = LAR_AppendBuffer(lar, (unsigned char *)buffer, len, &attr); + free(buffer); + return ret; +} + +struct lfile { + char *file; + char *larname; +}; + +int n_lfiles; + +int create_lar_from_config(const char *input, const char *output) +{ + struct config config; + FILE *stream; + struct LAR *lar; + struct LARAttr attr; + int i, j, ret = -1; + struct lfile *lfiles; + + stream = fopen(input, "r"); + + if (stream == NULL) { + warn("E: Couldn't open %s for reading\n", input); + return -1; + } + + memset(&config, 0, sizeof(config)); + + parseconfig(stream, &config); + fclose(stream); + + lar = LAR_Create(output); + + if (lar == NULL) { + warn("E: Couldn't create a new lar file\n"); + return -1; + } + + LAR_SetCompressionFuncs(lar, ALGO_LZMA, do_lzma_compress, NULL); + + lfiles = calloc(sizeof(struct lfile), config.n_entries); + + if (lfiles == NULL) { + warn("E: Couldn't allocate memory: %m\n"); + return -1; + } + + for (i = 0; i < config.n_entries; i++) { + /* Master chain entries don't have files associated with them. */ + if (config.entries[i]->type == BPT_TYPE_CHAIN) + continue; + + if (access(config.entries[i]->file, R_OK)) { + warn("E: Could not find file %s\n", + config.entries[i]->file); + + goto err; + } + + if (config.entries[i]->larname == NULL) { + config.entries[i]->larname = + strdup(basename(config.entries[i]->file)); + + if (config.entries[i]->larname == NULL) { + warn("E: Could not allocate memory for the default name\n"); + goto err; + } + } + + /* + * Add the file to the list of files to add to the LAR - skip + * any duplicates, but be on the lookout for the same LAR name + * attached to a different file. + */ + for (j = 0; j < n_lfiles; j++) { + if (!strcmp(lfiles[j].larname, + config.entries[i]->larname)) { + if (strcmp(lfiles[j].file, + config.entries[i]->file)) { + warn("E: LAR name '%s' has already been used\n", config.entries[i]->larname); + goto err; + } + break; + } + } + + if (j == n_lfiles) { + lfiles[n_lfiles].file = config.entries[i]->file; + lfiles[n_lfiles++].larname = config.entries[i]->larname; + } + } + + /* Add all the files to the LAR. */ + for (i = 0; i < n_lfiles; i++) { + LAR_SetAttrs(&attr, lfiles[i].larname, ALGO_LZMA); + + if (LAR_AppendFile(lar, lfiles[i].file, &attr)) { + warn("E: Could not add %s to the LAR\n", + lfiles[i].file); + goto err; + } + } + + ret = add_bpt_to_lar(lar, &config); + +err: + LAR_Close(lar); + return ret; +} diff --git a/payloads/bayou/util/pbuilder/liblar/Makefile b/payloads/bayou/util/pbuilder/liblar/Makefile new file mode 100644 index 0000000000..23f2feb035 --- /dev/null +++ b/payloads/bayou/util/pbuilder/liblar/Makefile @@ -0,0 +1,31 @@ +## +## This file is part of the bayou project. +## +## Copyright (C) 2008 Advanced Micro Devices, Inc. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## 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 +## + +CC = gcc +LAROBJS = self.o lib.o +CFLAGS = -g -Wall + +liblar.a: $(LAROBJS) + ar rc $@ $(LAROBJS) + +%.o: %.c + $(CC) -c $(CFLAGS) -o $@ $< + +clean: + rm -f liblar.a *.o diff --git a/payloads/bayou/util/pbuilder/liblar/lar.h b/payloads/bayou/util/pbuilder/liblar/lar.h new file mode 100644 index 0000000000..9ef827d0e0 --- /dev/null +++ b/payloads/bayou/util/pbuilder/liblar/lar.h @@ -0,0 +1,95 @@ +/* + * lar - lightweight archiver + * + * Copyright (C) 2006 coresystems GmbH + * (Written by Stefan Reinauer <stepan@coresystems.de> for coresystems GmbH) + * Copyright (C) 2007 Patrick Georgi <patrick@georgi-clan.de> + * + * 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. + * --------------------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdint.h> + +#define MAGIC "LARCHIVE" +#define MAX_PATHLEN 1024 +#define BOOTBLOCK_SIZE 20480 + +#define BOOTBLOCK_NAME "bootblock" +#define BOOTBLOCK_NAME_LEN 16 + +typedef uint64_t u64; +typedef int64_t s64; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint8_t u8; + +/* NOTE -- This and the coreboot lar.h may NOT be in sync. Be careful. */ +struct lar_header { + char magic[8]; + u32 len; + u32 reallen; + u32 checksum; + u32 compchecksum; + /* Filenames are limited to 2^31-1-sizeof(lar_header)-1 bytes. + * "Nobody will ever need more than 640k" */ + u32 offset; + /* Compression: + * 0 = no compression + * 1 = lzma + * 2 = nrv2b + * 3 = zeroes + */ + u32 compression; + u64 entry; + u64 loadaddress; +}; + +enum compalgo { + ALGO_NONE = 0, + ALGO_LZMA = 1, + ALGO_NRV2B = 2, + ALGO_ZEROES = 3, + /* invalid should always be the last entry. */ + ALGO_INVALID +}; diff --git a/payloads/bayou/util/pbuilder/liblar/lib.c b/payloads/bayou/util/pbuilder/liblar/lib.c new file mode 100644 index 0000000000..f0e0a41bd4 --- /dev/null +++ b/payloads/bayou/util/pbuilder/liblar/lib.c @@ -0,0 +1,461 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <arpa/inet.h> + +#include "liblar.h" +#include "self.h" + +static int lar_compress(struct LAR *lar, int algo, char *src, char *dst, + int len) +{ + int ret; + + if (!lar->cfuncs[algo]) + return -1; + + lar->cfuncs[algo] (src, len, dst, &ret); + return ret; +} + +static int lar_decompress(struct LAR *lar, int algo, char *src, char *dst, + int slen, int dlen) +{ + if (!lar->dfuncs[algo]) + return -1; + + lar->dfuncs[algo] (src, slen, dst, dlen); + return dlen; +} + +static struct LARHeader *lar_get_header(struct LAR *lar, const char *filename) +{ + char *buffer; + int offset = 0; + struct LARHeader *lheader = NULL; + struct lar_header *header; + + printf("Getting %s\n", filename); + + buffer = malloc(sizeof(struct lar_header) + MAX_PATHLEN); + + if (buffer == NULL) + return NULL; + + while (1) { + int ret; + + if (lseek(lar->fd, offset, SEEK_SET) == -1) + goto err; + + ret = read(lar->fd, buffer, sizeof(struct lar_header)); + + if (ret <= 0) + goto err; + + header = (struct lar_header *)buffer; + + if (strncmp(header->magic, MAGIC, sizeof(MAGIC))) + goto err; + + ret = read(lar->fd, buffer + sizeof(struct lar_header), + ntohl(header->offset) - sizeof(struct lar_header)); + + if (ret <= 0) + goto err; + + if (!strcmp(buffer + sizeof(struct lar_header), filename)) + break; + + offset += ntohl(header->offset) + + ((ntohl(header->len) + 15) & ~0xF); + } + + lheader = calloc(sizeof(struct LARHeader), 1); + + if (lheader == NULL) + goto err; + + lheader->hoffset = offset; + lheader->offset = offset + ntohl(header->offset); + + lheader->reallen = ntohl(header->reallen); + lheader->len = ntohl(header->len); + + lheader->loadaddress = ntohl(header->loadaddress); + lheader->compression = ntohl(header->compression); + lheader->entry = ntohl(header->entry); + lheader->checksum = ntohl(header->checksum); + +err: + free(buffer); + return lheader; +} + +static int LAR_AppendBlob(struct LAR *lar, unsigned char *buffer, + int len, int rlen, struct LARAttr *attr) +{ + int nlen, nsize, lsize, i; + struct lar_header *header; + u8 *lptr; + u32 csum = 0; + + if (attr == NULL) + return -1; + + nlen = strlen(attr->name) + 1; + + if (nlen > MAX_PATHLEN - 1) + nlen = MAX_PATHLEN - 1; + + nsize = (nlen + 15) & ~0xF; + + lsize = sizeof(struct lar_header) + nsize + len; + lptr = calloc(lsize + 1, 1); + + if (lptr == NULL) + return -1; + + header = (struct lar_header *)lptr; + + memcpy(header->magic, MAGIC, 8); + header->reallen = htonl(rlen); + header->len = htonl(len); + header->offset = htonl(lsize - len); + header->loadaddress = htonl(attr->loadaddr); + header->compression = htonl(attr->compression); + header->entry = htonl(attr->entry); + + strncpy(((char *)header) + sizeof(struct lar_header), attr->name, nlen); + + for (i = 0; i < sizeof(struct lar_header) + nsize; i += 4) + csum += *((u32 *) (lptr + i)); + + for (i = 0; i < len; i += 4) { + /* + * The checksum needs to include the 16 byte padding at + * the end of the data before the next lar header. The + * problem is that the padding isn't going to be in the + * buffer, and if we try to read off the end of the buffer, + * we are just asking for trouble. So account for the + * situation where the datalen is not a multiple of four + * and get a safe value to add into the checksum. + * The rest of the padding will be zero, and can be safely + * ignored here. + */ + if ((len - i) < 4) { + u32 val = 0; + int t; + + for (t = 0; t < (len - i); t++) + val |= *((u8 *) buffer + (i + t)) << (t * 8); + csum += val; + } else + csum += *((u32 *) (buffer + i)); + } + + header->checksum = (u32) (~0 - csum); + + lseek(lar->fd, 0, SEEK_END); + + /* FIXME: Error check here. */ + + write(lar->fd, header, sizeof(struct lar_header) + nsize); + write(lar->fd, buffer, len); + + /* Add in padding to the next 16 byte boundary. */ + if (lsize & 0xF) { + int i; + char null = '\0'; + + for (i = lsize & 0xF; i < 0x10; i++) + write(lar->fd, &null, 1); + } + + return 0; +} + +int LAR_AppendBuffer(struct LAR *lar, unsigned char *buffer, int len, + struct LARAttr *attr) +{ + unsigned char *tbuf; + int rlen, ret = -1; + + if (attr->compression == ALGO_NONE) + return LAR_AppendBlob(lar, buffer, len, len, attr); + + tbuf = malloc(len); + + if (tbuf == NULL) + return -1; + + rlen = lar_compress(lar, attr->compression, (char *)buffer, + (char *)tbuf, len); + + if (rlen > 0) + ret = LAR_AppendBlob(lar, tbuf, rlen, len, attr); + + free(tbuf); + return ret; +} + +int LAR_AppendSelf(struct LAR *lar, const char *filename, struct LARAttr *attr) +{ + unsigned char *buffer; + int len = elf_to_self(filename, &buffer, + lar->cfuncs[attr->compression]); + int ret; + + if (len == -1) + return -1; + + ret = LAR_AppendBlob(lar, buffer, len, len, attr); + free(buffer); + + return ret; +} + +int LAR_AppendFile(struct LAR *lar, const char *filename, struct LARAttr *attr) +{ + int fd; + struct stat s; + char *filep; + int ret; + + if (iself((char *)filename)) + return LAR_AppendSelf(lar, filename, attr); + + fd = open(filename, O_RDONLY); + + if (fd == -1) + return -1; + + if (fstat(fd, &s)) + return -1; + + filep = (char *)mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0); + + if (filep == MAP_FAILED) + return -1; + + ret = LAR_AppendBuffer(lar, (unsigned char *)filep, s.st_size, attr); + + munmap(filep, s.st_size); + return ret; +} + +int LAR_DeleteFile(struct LAR *lar, const char *filename) +{ + struct LARHeader *header = lar_get_header(lar, filename); + int len, ret = -1; + char *filep, *buffer; + + if (header == NULL) + return -1; + + buffer = malloc(4096); + if (buffer == NULL) + return -1; + + len = header->offset + header->len; + + /* First, map the space and zero it out. */ + + filep = (char *)mmap(0, len, PROT_READ, MAP_SHARED, lar->fd, + header->hoffset); + + if (filep == MAP_FAILED) + return -1; + + memset(filep, 0, len); + munmap(filep, len); + + /* Now move the rest of the LAR into place. */ + /* FIXME: This does not account for the bootblock! */ + + int dst = header->hoffset; + int src = header->hoffset + len; + + while (1) { + int l, w; + + if (lseek(lar->fd, src, SEEK_SET)) + goto err; + + l = read(lar->fd, buffer, 8192); + + if (l == -1) + goto err; + if (l == 0) + goto err; + if (lseek(lar->fd, dst, SEEK_SET)) + goto err; + + w = write(lar->fd, buffer, l); + + if (w <= 0) + goto err; + + dst += w; + src += w; + } + + ret = 0; + +err: + free(buffer); + return ret; +} + +void LAR_CloseFile(struct LARFile *file) +{ + if (file != NULL) { + if (file->buffer != NULL) + free(file->buffer); + free(file); + } +} + +struct LARFile *LAR_MapFile(struct LAR *lar, const char *filename) +{ + struct LARFile *file; + struct LARHeader *header = lar_get_header(lar, filename); + char *filep; + int ret; + + if (header == NULL) + return NULL; + + file = calloc(sizeof(struct LARFile), 1); + + if (file == NULL) + return NULL; + + file->len = header->reallen; + file->buffer = calloc(header->reallen, 1); + + if (file->buffer == NULL) + goto err; + + /* + * The offset needs to be a multiple of PAGE_SIZE, so just mmap + * from offset 0, its easier then doing the math. + */ + + filep = mmap(0, header->offset + header->len, + PROT_READ, MAP_SHARED, lar->fd, 0); + + if (filep == MAP_FAILED) { + printf("Map failed: %m\n"); + goto err; + } + + if (header->compression != ALGO_NONE) { + ret = lar_decompress(lar, header->compression, + filep + header->offset, file->buffer, + header->len, header->reallen); + } else { + memcpy(file->buffer, filep + header->offset, header->len); + ret = header->len; + } + + munmap(filep, header->offset + header->len); + + if (ret == header->reallen) + return file; + +err: + if (file->buffer) + free(file->buffer); + + free(file); + return NULL; +} + +int LAR_SetCompressionFuncs(struct LAR *lar, int algo, + LAR_CompFunc cfunc, LAR_DecompFunc dfunc) +{ + + if (algo >= ALGO_INVALID) + return -1; + + lar->cfuncs[algo] = cfunc; + lar->dfuncs[algo] = dfunc; + + return 0; +} + +void LAR_Close(struct LAR *lar) +{ + if (lar != NULL) { + if (lar->fd) + close(lar->fd); + + free(lar); + } +} + +struct LAR *LAR_Open(const char *filename) +{ + struct LAR *lar = calloc(sizeof(struct LAR), 1); + + if (lar == NULL) + return NULL; + + lar->fd = open(filename, O_RDWR); + + if (lar->fd > 0) + return lar; + + free(lar); + return NULL; +} + +struct LAR *LAR_Create(const char *filename) +{ + struct LAR *lar = calloc(sizeof(struct LAR), 1); + + if (lar == NULL) + return NULL; + + lar->fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + + if (lar->fd > 0) + return lar; + + free(lar); + return NULL; +} + +void LAR_SetAttrs(struct LARAttr *attrs, char *name, int algo) +{ + if (attrs == NULL) + return; + + memset(attrs, 0, sizeof(*attrs)); + snprintf(attrs->name, sizeof(attrs->name) - 1, name); + attrs->compression = algo; +} diff --git a/payloads/bayou/util/pbuilder/liblar/liblar.h b/payloads/bayou/util/pbuilder/liblar/liblar.h new file mode 100644 index 0000000000..bd60e1e31b --- /dev/null +++ b/payloads/bayou/util/pbuilder/liblar/liblar.h @@ -0,0 +1,75 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + */ + +#ifndef _LIBLAR_H_ +#define _LIBLAR_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "lar.h" + +typedef void (*LAR_CompFunc) (char *, int, char *, int *); +typedef void (*LAR_DecompFunc) (char *, int, char *, int); + +struct LAR { + int fd; + LAR_CompFunc cfuncs[ALGO_INVALID]; + LAR_DecompFunc dfuncs[ALGO_INVALID]; +}; + +struct LARHeader { + u32 len; + u32 reallen; + u32 checksum; + u32 compression; + u64 loadaddress; + u64 entry; + /* These are the offsets within the file. */ + unsigned int offset; + unsigned int hoffset; +}; + +struct LARAttr { + char name[MAX_PATHLEN]; + u64 loadaddr; + int compression; + u64 entry; +}; + +struct LARFile { + int len; + char *buffer; +}; + +int LAR_AppendBuffer(struct LAR *lar, unsigned char *buffer, int len, + struct LARAttr *attr); +int LAR_AppendSelf(struct LAR *lar, const char *filename, struct LARAttr *attr); +int LAR_AppendFile(struct LAR *lar, const char *filename, struct LARAttr *attr); +int LAR_DeleteFile(struct LAR *lar, const char *filename); +void LAR_CloseFile(struct LARFile *file); +struct LARFile *LAR_MapFile(struct LAR *lar, const char *filename); +int LAR_SetCompressionFuncs(struct LAR *lar, int algo, + LAR_CompFunc cfunc, LAR_DecompFunc dfunc); +void LAR_Close(struct LAR *lar); +struct LAR *LAR_Open(const char *filename); +struct LAR *LAR_Create(const char *filename); +void LAR_SetAttrs(struct LARAttr *attrs, char *name, int algo); + +#endif diff --git a/payloads/bayou/util/pbuilder/liblar/self.c b/payloads/bayou/util/pbuilder/liblar/self.c new file mode 100644 index 0000000000..c7fff3d97f --- /dev/null +++ b/payloads/bayou/util/pbuilder/liblar/self.c @@ -0,0 +1,206 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * Includes code from util/lar from coreboot-v3 + * + * Copyright (C) 2006-2007 coresystems GmbH + * Copyright (C) 2007 Patrick Georgi <patrick@georgi-clan.de> + * Copyright (C) 2007 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <elf.h> +#include <sys/mman.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdint.h> + +typedef uint64_t u64; +typedef int64_t s64; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint8_t u8; + +#include "self.h" + +int elf_to_self(const char *filename, unsigned char **buffer, + void (*compress) (char *, int, char *, int *)) +{ + struct stat s; + Elf32_Phdr *phdr; + Elf32_Ehdr *ehdr; + Elf32_Shdr *shdr; + void *filep; + char *header, *strtab; + unsigned char *sptr; + int headers, segments = 1, isize = 0, osize = 0, doffset = 0, fd, i; + struct self_segment *segs; + + if (stat(filename, &s)) { + printf("Unable to stat %s: %m\n", filename); + return -1; + } + + fd = open(filename, O_RDONLY); + + if (fd == -1) { + printf("Unable to open %s: %m\n", filename); + return -1; + } + + /* Map the file so that we can easily parse it. */ + filep = (void *) + mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0); + + if (filep == MAP_FAILED) { + close(fd); + return -1; + } + + ehdr = (Elf32_Ehdr *) filep; + headers = ehdr->e_phnum; + header = (char *)ehdr; + + phdr = (Elf32_Phdr *) & (header[ehdr->e_phoff]); + shdr = (Elf32_Shdr *) & (header[ehdr->e_shoff]); + + strtab = &header[shdr[ehdr->e_shstrndx].sh_offset]; + + /* Count number of headers - look for the .notes.pinfo section. */ + for (i = 0; i < ehdr->e_shnum; i++) { + char *name; + + if (i == ehdr->e_shstrndx) + continue; + + if (shdr[i].sh_size == 0) + continue; + + name = (char *)(strtab + shdr[i].sh_name); + + if (!strcmp(name, ".note.pinfo")) + segments++; + } + + /* + * Now, regular headers - we only care about PT_LOAD headers, + * because thats what we're actually going to load. + */ + for (i = 0; i < headers; i++) { + if (phdr[i].p_type != PT_LOAD) + continue; + + /* Empty segments are never interesting. */ + if (phdr[i].p_memsz == 0) + continue; + + isize += phdr[i].p_filesz; + segments++; + } + + /* Allocate a block of memory to store the SELF in. */ + sptr = calloc((segments * sizeof(struct self_segment)) + isize, 1); + doffset = (segments * sizeof(struct self_segment)); + + if (sptr == NULL) + goto err; + + segs = (struct self_segment *)sptr; + segments = 0; + + for (i = 0; i < ehdr->e_shnum; i++) { + char *name; + + if (i == ehdr->e_shstrndx) + continue; + + if (shdr[i].sh_size == 0) + continue; + + name = (char *)(strtab + shdr[i].sh_name); + + if (!strcmp(name, ".note.pinfo")) { + segs[segments].type = SELF_TYPE_PARAMS; + segs[segments].load_addr = 0; + segs[segments].len = (u32) shdr[i].sh_size; + segs[segments].offset = doffset; + + memcpy((unsigned long *)(sptr + doffset), + &header[shdr[i].sh_offset], shdr[i].sh_size); + + doffset += segs[segments].len; + osize += segs[segments].len; + + segments++; + } + } + + for (i = 0; i < headers; i++) { + if (phdr[i].p_type != PT_LOAD) + continue; + + if (phdr[i].p_memsz == 0) + continue; + + segs[segments].type = SELF_TYPE_DATA; + segs[segments].load_addr = (u64) phdr[i].p_paddr; + segs[segments].mem_len = (u32) phdr[i].p_memsz; + segs[segments].offset = doffset; + + compress((char *)&header[phdr[i].p_offset], + phdr[i].p_filesz, + (char *)(sptr + doffset), (int *)&segs[segments].len); + + doffset += segs[segments].len; + osize += segs[segments].len; + + segments++; + } + + segs[segments].type = SELF_TYPE_ENTRY; + segs[segments++].load_addr = (unsigned long long)ehdr->e_entry; + + *buffer = sptr; + + munmap(filep, s.st_size); + close(fd); + + return (segments * sizeof(struct self_segment)) + osize; + +err: + munmap(filep, s.st_size); + close(fd); + + return -1; +} + +int iself(char *filename) +{ + Elf32_Ehdr ehdr; + int fd = open(filename, O_RDONLY); + int ret = 0; + + if (fd == -1) + return 0; + + if (read(fd, &ehdr, sizeof(ehdr)) == sizeof(ehdr)) + ret = !memcmp(ehdr.e_ident, ELFMAG, 4); + + close(fd); + + return ret; +} diff --git a/payloads/bayou/util/pbuilder/liblar/self.h b/payloads/bayou/util/pbuilder/liblar/self.h new file mode 100644 index 0000000000..0667373d3d --- /dev/null +++ b/payloads/bayou/util/pbuilder/liblar/self.h @@ -0,0 +1,42 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + */ + +#ifndef SELF_H_ +#define SELF_H_ + +struct self_segment { + u32 type; + u32 offset; + u64 load_addr; + u32 len; + u32 mem_len; +}; + +#define SELF_TYPE_CODE 0x45444F43 +#define SELF_TYPE_DATA 0x41544144 +#define SELF_TYPE_BSS 0x20535342 +#define SELF_TYPE_PARAMS 0x41524150 +#define SELF_TYPE_ENTRY 0x52544E45 + +int elf_to_self(const char *filename, unsigned char **buffer, + void (*compress) (char *, int, char *, int *)); + +int iself(char *filename); + +#endif diff --git a/payloads/bayou/util/pbuilder/main.c b/payloads/bayou/util/pbuilder/main.c new file mode 100644 index 0000000000..f5ce374b16 --- /dev/null +++ b/payloads/bayou/util/pbuilder/main.c @@ -0,0 +1,82 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + */ + +#include <stdio.h> +#include <string.h> +#include <getopt.h> +#include "pbuilder.h" + +static void usage(void) +{ + printf("./pbuilder [-c config] [create|show] [LAR]\n"); +} + +int main(int argc, char **argv) +{ + char *config = NULL; + + while (1) { + signed ch = getopt(argc, argv, "c:"); + if (ch == -1) + break; + + switch (ch) { + case 'c': + config = optarg; + break; + default: + usage(); + return -1; + } + } + + if (optind >= argc) { + usage(); + return 0; + } + + if (!strcmp(argv[optind], "create")) { + if (config == NULL) { + warn("E: No config was provided\n"); + usage(); + return -1; + } + + if (optind + 1 >= argc) { + warn("E: No LAR name was given\n"); + usage(); + return -1; + } + + create_lar_from_config((const char *)config, + (const char *)argv[optind + 1]); + } else if (!strcmp(argv[optind], "show")) { + if (optind + 1 >= argc) { + warn("E: No LAR name was given\n"); + usage(); + return -1; + } + pbuilder_show_lar((const char *)argv[optind + 1]); + } else { + usage(); + return -1; + } + + return 0; +} diff --git a/payloads/bayou/util/pbuilder/pbuilder.h b/payloads/bayou/util/pbuilder/pbuilder.h new file mode 100644 index 0000000000..80902bc78f --- /dev/null +++ b/payloads/bayou/util/pbuilder/pbuilder.h @@ -0,0 +1,77 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + */ + +#include <stdio.h> + +#ifndef PBUILDER_H_ +#define PBUILDER_H_ + +#include <stdint.h> +#include <stdio.h> + +#define warn(fmt, args...) fprintf(stderr, fmt, ##args) +#define die(fmt, args...) \ + do { fprintf(stderr, fmt, ##args); exit(-1); } \ + while(0) + +struct pentry { + uint8_t index; + uint8_t parent; + uint8_t type; + uint8_t flags; + uint8_t title[64]; + char *file; + char *larname; +}; + +struct config { + int timeout; + int n_entries; + struct pentry **entries; +}; + +struct bpt_config { + uint32_t id; + uint8_t timeout; + uint8_t entries; + uint8_t padding[10]; +}; + +struct bpt_pentry { + uint8_t index; + uint8_t parent; + uint8_t type; + uint8_t flags; + uint8_t title[64]; + uint8_t nlen; +}; + +#define BPT_ID 0x30545042 +#define BPT_TYPE_CHOOSER 0x01 +#define BPT_TYPE_CHAIN 0x02 +#define BPT_TYPE_SUBCHAIN 0x03 + +#define BPT_FLAG_DEFAULT 0x01 +#define BPT_FLAG_NOSHOW 0x02 + +int pbuilder_show_lar(const char *input); +int create_lar_from_config(const char *input, const char *output); +void parseconfig(FILE * stream, struct config *config); + +#endif diff --git a/payloads/bayou/util/pbuilder/show.c b/payloads/bayou/util/pbuilder/show.c new file mode 100644 index 0000000000..9cb0598c50 --- /dev/null +++ b/payloads/bayou/util/pbuilder/show.c @@ -0,0 +1,131 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 + */ + +#include <stdio.h> +#include "liblar.h" +#include "pbuilder.h" + +void show_subchain(struct bpt_config *cfg, char *fptr, int index) +{ + int i; + char *ptr = fptr + sizeof(struct bpt_config); + + for (i = 0; i < cfg->entries; i++) { + struct bpt_pentry *entry = (struct bpt_pentry *)ptr; + + if (entry->parent == index) + printf(" + %.64s\n", + ptr + sizeof(struct bpt_pentry)); + + ptr += (sizeof(struct bpt_pentry) + entry->nlen); + } +} + +int show_payloads(struct bpt_config *cfg, char *fptr) +{ + int i; + char *ptr = fptr + sizeof(struct bpt_config); + + for (i = 0; i < cfg->entries; i++) { + struct bpt_pentry *entry = (struct bpt_pentry *)ptr; + + if (entry->parent != 0) { + ptr += (sizeof(struct bpt_pentry) + entry->nlen); + continue; + } + + printf(" "); + + if (entry->flags & BPT_FLAG_DEFAULT) + printf("D"); + else + printf(" "); + + if (entry->flags & BPT_FLAG_NOSHOW) + printf("N"); + else + printf(" "); + + switch (entry->type) { + case BPT_TYPE_CHOOSER: + printf(" MENU "); + break; + case BPT_TYPE_CHAIN: + printf(" CHAIN"); + break; + } + + if (entry->title[0] != 0) + printf(" %.64s\n", entry->title); + else + printf(" - no title -\n"); + + if (entry->type == BPT_TYPE_CHOOSER) + printf(" %.60s\n", + ptr + sizeof(struct bpt_pentry)); + else + show_subchain(cfg, fptr, entry->index); + + ptr += (sizeof(struct bpt_pentry) + entry->nlen); + } + + return 0; +} + +int pbuilder_show_lar(const char *input) +{ + int ret = -1; + struct LAR *lar; + struct bpt_config *cfg; + struct LARFile *lfile; + + lar = LAR_Open(input); + + if (lar == NULL) { + warn("E: Couldn't open LAR %s\n", input); + return -1; + } + + lfile = LAR_MapFile(lar, "bayou_payload_table"); + + if (lfile == NULL) { + warn("E: Couldn't find the bayou payload table. Nothing to do.\n"); + goto err; + } + + cfg = (struct bpt_config *)lfile->buffer; + + if (cfg->id != BPT_ID) { + warn("E: BPT ID does not match\n"); + goto err; + } + + printf("Bayou Payload Configuration\n"); + printf("Timeout = %d seconds\n", cfg->timeout); + + printf("Payload List:\n"); + show_payloads(cfg, lfile->buffer); + ret = 0; + +err: + LAR_CloseFile(lfile); + LAR_Close(lar); + + return ret; +} |