brcm63xx: add working lzma-loader and use it for initramfs

Add a working lzma loader and use it for generating initramfs kernels
to allow easily netbooting elf kernels on devices with a 4 MiB CFE
size limit.

Based on ar71xx's lzma-loader.

Signed-off-by: Jonas Gorski <jogo@openwrt.org>

SVN-Revision: 41940
This commit is contained in:
Jonas Gorski 2014-08-01 21:56:31 +00:00
parent 21845cb45d
commit 701e2a38fe
23 changed files with 1580 additions and 925 deletions

View file

@ -143,9 +143,25 @@ define Build/Clean
$(MAKE) -C lzma-loader clean $(MAKE) -C lzma-loader clean
endef endef
define Image/Prepare define Image/PrepareLoader
# Standard LZMA kernel # Standard LZMA kernel
cat $(KDIR)/vmlinux | $(STAGING_DIR_HOST)/bin/lzma e -si -so -eos -lc1 -lp2 -pb2 > $(KDIR)/vmlinux.lzma $(STAGING_DIR_HOST)/bin/lzma e -d22 -fb64 -a1 $(KDIR)/vmlinux$(1) $(KDIR)/vmlinux$(1).lzma
# Build the LZMA loader
rm -rf $(KDIR)/lzma-loader
$(MAKE) -C lzma-loader \
$(LOADER_MAKEOPTS) \
BUILD_DIR="$(KDIR)" \
TARGET_DIR="$(BIN_DIR)" \
LOADER_DATA="$(KDIR)/vmlinux$(1).lzma" \
LOADER=$(IMG_PREFIX)-loader$(1).elf \
LZMA_TEXT_START=0x80a00000 \
compile loader.elf
rm -f $(KDIR)/vmlinux$(1).lzma
endef
define Image/Prepare
# CFE is a LZMA nazi! It took me hours to find out the parameters! # CFE is a LZMA nazi! It took me hours to find out the parameters!
# Also I think lzma has a bug cause it generates different output depending on # Also I think lzma has a bug cause it generates different output depending on
@ -158,14 +174,9 @@ define Image/Prepare
dd if=$(KDIR)/vmlinux.lzma.tmp of=$(KDIR)/vmlinux.lzma.cfe ibs=13 obs=5 skip=1 seek=1 conv=notrunc dd if=$(KDIR)/vmlinux.lzma.tmp of=$(KDIR)/vmlinux.lzma.cfe ibs=13 obs=5 skip=1 seek=1 conv=notrunc
rm -f $(KDIR)/vmlinux.lzma.tmp rm -f $(KDIR)/vmlinux.lzma.tmp
# Build the LZMA loader ifeq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),y)
rm -f $(KDIR)/loader.gz $(call Image/PrepareLoader,-initramfs)
$(MAKE) -C lzma-loader \ endif
BUILD_DIR="$(KDIR)" \
TARGET="$(KDIR)" \
clean install
echo -ne "\\x00" >> $(KDIR)/loader.gz
rm -f $(KDIR)/fs_mark rm -f $(KDIR)/fs_mark
touch $(KDIR)/fs_mark touch $(KDIR)/fs_mark
$(call prepare_generic_squashfs,$(KDIR)/fs_mark) $(call prepare_generic_squashfs,$(KDIR)/fs_mark)

View file

@ -1,5 +1,6 @@
# #
# Copyright (C) 2006 OpenWrt.org # Copyright (C) 2011 OpenWrt.org
# Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
# #
# This is free software, licensed under the GNU General Public License v2. # This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information. # See /LICENSE for more information.
@ -7,27 +8,55 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
LZMA_TEXT_START := 0x80a00000
LOADER := loader.bin
LOADER_NAME := $(basename $(notdir $(LOADER)))
LOADER_DATA :=
TARGET_DIR :=
FLASH_OFFS :=
FLASH_MAX :=
ifeq ($(TARGET_DIR),)
TARGET_DIR := $(KDIR)
endif
LOADER_BIN := $(TARGET_DIR)/$(LOADER_NAME).bin
LOADER_GZ := $(TARGET_DIR)/$(LOADER_NAME).gz
LOADER_ELF := $(TARGET_DIR)/$(LOADER_NAME).elf
PKG_NAME := lzma-loader PKG_NAME := lzma-loader
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) PKG_BUILD_DIR := $(KDIR)/$(PKG_NAME)
.PHONY : loader-compile loader.bin loader.elf loader.gz
$(PKG_BUILD_DIR)/.prepared: $(PKG_BUILD_DIR)/.prepared:
mkdir $(PKG_BUILD_DIR) mkdir $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/ $(CP) ./src/* $(PKG_BUILD_DIR)/
touch $@ touch $@
$(PKG_BUILD_DIR)/loader.gz: $(PKG_BUILD_DIR)/.prepared loader-compile: $(PKG_BUILD_DIR)/.prepared
$(MAKE) -C $(PKG_BUILD_DIR) CC="$(TARGET_CC)" \ $(MAKE) -C $(PKG_BUILD_DIR) CROSS_COMPILE="$(TARGET_CROSS)" \
LD="$(TARGET_CROSS)ld" CROSS_COMPILE="$(TARGET_CROSS)" LZMA_TEXT_START=$(LZMA_TEXT_START) \
LOADER_DATA=$(LOADER_DATA) \
FLASH_OFFS=$(FLASH_OFFS) \
FLASH_MAX=$(FLASH_MAX) \
clean all
download: loader.gz: $(PKG_BUILD_DIR)/loader.bin
gzip -nc9 $< > $(LOADER_GZ)
loader.elf: $(PKG_BUILD_DIR)/loader.elf
$(CP) $< $(LOADER_ELF)
loader.bin: $(PKG_BUILD_DIR)/loader.bin
$(CP) $< $(LOADER_BIN)
download:
prepare: $(PKG_BUILD_DIR)/.prepared prepare: $(PKG_BUILD_DIR)/.prepared
compile: $(PKG_BUILD_DIR)/loader.gz compile: loader-compile
install:
ifneq ($(TARGET),) install:
install: compile
$(CP) $(PKG_BUILD_DIR)/loader.gz $(PKG_BUILD_DIR)/loader.elf $(TARGET)/
endif
clean: clean:
rm -rf $(PKG_BUILD_DIR) rm -rf $(PKG_BUILD_DIR)

View file

@ -1,8 +1,8 @@
/* /*
LzmaDecode.c LzmaDecode.c
LZMA Decoder LZMA Decoder (optimized for Speed version)
LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25) LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
http://www.7-zip.org/ http://www.7-zip.org/
LZMA SDK is licensed under two licenses: LZMA SDK is licensed under two licenses:
@ -12,19 +12,15 @@
follow rules of that license. follow rules of that license.
SPECIAL EXCEPTION: SPECIAL EXCEPTION:
Igor Pavlov, as the author of this code, expressly permits you to Igor Pavlov, as the author of this Code, expressly permits you to
statically or dynamically link your code (or bind by name) to the statically or dynamically link your Code (or bind by name) to the
interfaces of this file without subjecting your linked code to the interfaces of this file without subjecting your linked Code to the
terms of the CPL or GNU LGPL. Any modifications or additions terms of the CPL or GNU LGPL. Any modifications or additions
to this file, however, are subject to the LGPL or CPL terms. to this file, however, are subject to the LGPL or CPL terms.
*/ */
#include "LzmaDecode.h" #include "LzmaDecode.h"
#ifndef Byte
#define Byte unsigned char
#endif
#define kNumTopBits 24 #define kNumTopBits 24
#define kTopValue ((UInt32)1 << kNumTopBits) #define kTopValue ((UInt32)1 << kNumTopBits)
@ -32,242 +28,44 @@
#define kBitModelTotal (1 << kNumBitModelTotalBits) #define kBitModelTotal (1 << kNumBitModelTotalBits)
#define kNumMoveBits 5 #define kNumMoveBits 5
typedef struct _CRangeDecoder #define RC_READ_BYTE (*Buffer++)
{
Byte *Buffer;
Byte *BufferLim;
UInt32 Range;
UInt32 Code;
#ifdef _LZMA_IN_CB
ILzmaInCallback *InCallback;
int Result;
#endif
int ExtraBytes;
} CRangeDecoder;
Byte RangeDecoderReadByte(CRangeDecoder *rd) #define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
{ { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
if (rd->Buffer == rd->BufferLim)
{
#ifdef _LZMA_IN_CB
UInt32 size;
rd->Result = rd->InCallback->Read(rd->InCallback, &rd->Buffer, &size);
rd->BufferLim = rd->Buffer + size;
if (size == 0)
#endif
{
rd->ExtraBytes = 1;
return 0xFF;
}
}
return (*rd->Buffer++);
}
/* #define ReadByte (*rd->Buffer++) */ #ifdef _LZMA_IN_CB
#define ReadByte (RangeDecoderReadByte(rd))
void RangeDecoderInit(CRangeDecoder *rd, #define RC_TEST { if (Buffer == BufferLim) \
#ifdef _LZMA_IN_CB { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \
ILzmaInCallback *inCallback BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }}
#else
Byte *stream, UInt32 bufferSize
#endif
)
{
int i;
#ifdef _LZMA_IN_CB
rd->InCallback = inCallback;
rd->Buffer = rd->BufferLim = 0;
#else
rd->Buffer = stream;
rd->BufferLim = stream + bufferSize;
#endif
rd->ExtraBytes = 0;
rd->Code = 0;
rd->Range = (0xFFFFFFFF);
for(i = 0; i < 5; i++)
rd->Code = (rd->Code << 8) | ReadByte;
}
#define RC_INIT_VAR UInt32 range = rd->Range; UInt32 code = rd->Code; #define RC_INIT Buffer = BufferLim = 0; RC_INIT2
#define RC_FLUSH_VAR rd->Range = range; rd->Code = code;
#define RC_NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | ReadByte; }
UInt32 RangeDecoderDecodeDirectBits(CRangeDecoder *rd, int numTotalBits) #else
{
RC_INIT_VAR
UInt32 result = 0;
int i;
for (i = numTotalBits; i > 0; i--)
{
/* UInt32 t; */
range >>= 1;
result <<= 1; #define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
if (code >= range)
{
code -= range;
result |= 1;
}
/*
t = (code - range) >> 31;
t &= 1;
code -= range & (t - 1);
result = (result + result) | (1 - t);
*/
RC_NORMALIZE
}
RC_FLUSH_VAR
return result;
}
int RangeDecoderBitDecode(CProb *prob, CRangeDecoder *rd) #define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
{
UInt32 bound = (rd->Range >> kNumBitModelTotalBits) * *prob; #endif
if (rd->Code < bound)
{
rd->Range = bound;
*prob += (kBitModelTotal - *prob) >> kNumMoveBits;
if (rd->Range < kTopValue)
{
rd->Code = (rd->Code << 8) | ReadByte;
rd->Range <<= 8;
}
return 0;
}
else
{
rd->Range -= bound;
rd->Code -= bound;
*prob -= (*prob) >> kNumMoveBits;
if (rd->Range < kTopValue)
{
rd->Code = (rd->Code << 8) | ReadByte;
rd->Range <<= 8;
}
return 1;
}
}
#define RC_GET_BIT2(prob, mi, A0, A1) \ #define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
UInt32 bound = (range >> kNumBitModelTotalBits) * *prob; \
if (code < bound) \
{ A0; range = bound; *prob += (kBitModelTotal - *prob) >> kNumMoveBits; mi <<= 1; } \
else \
{ A1; range -= bound; code -= bound; *prob -= (*prob) >> kNumMoveBits; mi = (mi + mi) + 1; } \
RC_NORMALIZE
#define RC_GET_BIT(prob, mi) RC_GET_BIT2(prob, mi, ; , ;) #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;
int RangeDecoderBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd) #define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
{ { UpdateBit0(p); mi <<= 1; A0; } else \
int mi = 1; { UpdateBit1(p); mi = (mi + mi) + 1; A1; }
int i;
#ifdef _LZMA_LOC_OPT #define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)
RC_INIT_VAR
#endif
for(i = numLevels; i > 0; i--)
{
#ifdef _LZMA_LOC_OPT
CProb *prob = probs + mi;
RC_GET_BIT(prob, mi)
#else
mi = (mi + mi) + RangeDecoderBitDecode(probs + mi, rd);
#endif
}
#ifdef _LZMA_LOC_OPT
RC_FLUSH_VAR
#endif
return mi - (1 << numLevels);
}
int RangeDecoderReverseBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd) #define RangeDecoderBitTreeDecode(probs, numLevels, res) \
{ { int i = numLevels; res = 1; \
int mi = 1; do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \
int i; res -= (1 << numLevels); }
int symbol = 0;
#ifdef _LZMA_LOC_OPT
RC_INIT_VAR
#endif
for(i = 0; i < numLevels; i++)
{
#ifdef _LZMA_LOC_OPT
CProb *prob = probs + mi;
RC_GET_BIT2(prob, mi, ; , symbol |= (1 << i))
#else
int bit = RangeDecoderBitDecode(probs + mi, rd);
mi = mi + mi + bit;
symbol |= (bit << i);
#endif
}
#ifdef _LZMA_LOC_OPT
RC_FLUSH_VAR
#endif
return symbol;
}
Byte LzmaLiteralDecode(CProb *probs, CRangeDecoder *rd)
{
int symbol = 1;
#ifdef _LZMA_LOC_OPT
RC_INIT_VAR
#endif
do
{
#ifdef _LZMA_LOC_OPT
CProb *prob = probs + symbol;
RC_GET_BIT(prob, symbol)
#else
symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
#endif
}
while (symbol < 0x100);
#ifdef _LZMA_LOC_OPT
RC_FLUSH_VAR
#endif
return symbol;
}
Byte LzmaLiteralDecodeMatch(CProb *probs, CRangeDecoder *rd, Byte matchByte)
{
int symbol = 1;
#ifdef _LZMA_LOC_OPT
RC_INIT_VAR
#endif
do
{
int bit;
int matchBit = (matchByte >> 7) & 1;
matchByte <<= 1;
#ifdef _LZMA_LOC_OPT
{
CProb *prob = probs + ((1 + matchBit) << 8) + symbol;
RC_GET_BIT2(prob, symbol, bit = 0, bit = 1)
}
#else
bit = RangeDecoderBitDecode(probs + ((1 + matchBit) << 8) + symbol, rd);
symbol = (symbol << 1) | bit;
#endif
if (matchBit != bit)
{
while (symbol < 0x100)
{
#ifdef _LZMA_LOC_OPT
CProb *prob = probs + symbol;
RC_GET_BIT(prob, symbol)
#else
symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
#endif
}
break;
}
}
while (symbol < 0x100);
#ifdef _LZMA_LOC_OPT
RC_FLUSH_VAR
#endif
return symbol;
}
#define kNumPosBitsMax 4 #define kNumPosBitsMax 4
#define kNumPosStatesMax (1 << kNumPosBitsMax) #define kNumPosStatesMax (1 << kNumPosBitsMax)
@ -286,19 +84,9 @@ Byte LzmaLiteralDecodeMatch(CProb *probs, CRangeDecoder *rd, Byte matchByte)
#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) #define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
#define kNumLenProbs (LenHigh + kLenNumHighSymbols) #define kNumLenProbs (LenHigh + kLenNumHighSymbols)
int LzmaLenDecode(CProb *p, CRangeDecoder *rd, int posState)
{
if(RangeDecoderBitDecode(p + LenChoice, rd) == 0)
return RangeDecoderBitTreeDecode(p + LenLow +
(posState << kLenNumLowBits), kLenNumLowBits, rd);
if(RangeDecoderBitDecode(p + LenChoice2, rd) == 0)
return kLenNumLowSymbols + RangeDecoderBitTreeDecode(p + LenMid +
(posState << kLenNumMidBits), kLenNumMidBits, rd);
return kLenNumLowSymbols + kLenNumMidSymbols +
RangeDecoderBitTreeDecode(p + LenHigh, kLenNumHighBits, rd);
}
#define kNumStates 12 #define kNumStates 12
#define kNumLitStates 7
#define kStartPosModelIndex 4 #define kStartPosModelIndex 4
#define kEndPosModelIndex 14 #define kEndPosModelIndex 14
@ -329,94 +117,115 @@ int LzmaLenDecode(CProb *p, CRangeDecoder *rd, int posState)
StopCompilingDueBUG StopCompilingDueBUG
#endif #endif
#ifdef _LZMA_OUT_READ int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
typedef struct _LzmaVarState
{ {
CRangeDecoder RangeDecoder; unsigned char prop0;
Byte *Dictionary; if (size < LZMA_PROPERTIES_SIZE)
UInt32 DictionarySize; return LZMA_RESULT_DATA_ERROR;
UInt32 DictionaryPos; prop0 = propsData[0];
UInt32 GlobalPos; if (prop0 >= (9 * 5 * 5))
UInt32 Reps[4]; return LZMA_RESULT_DATA_ERROR;
int lc; {
int lp; for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
int pb; for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
int State; propsRes->lc = prop0;
int PreviousIsMatch; /*
int RemainLen; unsigned char remainder = (unsigned char)(prop0 / 9);
} LzmaVarState; propsRes->lc = prop0 % 9;
propsRes->pb = remainder / 5;
propsRes->lp = remainder % 5;
*/
}
int LzmaDecoderInit( #ifdef _LZMA_OUT_READ
unsigned char *buffer, UInt32 bufferSize, {
int lc, int lp, int pb, int i;
unsigned char *dictionary, UInt32 dictionarySize, propsRes->DictionarySize = 0;
#ifdef _LZMA_IN_CB for (i = 0; i < 4; i++)
ILzmaInCallback *inCallback propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8);
#else if (propsRes->DictionarySize == 0)
unsigned char *inStream, UInt32 inSize propsRes->DictionarySize = 1;
#endif }
) #endif
{
LzmaVarState *vs = (LzmaVarState *)buffer;
CProb *p = (CProb *)(buffer + sizeof(LzmaVarState));
UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp));
UInt32 i;
if (bufferSize < numProbs * sizeof(CProb) + sizeof(LzmaVarState))
return LZMA_RESULT_NOT_ENOUGH_MEM;
vs->Dictionary = dictionary;
vs->DictionarySize = dictionarySize;
vs->DictionaryPos = 0;
vs->GlobalPos = 0;
vs->Reps[0] = vs->Reps[1] = vs->Reps[2] = vs->Reps[3] = 1;
vs->lc = lc;
vs->lp = lp;
vs->pb = pb;
vs->State = 0;
vs->PreviousIsMatch = 0;
vs->RemainLen = 0;
dictionary[dictionarySize - 1] = 0;
for (i = 0; i < numProbs; i++)
p[i] = kBitModelTotal >> 1;
RangeDecoderInit(&vs->RangeDecoder,
#ifdef _LZMA_IN_CB
inCallback
#else
inStream, inSize
#endif
);
return LZMA_RESULT_OK; return LZMA_RESULT_OK;
} }
int LzmaDecode(unsigned char *buffer, #define kLzmaStreamWasFinishedId (-1)
unsigned char *outStream, UInt32 outSize,
UInt32 *outSizeProcessed) int LzmaDecode(CLzmaDecoderState *vs,
#ifdef _LZMA_IN_CB
ILzmaInCallback *InCallback,
#else
const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
#endif
unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
{ {
LzmaVarState *vs = (LzmaVarState *)buffer; CProb *p = vs->Probs;
CProb *p = (CProb *)(buffer + sizeof(LzmaVarState)); SizeT nowPos = 0;
CRangeDecoder rd = vs->RangeDecoder; Byte previousByte = 0;
UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
int lc = vs->Properties.lc;
#ifdef _LZMA_OUT_READ
UInt32 Range = vs->Range;
UInt32 Code = vs->Code;
#ifdef _LZMA_IN_CB
const Byte *Buffer = vs->Buffer;
const Byte *BufferLim = vs->BufferLim;
#else
const Byte *Buffer = inStream;
const Byte *BufferLim = inStream + inSize;
#endif
int state = vs->State; int state = vs->State;
int previousIsMatch = vs->PreviousIsMatch;
Byte previousByte;
UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3]; UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
UInt32 nowPos = 0;
UInt32 posStateMask = (1 << (vs->pb)) - 1;
UInt32 literalPosMask = (1 << (vs->lp)) - 1;
int lc = vs->lc;
int len = vs->RemainLen; int len = vs->RemainLen;
UInt32 globalPos = vs->GlobalPos; UInt32 globalPos = vs->GlobalPos;
UInt32 distanceLimit = vs->DistanceLimit;
Byte *dictionary = vs->Dictionary; Byte *dictionary = vs->Dictionary;
UInt32 dictionarySize = vs->DictionarySize; UInt32 dictionarySize = vs->Properties.DictionarySize;
UInt32 dictionaryPos = vs->DictionaryPos; UInt32 dictionaryPos = vs->DictionaryPos;
if (len == -1) Byte tempDictionary[4];
{
*outSizeProcessed = 0; #ifndef _LZMA_IN_CB
*inSizeProcessed = 0;
#endif
*outSizeProcessed = 0;
if (len == kLzmaStreamWasFinishedId)
return LZMA_RESULT_OK; return LZMA_RESULT_OK;
if (dictionarySize == 0)
{
dictionary = tempDictionary;
dictionarySize = 1;
tempDictionary[0] = vs->TempDictionary[0];
} }
while(len > 0 && nowPos < outSize) if (len == kLzmaNeedInitId)
{
{
UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
UInt32 i;
for (i = 0; i < numProbs; i++)
p[i] = kBitModelTotal >> 1;
rep0 = rep1 = rep2 = rep3 = 1;
state = 0;
globalPos = 0;
distanceLimit = 0;
dictionaryPos = 0;
dictionary[dictionarySize - 1] = 0;
#ifdef _LZMA_IN_CB
RC_INIT;
#else
RC_INIT(inStream, inSize);
#endif
}
len = 0;
}
while(len != 0 && nowPos < outSize)
{ {
UInt32 pos = dictionaryPos - rep0; UInt32 pos = dictionaryPos - rep0;
if (pos >= dictionarySize) if (pos >= dictionarySize)
@ -430,47 +239,41 @@ int LzmaDecode(unsigned char *buffer,
previousByte = dictionary[dictionarySize - 1]; previousByte = dictionary[dictionarySize - 1];
else else
previousByte = dictionary[dictionaryPos - 1]; previousByte = dictionary[dictionaryPos - 1];
#else
int LzmaDecode( #else /* if !_LZMA_OUT_READ */
Byte *buffer, UInt32 bufferSize,
int lc, int lp, int pb,
#ifdef _LZMA_IN_CB
ILzmaInCallback *inCallback,
#else
unsigned char *inStream, UInt32 inSize,
#endif
unsigned char *outStream, UInt32 outSize,
UInt32 *outSizeProcessed)
{
UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp));
CProb *p = (CProb *)buffer;
CRangeDecoder rd;
UInt32 i;
int state = 0; int state = 0;
int previousIsMatch = 0;
Byte previousByte = 0;
UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
UInt32 nowPos = 0;
UInt32 posStateMask = (1 << pb) - 1;
UInt32 literalPosMask = (1 << lp) - 1;
int len = 0; int len = 0;
if (bufferSize < numProbs * sizeof(CProb)) const Byte *Buffer;
return LZMA_RESULT_NOT_ENOUGH_MEM; const Byte *BufferLim;
for (i = 0; i < numProbs; i++) UInt32 Range;
p[i] = kBitModelTotal >> 1; UInt32 Code;
RangeDecoderInit(&rd,
#ifdef _LZMA_IN_CB
inCallback
#else
inStream, inSize
#endif
);
#endif
#ifndef _LZMA_IN_CB
*inSizeProcessed = 0;
#endif
*outSizeProcessed = 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;
}
#ifdef _LZMA_IN_CB
RC_INIT;
#else
RC_INIT(inStream, inSize);
#endif
#endif /* _LZMA_OUT_READ */
while(nowPos < outSize) while(nowPos < outSize)
{ {
CProb *prob;
UInt32 bound;
int posState = (int)( int posState = (int)(
(nowPos (nowPos
#ifdef _LZMA_OUT_READ #ifdef _LZMA_OUT_READ
@ -478,15 +281,13 @@ int LzmaDecode(
#endif #endif
) )
& posStateMask); & posStateMask);
#ifdef _LZMA_IN_CB
if (rd.Result != LZMA_RESULT_OK) prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
return rd.Result; IfBit0(prob)
#endif
if (rd.ExtraBytes != 0)
return LZMA_RESULT_DATA_ERROR;
if (RangeDecoderBitDecode(p + IsMatch + (state << kNumPosBitsMax) + posState, &rd) == 0)
{ {
CProb *probs = p + Literal + (LZMA_LIT_SIZE * int symbol = 1;
UpdateBit0(prob)
prob = p + Literal + (LZMA_LIT_SIZE *
((( (((
(nowPos (nowPos
#ifdef _LZMA_OUT_READ #ifdef _LZMA_OUT_READ
@ -495,12 +296,9 @@ int LzmaDecode(
) )
& literalPosMask) << lc) + (previousByte >> (8 - lc)))); & literalPosMask) << lc) + (previousByte >> (8 - lc))));
if (state < 4) state = 0; if (state >= kNumLitStates)
else if (state < 10) state -= 3;
else state -= 6;
if (previousIsMatch)
{ {
Byte matchByte; int matchByte;
#ifdef _LZMA_OUT_READ #ifdef _LZMA_OUT_READ
UInt32 pos = dictionaryPos - rep0; UInt32 pos = dictionaryPos - rep0;
if (pos >= dictionarySize) if (pos >= dictionarySize)
@ -509,39 +307,73 @@ int LzmaDecode(
#else #else
matchByte = outStream[nowPos - rep0]; matchByte = outStream[nowPos - rep0];
#endif #endif
previousByte = LzmaLiteralDecodeMatch(probs, &rd, matchByte); do
previousIsMatch = 0; {
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);
} }
else while (symbol < 0x100)
previousByte = LzmaLiteralDecode(probs, &rd); {
CProb *probLit = prob + symbol;
RC_GET_BIT(probLit, symbol)
}
previousByte = (Byte)symbol;
outStream[nowPos++] = previousByte; outStream[nowPos++] = previousByte;
#ifdef _LZMA_OUT_READ #ifdef _LZMA_OUT_READ
if (distanceLimit < dictionarySize)
distanceLimit++;
dictionary[dictionaryPos] = previousByte; dictionary[dictionaryPos] = previousByte;
if (++dictionaryPos == dictionarySize) if (++dictionaryPos == dictionarySize)
dictionaryPos = 0; dictionaryPos = 0;
#endif #endif
if (state < 4) state = 0;
else if (state < 10) state -= 3;
else state -= 6;
} }
else else
{ {
previousIsMatch = 1; UpdateBit1(prob);
if (RangeDecoderBitDecode(p + IsRep + state, &rd) == 1) prob = p + IsRep + state;
IfBit0(prob)
{ {
if (RangeDecoderBitDecode(p + IsRepG0 + state, &rd) == 0) 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)
{ {
if (RangeDecoderBitDecode(p + IsRep0Long + (state << kNumPosBitsMax) + posState, &rd) == 0) UpdateBit0(prob);
prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
IfBit0(prob)
{ {
#ifdef _LZMA_OUT_READ #ifdef _LZMA_OUT_READ
UInt32 pos; UInt32 pos;
#endif #endif
if ( UpdateBit0(prob);
(nowPos
#ifdef _LZMA_OUT_READ #ifdef _LZMA_OUT_READ
+ globalPos if (distanceLimit == 0)
#endif #else
) if (nowPos == 0)
== 0) #endif
return LZMA_RESULT_DATA_ERROR; return LZMA_RESULT_DATA_ERROR;
state = state < 7 ? 9 : 11;
state = state < kNumLitStates ? 9 : 11;
#ifdef _LZMA_OUT_READ #ifdef _LZMA_OUT_READ
pos = dictionaryPos - rep0; pos = dictionaryPos - rep0;
if (pos >= dictionarySize) if (pos >= dictionarySize)
@ -554,20 +386,40 @@ int LzmaDecode(
previousByte = outStream[nowPos - rep0]; previousByte = outStream[nowPos - rep0];
#endif #endif
outStream[nowPos++] = previousByte; outStream[nowPos++] = previousByte;
#ifdef _LZMA_OUT_READ
if (distanceLimit < dictionarySize)
distanceLimit++;
#endif
continue; continue;
} }
else
{
UpdateBit1(prob);
}
} }
else else
{ {
UInt32 distance; UInt32 distance;
if(RangeDecoderBitDecode(p + IsRepG1 + state, &rd) == 0) UpdateBit1(prob);
prob = p + IsRepG1 + state;
IfBit0(prob)
{
UpdateBit0(prob);
distance = rep1; distance = rep1;
}
else else
{ {
if(RangeDecoderBitDecode(p + IsRepG2 + state, &rd) == 0) UpdateBit1(prob);
prob = p + IsRepG2 + state;
IfBit0(prob)
{
UpdateBit0(prob);
distance = rep2; distance = rep2;
}
else else
{ {
UpdateBit1(prob);
distance = rep3; distance = rep3;
rep3 = rep2; rep3 = rep2;
} }
@ -576,55 +428,115 @@ int LzmaDecode(
rep1 = rep0; rep1 = rep0;
rep0 = distance; rep0 = distance;
} }
len = LzmaLenDecode(p + RepLenCoder, &rd, posState); state = state < kNumLitStates ? 8 : 11;
state = state < 7 ? 8 : 11; prob = p + RepLenCoder;
} }
else
{ {
int posSlot; int numBits, offset;
rep3 = rep2; CProb *probLen = prob + LenChoice;
rep2 = rep1; IfBit0(probLen)
rep1 = rep0;
state = state < 7 ? 7 : 10;
len = LzmaLenDecode(p + LenCoder, &rd, posState);
posSlot = RangeDecoderBitTreeDecode(p + PosSlot +
((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
kNumPosSlotBits), kNumPosSlotBits, &rd);
if (posSlot >= kStartPosModelIndex)
{ {
int numDirectBits = ((posSlot >> 1) - 1); UpdateBit0(probLen);
rep0 = ((2 | ((UInt32)posSlot & 1)) << numDirectBits); probLen = prob + LenLow + (posState << kLenNumLowBits);
if (posSlot < kEndPosModelIndex) offset = 0;
numBits = kLenNumLowBits;
}
else
{
UpdateBit1(probLen);
probLen = prob + LenChoice2;
IfBit0(probLen)
{ {
rep0 += RangeDecoderReverseBitTreeDecode( UpdateBit0(probLen);
p + SpecPos + rep0 - posSlot - 1, numDirectBits, &rd); probLen = prob + LenMid + (posState << kLenNumMidBits);
offset = kLenNumLowSymbols;
numBits = kLenNumMidBits;
} }
else else
{ {
rep0 += RangeDecoderDecodeDirectBits(&rd, UpdateBit1(probLen);
numDirectBits - kNumAlignBits) << kNumAlignBits; probLen = prob + LenHigh;
rep0 += RangeDecoderReverseBitTreeDecode(p + Align, kNumAlignBits, &rd); 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 else
rep0 = posSlot; rep0 = posSlot;
rep0++; if (++rep0 == (UInt32)(0))
} {
if (rep0 == (UInt32)(0)) /* it's for stream version */
{ len = kLzmaStreamWasFinishedId;
/* it's for stream version */ break;
len = -1; }
break;
}
if (rep0 > nowPos
#ifdef _LZMA_OUT_READ
+ globalPos
#endif
)
{
return LZMA_RESULT_DATA_ERROR;
} }
len += kMatchMinLen; len += kMatchMinLen;
#ifdef _LZMA_OUT_READ
if (rep0 > distanceLimit)
#else
if (rep0 > nowPos)
#endif
return LZMA_RESULT_DATA_ERROR;
#ifdef _LZMA_OUT_READ
if (dictionarySize - distanceLimit > (UInt32)len)
distanceLimit += len;
else
distanceLimit = dictionarySize;
#endif
do do
{ {
#ifdef _LZMA_OUT_READ #ifdef _LZMA_OUT_READ
@ -638,26 +550,35 @@ int LzmaDecode(
#else #else
previousByte = outStream[nowPos - rep0]; previousByte = outStream[nowPos - rep0];
#endif #endif
outStream[nowPos++] = previousByte;
len--; len--;
outStream[nowPos++] = previousByte;
} }
while(len > 0 && nowPos < outSize); while(len != 0 && nowPos < outSize);
} }
} }
RC_NORMALIZE;
#ifdef _LZMA_OUT_READ #ifdef _LZMA_OUT_READ
vs->RangeDecoder = rd; vs->Range = Range;
vs->Code = Code;
vs->DictionaryPos = dictionaryPos; vs->DictionaryPos = dictionaryPos;
vs->GlobalPos = globalPos + nowPos; vs->GlobalPos = globalPos + (UInt32)nowPos;
vs->DistanceLimit = distanceLimit;
vs->Reps[0] = rep0; vs->Reps[0] = rep0;
vs->Reps[1] = rep1; vs->Reps[1] = rep1;
vs->Reps[2] = rep2; vs->Reps[2] = rep2;
vs->Reps[3] = rep3; vs->Reps[3] = rep3;
vs->State = state; vs->State = state;
vs->PreviousIsMatch = previousIsMatch;
vs->RemainLen = len; vs->RemainLen = len;
vs->TempDictionary[0] = tempDictionary[0];
#endif #endif
#ifdef _LZMA_IN_CB
vs->Buffer = Buffer;
vs->BufferLim = BufferLim;
#else
*inSizeProcessed = (SizeT)(Buffer - inStream);
#endif
*outSizeProcessed = nowPos; *outSizeProcessed = nowPos;
return LZMA_RESULT_OK; return LZMA_RESULT_OK;
} }

View file

@ -2,7 +2,7 @@
LzmaDecode.h LzmaDecode.h
LZMA Decoder interface LZMA Decoder interface
LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25) LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
http://www.7-zip.org/ http://www.7-zip.org/
LZMA SDK is licensed under two licenses: LZMA SDK is licensed under two licenses:
@ -22,6 +22,8 @@
#ifndef __LZMADECODE_H #ifndef __LZMADECODE_H
#define __LZMADECODE_H #define __LZMADECODE_H
#include "LzmaTypes.h"
/* #define _LZMA_IN_CB */ /* #define _LZMA_IN_CB */
/* Use callback for input data */ /* Use callback for input data */
@ -35,66 +37,77 @@
/* #define _LZMA_LOC_OPT */ /* #define _LZMA_LOC_OPT */
/* Enable local speed optimizations inside code */ /* Enable local speed optimizations inside code */
#ifndef UInt32
#ifdef _LZMA_UINT32_IS_ULONG
#define UInt32 unsigned long
#else
#define UInt32 unsigned int
#endif
#endif
#ifdef _LZMA_PROB32 #ifdef _LZMA_PROB32
#define CProb UInt32 #define CProb UInt32
#else #else
#define CProb unsigned short #define CProb UInt16
#endif #endif
#define LZMA_RESULT_OK 0 #define LZMA_RESULT_OK 0
#define LZMA_RESULT_DATA_ERROR 1 #define LZMA_RESULT_DATA_ERROR 1
#define LZMA_RESULT_NOT_ENOUGH_MEM 2
#ifdef _LZMA_IN_CB #ifdef _LZMA_IN_CB
typedef struct _ILzmaInCallback typedef struct _ILzmaInCallback
{ {
int (*Read)(void *object, unsigned char **buffer, UInt32 *bufferSize); int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize);
} ILzmaInCallback; } ILzmaInCallback;
#endif #endif
#define LZMA_BASE_SIZE 1846 #define LZMA_BASE_SIZE 1846
#define LZMA_LIT_SIZE 768 #define LZMA_LIT_SIZE 768
/* #define LZMA_PROPERTIES_SIZE 5
bufferSize = (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)))* sizeof(CProb)
bufferSize += 100 in case of _LZMA_OUT_READ typedef struct _CLzmaProperties
by default CProb is unsigned short, {
but if specify _LZMA_PROB_32, CProb will be UInt32(unsigned int) int lc;
*/ int lp;
int pb;
#ifdef _LZMA_OUT_READ
UInt32 DictionarySize;
#endif
}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;
#ifdef _LZMA_IN_CB
const unsigned char *Buffer;
const unsigned char *BufferLim;
#endif
#ifdef _LZMA_OUT_READ
unsigned char *Dictionary;
UInt32 Range;
UInt32 Code;
UInt32 DictionaryPos;
UInt32 GlobalPos;
UInt32 DistanceLimit;
UInt32 Reps[4];
int State;
int RemainLen;
unsigned char TempDictionary[4];
#endif
} CLzmaDecoderState;
#ifdef _LZMA_OUT_READ #ifdef _LZMA_OUT_READ
int LzmaDecoderInit( #define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; }
unsigned char *buffer, UInt32 bufferSize,
int lc, int lp, int pb,
unsigned char *dictionary, UInt32 dictionarySize,
#ifdef _LZMA_IN_CB
ILzmaInCallback *inCallback
#else
unsigned char *inStream, UInt32 inSize
#endif
);
#endif #endif
int LzmaDecode( int LzmaDecode(CLzmaDecoderState *vs,
unsigned char *buffer, #ifdef _LZMA_IN_CB
#ifndef _LZMA_OUT_READ
UInt32 bufferSize,
int lc, int lp, int pb,
#ifdef _LZMA_IN_CB
ILzmaInCallback *inCallback, ILzmaInCallback *inCallback,
#else #else
unsigned char *inStream, UInt32 inSize, const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
#endif #endif
#endif unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed);
unsigned char *outStream, UInt32 outSize,
UInt32 *outSizeProcessed);
#endif #endif

View file

@ -0,0 +1,45 @@
/*
LzmaTypes.h
Types for LZMA Decoder
This file written and distributed to public domain by Igor Pavlov.
This file is part of LZMA SDK 4.40 (2006-05-01)
*/
#ifndef __LZMATYPES_H
#define __LZMATYPES_H
#ifndef _7ZIP_BYTE_DEFINED
#define _7ZIP_BYTE_DEFINED
typedef unsigned char Byte;
#endif
#ifndef _7ZIP_UINT16_DEFINED
#define _7ZIP_UINT16_DEFINED
typedef unsigned short UInt16;
#endif
#ifndef _7ZIP_UINT32_DEFINED
#define _7ZIP_UINT32_DEFINED
#ifdef _LZMA_UINT32_IS_ULONG
typedef unsigned long UInt32;
#else
typedef unsigned int UInt32;
#endif
#endif
/* #define _LZMA_NO_SYSTEM_SIZE_T */
/* You can use it, if you don't want <stddef.h> */
#ifndef _7ZIP_SIZET_DEFINED
#define _7ZIP_SIZET_DEFINED
#ifdef _LZMA_NO_SYSTEM_SIZE_T
typedef UInt32 SizeT;
#else
#include <stddef.h>
typedef size_t SizeT;
#endif
#endif
#endif

View file

@ -1,77 +1,86 @@
# #
# Makefile for Broadcom BCM947XX boards # Makefile for the LZMA compressed kernel loader for
# Atheros AR7XXX/AR9XXX based boards
# #
# Copyright 2001-2003, Broadcom Corporation # Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
# All Rights Reserved.
#
# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
# #
# Copyright 2004 Manuel Novoa III <mjn3@codepoet.org> # Some parts of this file was based on the OpenWrt specific lzma-loader
# Modified to support bzip'd kernels. # for the BCM47xx and ADM5120 based boards:
# Of course, it would be better to integrate bunzip capability into CFE. # Copyright (C) 2004 Manuel Novoa III (mjn3@codepoet.org)
# Copyright (C) 2005 Mineharu Takahara <mtakahar@yahoo.com>
# Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
# #
# Copyright 2005 Oleg I. Vdovikin <oleg@cs.msu.su> # This program is free software; you can redistribute it and/or modify it
# Cleaned up, modified for lzma support, removed from kernel # under the terms of the GNU General Public License version 2 as published
# by the Free Software Foundation.
# #
TEXT_START := 0x80010000 LOADADDR :=
BZ_TEXT_START := 0x80300000 LZMA_TEXT_START := 0x80a00000
LOADER_DATA :=
OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .reginfo -R .note -R .comment -R .mdebug -S CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdump
BIN_FLAGS := -O binary -R .reginfo -R .note -R .comment -R .mdebug -S
CFLAGS = -D__KERNEL__ -Wall -Wstrict-prototypes -Wno-trigraphs -Os \ CFLAGS = -D__KERNEL__ -Wall -Wstrict-prototypes -Wno-trigraphs -Os \
-fno-strict-aliasing -fno-common -fomit-frame-pointer -G 0 -mno-abicalls -fno-pic \ -fno-strict-aliasing -fno-common -fomit-frame-pointer -G 0 \
-ffunction-sections -pipe -mlong-calls -fno-common \ -mno-abicalls -fno-pic -ffunction-sections -pipe \
-mabi=32 -march=mips32 -Wa,-32 -Wa,-march=mips32 -Wa,-mips32 -Wa,--trap -ffreestanding -fhonour-copts \
CFLAGS += -DLOADADDR=$(TEXT_START) -D_LZMA_IN_CB -mabi=32 -march=mips32 \
-Wa,-32 -Wa,-march=mips32 -Wa,-mips32 -Wa,--trap
CFLAGS += -D_LZMA_PROB32
ASFLAGS = $(CFLAGS) -D__ASSEMBLY__ -DBZ_TEXT_START=$(BZ_TEXT_START) ASFLAGS = $(CFLAGS) -D__ASSEMBLY__
SEDFLAGS := s/BZ_TEXT_START/$(BZ_TEXT_START)/;s/TEXT_START/$(TEXT_START)/ LDFLAGS = -static --gc-sections -no-warn-mismatch
LDFLAGS += -e startup -T loader.lds -Ttext $(LZMA_TEXT_START)
OBJECTS := head.o data.o O_FORMAT = $(shell $(OBJDUMP) -i | head -2 | grep elf32)
all: loader.gz loader.elf OBJECTS := head.o loader.o cache.o board.o printf.o LzmaDecode.o
ifneq ($(strip $(LOADER_DATA)),)
OBJECTS += data.o
CFLAGS += -DLZMA_WRAPPER=1 -DLOADADDR=$(LOADADDR)
endif
all: loader.elf
# Don't build dependencies, this may die if $(CC) isn't gcc # Don't build dependencies, this may die if $(CC) isn't gcc
dep: dep:
install: install:
loader.gz: loader %.o : %.c
gzip -nc9 $< > $@ $(CC) $(CFLAGS) -c -o $@ $<
loader.elf: loader.o %.o : %.S
cp $< $@ $(CC) $(ASFLAGS) -c -o $@ $<
loader: loader.o data.o: $(LOADER_DATA)
$(OBJCOPY) $< $@ $(LD) -r -b binary --oformat $(O_FORMAT) -T lzma-data.lds -o $@ $<
loader.o: loader.lds $(OBJECTS) loader: $(OBJECTS)
$(LD) -static --gc-sections -no-warn-mismatch -T loader.lds -o $@ $(OBJECTS) $(LD) $(LDFLAGS) -o $@ $(OBJECTS)
loader.lds: loader.lds.in Makefile loader.bin: loader
@sed "$(SEDFLAGS)" < $< > $@ $(OBJCOPY) $(BIN_FLAGS) $< $@
data.o: data.lds decompress.image loader2.o: loader.bin
$(LD) -no-warn-mismatch -T data.lds -r -o $@ -b binary decompress.image -b elf32-tradlittlemips $(LD) -r -b binary --oformat $(O_FORMAT) -o $@ $<
data.lds: loader.elf: loader2.o
@echo "SECTIONS { .data : { code_start = .; *(.data) code_stop = .; }}" > $@ $(LD) -e startup -T loader2.lds -Ttext $(LOADADDR) -o $@ $<
decompress.image: decompress
$(OBJCOPY) $< $@
decompress: decompress.lds decompress.o LzmaDecode.o
$(LD) -static --gc-sections -no-warn-mismatch -T decompress.lds -o $@ decompress.o LzmaDecode.o
decompress.lds: decompress.lds.in Makefile
@sed "$(SEDFLAGS)" < $< > $@
mrproper: clean mrproper: clean
clean: clean:
rm -f loader.gz loader decompress *.lds *.o *.image rm -f loader *.elf *.bin *.o

View file

@ -1,55 +0,0 @@
/*
* LZMA compressed kernel decompressor for bcm947xx boards
*
* Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
The code is intended to decompress kernel, being compressed using lzma utility
build using 7zip LZMA SDK. This utility is located in the LZMA_Alone directory
decompressor code expects that your .trx file consist of three partitions:
1) decompressor itself (this is gziped code which pmon/cfe will extract and run
on boot-up instead of real kernel)
2) LZMA compressed kernel (both streamed and regular modes are supported now)
3) Root filesystem
Please be sure to apply the following patch for use this new trx layout (it will
allow using both new and old trx files for root filesystem lookup code)
--- linuz/arch/mips/brcm-boards/bcm947xx/setup.c 2005-01-23 19:24:27.503322896 +0300
+++ linux/arch/mips/brcm-boards/bcm947xx/setup.c 2005-01-23 19:29:05.237100944 +0300
@@ -221,7 +221,9 @@
/* Try looking at TRX header for rootfs offset */
if (le32_to_cpu(trx->magic) == TRX_MAGIC) {
bcm947xx_parts[1].offset = off;
- if (le32_to_cpu(trx->offsets[1]) > off)
+ if (le32_to_cpu(trx->offsets[2]) > off)
+ off = le32_to_cpu(trx->offsets[2]);
+ else if (le32_to_cpu(trx->offsets[1]) > off)
off = le32_to_cpu(trx->offsets[1]);
continue;
}
Revision history:
0.02 Initial release
0.03 Added Mineharu Takahara <mtakahar@yahoo.com> patch to pass actual
output size to decoder (stream mode compressed input is not
a requirement anymore)
0.04 Reordered functions using lds script

View file

@ -0,0 +1,103 @@
/*
* BCM63XX specific implementation parts
*
* Copyright (C) 2014 Jonas Gorski <jogo@openwrt.org>
*
* 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.
*/
#include <stddef.h>
#include "config.h"
#include "cp0regdef.h"
#define READREG(r) *(volatile unsigned int *)(r)
#define WRITEREG(r,v) *(volatile unsigned int *)(r) = v
#define UART_IR_REG 0x10
#define UART_FIFO_REG 0x14
unsigned long uart_base;
static void wait_xfered(void)
{
unsigned int val;
do {
val = READREG(uart_base + UART_IR_REG);
if (val & (1 << 5))
break;
} while (1);
}
void board_putc(int ch)
{
if (!uart_base)
return;
wait_xfered();
WRITEREG(uart_base + UART_FIFO_REG, ch);
wait_xfered();
}
#define PRID_IMP_BMIPS32_REV4 0x4000
#define PRID_IMP_BMIPS32_REV8 0x8000
#define PRID_IMP_BMIPS3300 0x9000
#define PRID_IMP_BMIPS3300_ALT 0x9100
#define PRID_IMP_BMIPS3300_BUG 0x0000
#define PRID_IMP_BMIPS43XX 0xa000
void board_init(void)
{
unsigned long prid, chipid, chipid_reg;
prid = read_32bit_c0_register($15, 0);
switch (prid & 0xff00) {
case PRID_IMP_BMIPS32_REV4:
case PRID_IMP_BMIPS32_REV8:
case PRID_IMP_BMIPS3300_ALT:
case PRID_IMP_BMIPS3300_BUG:
chipid_reg = 0xfffe0000;
break;
case PRID_IMP_BMIPS3300:
if ((prid & 0xff) >= 0x33)
chipid_reg = 0xb0000000;
else
chipid_reg = 0xfffe0000;
break;
case PRID_IMP_BMIPS43XX:
if ((prid & 0xff) >= 0x30)
chipid_reg = 0xb0000000;
else
chipid_reg = 0xfffe0000;
break;
default:
return;
}
chipid = READREG(chipid_reg);
switch (chipid >> 16) {
case 0x6318:
case 0x6328:
case 0x6358:
case 0x6362:
case 0x6368:
case 0x6369:
uart_base = chipid_reg + 0x100;
break;
case 0x6316:
case 0x6326:
uart_base = chipid_reg + 0x180;
break;
case 0x6338:
case 0x6345:
case 0x6348:
uart_base = chipid_reg + 0x300;
break;
default:
return;
}
}

View file

@ -0,0 +1,46 @@
/*
* LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
*
* Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
*
* The cache manipulation routine has been taken from the U-Boot project.
* (C) Copyright 2003
* Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
*
* 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.
*
*/
#include "cache.h"
#include "cacheops.h"
#include "config.h"
#include "printf.h"
#define cache_op(op,addr) \
__asm__ __volatile__( \
" .set push \n" \
" .set noreorder \n" \
" .set mips3\n\t \n" \
" cache %0, %1 \n" \
" .set pop \n" \
: \
: "i" (op), "R" (*(unsigned char *)(addr)))
void flush_cache(unsigned long start_addr, unsigned long size)
{
unsigned long lsize = CONFIG_CACHELINE_SIZE;
unsigned long addr = start_addr & ~(lsize - 1);
unsigned long aend = (start_addr + size + (lsize - 1)) & ~(lsize - 1);
printf("blasting from 0x%08x to 0x%08x (0x%08x - 0x%08x)\n", start_addr, size, addr, aend);
while (1) {
cache_op(Hit_Writeback_Inv_D, addr);
cache_op(Hit_Invalidate_I, addr);
if (addr == aend)
break;
addr += lsize;
}
}

View file

@ -0,0 +1,17 @@
/*
* LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
*
* Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
*
* 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.
*
*/
#ifndef __CACHE_H
#define __CACHE_H
void flush_cache(unsigned long start_addr, unsigned long size);
#endif /* __CACHE_H */

View file

@ -0,0 +1,85 @@
/*
* Cache operations for the cache instruction.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* (C) Copyright 1996, 97, 99, 2002, 03 Ralf Baechle
* (C) Copyright 1999 Silicon Graphics, Inc.
*/
#ifndef __ASM_CACHEOPS_H
#define __ASM_CACHEOPS_H
/*
* Cache Operations available on all MIPS processors with R4000-style caches
*/
#define Index_Invalidate_I 0x00
#define Index_Writeback_Inv_D 0x01
#define Index_Load_Tag_I 0x04
#define Index_Load_Tag_D 0x05
#define Index_Store_Tag_I 0x08
#define Index_Store_Tag_D 0x09
#if defined(CONFIG_CPU_LOONGSON2)
#define Hit_Invalidate_I 0x00
#else
#define Hit_Invalidate_I 0x10
#endif
#define Hit_Invalidate_D 0x11
#define Hit_Writeback_Inv_D 0x15
/*
* R4000-specific cacheops
*/
#define Create_Dirty_Excl_D 0x0d
#define Fill 0x14
#define Hit_Writeback_I 0x18
#define Hit_Writeback_D 0x19
/*
* R4000SC and R4400SC-specific cacheops
*/
#define Index_Invalidate_SI 0x02
#define Index_Writeback_Inv_SD 0x03
#define Index_Load_Tag_SI 0x06
#define Index_Load_Tag_SD 0x07
#define Index_Store_Tag_SI 0x0A
#define Index_Store_Tag_SD 0x0B
#define Create_Dirty_Excl_SD 0x0f
#define Hit_Invalidate_SI 0x12
#define Hit_Invalidate_SD 0x13
#define Hit_Writeback_Inv_SD 0x17
#define Hit_Writeback_SD 0x1b
#define Hit_Set_Virtual_SI 0x1e
#define Hit_Set_Virtual_SD 0x1f
/*
* R5000-specific cacheops
*/
#define R5K_Page_Invalidate_S 0x17
/*
* RM7000-specific cacheops
*/
#define Page_Invalidate_T 0x16
/*
* R10000-specific cacheops
*
* Cacheops 0x02, 0x06, 0x0a, 0x0c-0x0e, 0x16, 0x1a and 0x1e are unused.
* Most of the _S cacheops are identical to the R4000SC _SD cacheops.
*/
#define Index_Writeback_Inv_S 0x03
#define Index_Load_Tag_S 0x07
#define Index_Store_Tag_S 0x0B
#define Hit_Invalidate_S 0x13
#define Cache_Barrier 0x14
#define Hit_Writeback_Inv_S 0x17
#define Index_Load_Data_I 0x18
#define Index_Load_Data_D 0x19
#define Index_Load_Data_S 0x1b
#define Index_Store_Data_I 0x1c
#define Index_Store_Data_D 0x1d
#define Index_Store_Data_S 0x1f
#endif /* __ASM_CACHEOPS_H */

View file

@ -0,0 +1,31 @@
/*
* LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
*
* Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
*
* 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.
*
*/
#ifndef _CONFIG_H_
#define _CONFIG_H_
#define CONFIG_ICACHE_SIZE (32 * 1024)
#define CONFIG_DCACHE_SIZE (32 * 1024)
#define CONFIG_CACHELINE_SIZE 16
#ifndef CONFIG_FLASH_OFFS
#define CONFIG_FLASH_OFFS 0
#endif
#ifndef CONFIG_FLASH_MAX
#define CONFIG_FLASH_MAX 0
#endif
#ifndef CONFIG_FLASH_STEP
#define CONFIG_FLASH_STEP 0x1000
#endif
#endif /* _CONFIG_H_ */

View file

@ -0,0 +1,54 @@
/*
* Copyright (C) 1994, 1995, 1996, 1997, 2000, 2001 by Ralf Baechle
*
* Copyright (C) 2001, Monta Vista Software
* Author: jsun@mvista.com or jsun@junsun.net
*/
#ifndef _cp0regdef_h_
#define _cp0regdef_h_
#define CP0_INDEX $0
#define CP0_RANDOM $1
#define CP0_ENTRYLO0 $2
#define CP0_ENTRYLO1 $3
#define CP0_CONTEXT $4
#define CP0_PAGEMASK $5
#define CP0_WIRED $6
#define CP0_BADVADDR $8
#define CP0_COUNT $9
#define CP0_ENTRYHI $10
#define CP0_COMPARE $11
#define CP0_STATUS $12
#define CP0_CAUSE $13
#define CP0_EPC $14
#define CP0_PRID $15
#define CP0_CONFIG $16
#define CP0_LLADDR $17
#define CP0_WATCHLO $18
#define CP0_WATCHHI $19
#define CP0_XCONTEXT $20
#define CP0_FRAMEMASK $21
#define CP0_DIAGNOSTIC $22
#define CP0_PERFORMANCE $25
#define CP0_ECC $26
#define CP0_CACHEERR $27
#define CP0_TAGLO $28
#define CP0_TAGHI $29
#define CP0_ERROREPC $30
#define read_32bit_c0_register(reg,sel) \
({ int __res; \
if (sel == 0) \
__asm__ __volatile__( \
"mfc0\t%0, " #reg "\n\t" \
: "=r" (__res)); \
else \
__asm__ __volatile__( \
".set\tmips32\n\t" \
"mfc0\t%0, " #reg ", " #sel "\n\t" \
".set mips0\n\t" \
: "=r" (__res)); \
__res; \
})
#endif

View file

@ -1,175 +0,0 @@
/*
* LZMA compressed kernel decompressor for bcm947xx boards
*
* Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* Please note, this was code based on the bunzip2 decompressor code
* by Manuel Novoa III (mjn3@codepoet.org), although the only thing left
* is an idea and part of original vendor code
*
*
* 12-Mar-2005 Mineharu Takahara <mtakahar@yahoo.com>
* pass actual output size to decoder (stream mode
* compressed input is not a requirement anymore)
*
* 24-Apr-2005 Oleg I. Vdovikin
* reordered functions using lds script, removed forward decl
*
*/
#include "LzmaDecode.h"
#define BCM4710_FLASH 0x1fc00000 /* Flash */
#define KSEG0 0x80000000
#define KSEG1 0xa0000000
#define KSEG1ADDR(a) ((((unsigned)(a)) & 0x1fffffffU) | KSEG1)
#define Index_Invalidate_I 0x00
#define Index_Writeback_Inv_D 0x01
#define cache_unroll(base,op) \
__asm__ __volatile__( \
".set noreorder;\n" \
".set mips3;\n" \
"cache %1, (%0);\n" \
".set mips0;\n" \
".set reorder\n" \
: \
: "r" (base), \
"i" (op));
static __inline__ void blast_icache(unsigned long size, unsigned long lsize)
{
unsigned long start = KSEG0;
unsigned long end = (start + size);
while(start < end) {
cache_unroll(start,Index_Invalidate_I);
start += lsize;
}
}
static __inline__ void blast_dcache(unsigned long size, unsigned long lsize)
{
unsigned long start = KSEG0;
unsigned long end = (start + size);
while(start < end) {
cache_unroll(start,Index_Writeback_Inv_D);
start += lsize;
}
}
#define TRX_MAGIC 0x30524448 /* "HDR0" */
struct trx_header {
unsigned int magic; /* "HDR0" */
unsigned int len; /* Length of file including header */
unsigned int crc32; /* 32-bit CRC from flag_version to end of file */
unsigned int flag_version; /* 0:15 flags, 16:31 version */
unsigned int offsets[3]; /* Offsets of partitions from start of header */
};
/* beyound the image end, size not known in advance */
extern unsigned char workspace[];
unsigned int offset;
unsigned char *data;
/* flash access should be aligned, so wrapper is used */
/* read byte from the flash, all accesses are 32-bit aligned */
static int read_byte(void *object, unsigned char **buffer, UInt32 *bufferSize)
{
static unsigned int val;
if (((unsigned int)offset % 4) == 0) {
val = *(unsigned int *)data;
data += 4;
}
*bufferSize = 1;
*buffer = ((unsigned char *)&val) + (offset++ & 3);
return LZMA_RESULT_OK;
}
static __inline__ unsigned char get_byte(void)
{
unsigned char *buffer;
UInt32 fake;
return read_byte(0, &buffer, &fake), *buffer;
}
/* should be the first function */
void entry(unsigned long icache_size, unsigned long icache_lsize,
unsigned long dcache_size, unsigned long dcache_lsize)
{
unsigned int i; /* temp value */
unsigned int lc; /* literal context bits */
unsigned int lp; /* literal pos state bits */
unsigned int pb; /* pos state bits */
unsigned int osize; /* uncompressed size */
ILzmaInCallback callback;
callback.Read = read_byte;
/* look for trx header, 32-bit data access */
for (data = ((unsigned char *) KSEG1ADDR(BCM4710_FLASH));
((struct trx_header *)data)->magic != TRX_MAGIC; data += 65536);
/* compressed kernel is in the partition 0 or 1 */
if (((struct trx_header *)data)->offsets[1] > 65536)
data += ((struct trx_header *)data)->offsets[0];
else
data += ((struct trx_header *)data)->offsets[1];
offset = 0;
/* lzma args */
i = get_byte();
lc = i % 9, i = i / 9;
lp = i % 5, pb = i / 5;
/* skip rest of the LZMA coder property */
for (i = 0; i < 4; i++)
get_byte();
/* read the lower half of uncompressed size in the header */
osize = ((unsigned int)get_byte()) +
((unsigned int)get_byte() << 8) +
((unsigned int)get_byte() << 16) +
((unsigned int)get_byte() << 24);
/* skip rest of the header (upper half of uncompressed size) */
for (i = 0; i < 4; i++)
get_byte();
/* decompress kernel */
if (LzmaDecode(workspace, ~0, lc, lp, pb, &callback,
(unsigned char*)LOADADDR, osize, &i) == LZMA_RESULT_OK)
{
blast_dcache(dcache_size, dcache_lsize);
blast_icache(icache_size, icache_lsize);
/* Jump to load address */
((void (*)(void)) LOADADDR)();
}
}

View file

@ -1,20 +0,0 @@
OUTPUT_ARCH(mips)
ENTRY(entry)
SECTIONS {
. = BZ_TEXT_START;
.text : {
*(.text.entry)
*(.text)
*(.rodata)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
workspace = .;
}

View file

@ -1,155 +1,118 @@
/* Copyright 2005 Oleg I. Vdovikin (oleg@cs.msu.su) */ /*
/* cache manipulation adapted from Broadcom code */ * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
/* idea taken from original bunzip2 decompressor code */ *
/* Copyright 2004 Manuel Novoa III (mjn3@codepoet.org) */ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
/* Licensed under the linux kernel's version of the GPL.*/ *
* Some parts of this code was based on the OpenWrt specific lzma-loader
* for the BCM47xx and ADM5120 based boards:
* Copyright (C) 2004 Manuel Novoa III (mjn3@codepoet.org)
* Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
*
* 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.
*/
#include <asm/asm.h> #include <asm/asm.h>
#include <asm/regdef.h> #include <asm/regdef.h>
#include "cp0regdef.h"
#include "cacheops.h"
#include "config.h"
#define KSEG0 0x80000000 #define KSEG0 0x80000000
#define C0_CONFIG $16 .macro ehb
#define C0_TAGLO $28 sll zero, 3
#define C0_TAGHI $29 .endm
#define CONF1_DA_SHIFT 7 /* D$ associativity */
#define CONF1_DA_MASK 0x00000380
#define CONF1_DA_BASE 1
#define CONF1_DL_SHIFT 10 /* D$ line size */
#define CONF1_DL_MASK 0x00001c00
#define CONF1_DL_BASE 2
#define CONF1_DS_SHIFT 13 /* D$ sets/way */
#define CONF1_DS_MASK 0x0000e000
#define CONF1_DS_BASE 64
#define CONF1_IA_SHIFT 16 /* I$ associativity */
#define CONF1_IA_MASK 0x00070000
#define CONF1_IA_BASE 1
#define CONF1_IL_SHIFT 19 /* I$ line size */
#define CONF1_IL_MASK 0x00380000
#define CONF1_IL_BASE 2
#define CONF1_IS_SHIFT 22 /* Instruction cache sets/way */
#define CONF1_IS_MASK 0x01c00000
#define CONF1_IS_BASE 64
#define Index_Invalidate_I 0x00
#define Index_Writeback_Inv_D 0x01
.text .text
LEAF(startup)
LEAF(startup)
.set noreorder .set noreorder
.set mips32
/* Copy decompressor code to the right place */
li t2, BZ_TEXT_START
add a0, t2, 0
la a1, code_start
la a2, code_stop
$L1:
lw t0, 0(a1)
sw t0, 0(a0)
add a1, 4
add a0, 4
blt a1, a2, $L1
nop
/* At this point we need to invalidate dcache and */
/* icache before jumping to new code */
1: /* Get cache sizes */ mtc0 zero, CP0_WATCHLO # clear watch registers
.set mips32 mtc0 zero, CP0_WATCHHI
mfc0 s0,C0_CONFIG,1 mtc0 zero, CP0_CAUSE # clear before writing status register
.set mips0
li s1,CONF1_DL_MASK mfc0 t0, CP0_STATUS
and s1,s0 li t1, 0x1000001f
beq s1,zero,nodc or t0, t1
xori t0, 0x1f
mtc0 t0, CP0_STATUS
ehb
mtc0 zero, CP0_COUNT
mtc0 zero, CP0_COMPARE
ehb
la t0, __reloc_label # get linked address of label
bal __reloc_label # branch and link to label to
nop # get actual address
__reloc_label:
subu t0, ra, t0 # get reloc_delta
beqz t0, __reloc_done # if delta is 0 we are in the right place
nop nop
srl s1,CONF1_DL_SHIFT /* Copy our code to the right place */
li t0,CONF1_DL_BASE la t1, _code_start # get linked address of _code_start
sll s1,t0,s1 /* s1 has D$ cache line size */ la t2, _code_end # get linked address of _code_end
addu t0, t0, t1 # calculate actual address of _code_start
li s2,CONF1_DA_MASK __reloc_copy:
and s2,s0 lw t3, 0(t0)
srl s2,CONF1_DA_SHIFT sw t3, 0(t1)
addiu s2,CONF1_DA_BASE /* s2 now has D$ associativity */ add t1, 4
blt t1, t2, __reloc_copy
add t0, 4
li t0,CONF1_DS_MASK /* flush cache */
and t0,s0 la t0, _code_start
srl t0,CONF1_DS_SHIFT la t1, _code_end
li s3,CONF1_DS_BASE
sll s3,s3,t0 /* s3 has D$ sets per way */
multu s2,s3 /* sets/way * associativity */ li t2, ~(CONFIG_CACHELINE_SIZE - 1)
mflo t0 /* total cache lines */ and t0, t2
and t1, t2
li t2, CONFIG_CACHELINE_SIZE
multu s1,t0 /* D$ linesize * lines */ b __flush_check
mflo s2 /* s2 is now D$ size in bytes */
/* Initilize the D$: */
mtc0 zero,C0_TAGLO
mtc0 zero,C0_TAGHI
li t0,KSEG0 /* Just an address for the first $ line */
addu t1,t0,s2 /* + size of cache == end */
.set mips3
1: cache Index_Writeback_Inv_D,0(t0)
.set mips0
bne t0,t1,1b
addu t0,s1
nodc:
/* Now we get to do it all again for the I$ */
move s3,zero /* just in case there is no icache */
move s4,zero
li t0,CONF1_IL_MASK
and t0,s0
beq t0,zero,noic
nop nop
srl t0,CONF1_IL_SHIFT __flush_line:
li s3,CONF1_IL_BASE cache Hit_Writeback_Inv_D, 0(t0)
sll s3,t0 /* s3 has I$ cache line size */ cache Hit_Invalidate_I, 0(t0)
add t0, t2
li t0,CONF1_IA_MASK __flush_check:
and t0,s0 bne t0, t1, __flush_line
srl t0,CONF1_IA_SHIFT nop
addiu s4,t0,CONF1_IA_BASE /* s4 now has I$ associativity */
li t0,CONF1_IS_MASK sync
and t0,s0
srl t0,CONF1_IS_SHIFT
li s5,CONF1_IS_BASE
sll s5,t0 /* s5 has I$ sets per way */
multu s4,s5 /* sets/way * associativity */ __reloc_done:
mflo t0 /* s4 is now total cache lines */
multu s3,t0 /* I$ linesize * lines */ /* clear bss */
mflo s4 /* s4 is cache size in bytes */ la t0, _bss_start
la t1, _bss_end
b __bss_check
nop
/* Initilize the I$: */ __bss_fill:
mtc0 zero,C0_TAGLO sw zero, 0(t0)
mtc0 zero,C0_TAGHI addi t0, 4
li t0,KSEG0 /* Just an address for the first $ line */ __bss_check:
addu t1,t0,s4 /* + size of cache == end */ bne t0, t1, __bss_fill
nop
.set mips3 /* Setup new "C" stack */
1: cache Index_Invalidate_I,0(t0) la sp, _stack
.set mips0
bne t0,t1,1b /* jump to the decompressor routine */
addu t0,s3 la t0, loader_main
jr t0
nop
noic:
move a0,s3 /* icache line size */
move a1,s4 /* icache size */
move a2,s1 /* dcache line size */
jal t2
move a3,s2 /* dcache size */
.set reorder .set reorder
END(startup) END(startup)

View file

@ -0,0 +1,175 @@
/*
* LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
*
* Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
*
* Some parts of this code was based on the OpenWrt specific lzma-loader
* for the BCM47xx and ADM5120 based boards:
* Copyright (C) 2004 Manuel Novoa III (mjn3@codepoet.org)
* Copyright (C) 2005 Mineharu Takahara <mtakahar@yahoo.com>
* Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
*
* The image_header structure has been taken from the U-Boot project.
* (C) Copyright 2008 Semihalf
* (C) Copyright 2000-2005
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* 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.
*/
#include <stddef.h>
#include <stdint.h>
#include "config.h"
#include "cache.h"
#include "printf.h"
#include "LzmaDecode.h"
#define KSEG0 0x80000000
#define KSEG1 0xa0000000
#define KSEG1ADDR(a) ((((unsigned)(a)) & 0x1fffffffU) | KSEG1)
#undef LZMA_DEBUG
#ifdef LZMA_DEBUG
# define DBG(f, a...) printf(f, ## a)
#else
# define DBG(f, a...) do {} while (0)
#endif
/* beyond the image end, size not known in advance */
extern unsigned char workspace[];
extern void board_init(void);
static CLzmaDecoderState lzma_state;
static unsigned char *lzma_data;
static unsigned long lzma_datasize;
static unsigned long lzma_outsize;
static unsigned long kernel_la;
static void halt(void)
{
printf("\nSystem halted!\n");
for(;;);
}
static __inline__ unsigned char lzma_get_byte(void)
{
unsigned char c;
lzma_datasize--;
c = *lzma_data++;
return c;
}
static int lzma_init_props(void)
{
unsigned char props[LZMA_PROPERTIES_SIZE];
int res;
int i;
/* read lzma properties */
for (i = 0; i < LZMA_PROPERTIES_SIZE; i++)
props[i] = lzma_get_byte();
/* read the lower half of uncompressed size in the header */
lzma_outsize = ((SizeT) lzma_get_byte()) +
((SizeT) lzma_get_byte() << 8) +
((SizeT) lzma_get_byte() << 16) +
((SizeT) lzma_get_byte() << 24);
/* skip rest of the header (upper half of uncompressed size) */
for (i = 0; i < 4; i++)
lzma_get_byte();
res = LzmaDecodeProperties(&lzma_state.Properties, props,
LZMA_PROPERTIES_SIZE);
return res;
}
static int lzma_decompress(unsigned char *outStream)
{
SizeT ip, op;
int ret;
lzma_state.Probs = (CProb *) workspace;
ret = LzmaDecode(&lzma_state, lzma_data, lzma_datasize, &ip, outStream,
lzma_outsize, &op);
if (ret != LZMA_RESULT_OK) {
int i;
DBG("LzmaDecode error %d at %08x, osize:%d ip:%d op:%d\n",
ret, lzma_data + ip, lzma_outsize, ip, op);
for (i = 0; i < 16; i++)
DBG("%02x ", lzma_data[ip + i]);
DBG("\n");
}
return ret;
}
static void lzma_init_data(void)
{
extern unsigned char _lzma_data_start[];
extern unsigned char _lzma_data_end[];
kernel_la = LOADADDR;
lzma_data = _lzma_data_start;
lzma_datasize = _lzma_data_end - _lzma_data_start;
}
void loader_main(unsigned long reg_a0, unsigned long reg_a1,
unsigned long reg_a2, unsigned long reg_a3)
{
void (*kernel_entry) (unsigned long, unsigned long, unsigned long,
unsigned long);
int res;
board_init();
printf("\n\nOpenWrt kernel loader for BCM63XX\n");
printf("Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>\n");
printf("Copyright (C) 2014 Jonas Gorski <jogo@openwrt.org>\n");
lzma_init_data();
res = lzma_init_props();
if (res != LZMA_RESULT_OK) {
printf("Incorrect LZMA stream properties!\n");
halt();
}
printf("Decompressing kernel... ");
res = lzma_decompress((unsigned char *) kernel_la);
if (res != LZMA_RESULT_OK) {
printf("failed, ");
switch (res) {
case LZMA_RESULT_DATA_ERROR:
printf("data error!\n");
break;
default:
printf("unknown error %d!\n", res);
}
halt();
} else {
printf("done!\n");
}
flush_cache(kernel_la, lzma_outsize);
printf("Starting kernel at %08x...\n\n", kernel_la);
kernel_entry = (void *) kernel_la;
kernel_entry(reg_a0, reg_a1, reg_a2, reg_a3);
}

View file

@ -0,0 +1,34 @@
OUTPUT_ARCH(mips)
SECTIONS {
.text : {
_code_start = .;
*(.text)
*(.text.*)
*(.rodata)
*(.rodata.*)
*(.data.lzma)
}
. = ALIGN(32);
.data : {
*(.data)
*(.data.*)
}
. = ALIGN(32);
_code_end = .;
_bss_start = .;
.bss : {
*(.bss)
*(.bss.*)
}
. = ALIGN(32);
_bss_end = .;
. = . + 8192;
_stack = .;
workspace = .;
}

View file

@ -1,17 +0,0 @@
OUTPUT_ARCH(mips)
ENTRY(startup)
SECTIONS {
. = TEXT_START;
.text : {
*(.text)
*(.rodata)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
}

View file

@ -0,0 +1,10 @@
OUTPUT_ARCH(mips)
SECTIONS {
.text : {
startup = .;
*(.text)
*(.text.*)
*(.data)
*(.data.*)
}
}

View file

@ -0,0 +1,8 @@
OUTPUT_ARCH(mips)
SECTIONS {
.data.lzma : {
_lzma_data_start = .;
*(.data)
_lzma_data_end = .;
}
}

View file

@ -0,0 +1,350 @@
/*
* Copyright (C) 2001 MontaVista Software Inc.
* Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include "printf.h"
extern void board_putc(int ch);
/* this is the maximum width for a variable */
#define LP_MAX_BUF 256
/* macros */
#define IsDigit(x) ( ((x) >= '0') && ((x) <= '9') )
#define Ctod(x) ( (x) - '0')
/* forward declaration */
static int PrintChar(char *, char, int, int);
static int PrintString(char *, char *, int, int);
static int PrintNum(char *, unsigned long, int, int, int, int, char, int);
/* private variable */
static const char theFatalMsg[] = "fatal error in lp_Print!";
/* -*-
* A low level printf() function.
*/
static void
lp_Print(void (*output)(void *, char *, int),
void * arg,
char *fmt,
va_list ap)
{
#define OUTPUT(arg, s, l) \
{ if (((l) < 0) || ((l) > LP_MAX_BUF)) { \
(*output)(arg, (char*)theFatalMsg, sizeof(theFatalMsg)-1); for(;;); \
} else { \
(*output)(arg, s, l); \
} \
}
char buf[LP_MAX_BUF];
char c;
char *s;
long int num;
int longFlag;
int negFlag;
int width;
int prec;
int ladjust;
char padc;
int length;
for(;;) {
{
/* scan for the next '%' */
char *fmtStart = fmt;
while ( (*fmt != '\0') && (*fmt != '%')) {
fmt ++;
}
/* flush the string found so far */
OUTPUT(arg, fmtStart, fmt-fmtStart);
/* are we hitting the end? */
if (*fmt == '\0') break;
}
/* we found a '%' */
fmt ++;
/* check for long */
if (*fmt == 'l') {
longFlag = 1;
fmt ++;
} else {
longFlag = 0;
}
/* check for other prefixes */
width = 0;
prec = -1;
ladjust = 0;
padc = ' ';
if (*fmt == '-') {
ladjust = 1;
fmt ++;
}
if (*fmt == '0') {
padc = '0';
fmt++;
}
if (IsDigit(*fmt)) {
while (IsDigit(*fmt)) {
width = 10 * width + Ctod(*fmt++);
}
}
if (*fmt == '.') {
fmt ++;
if (IsDigit(*fmt)) {
prec = 0;
while (IsDigit(*fmt)) {
prec = prec*10 + Ctod(*fmt++);
}
}
}
/* check format flag */
negFlag = 0;
switch (*fmt) {
case 'b':
if (longFlag) {
num = va_arg(ap, long int);
} else {
num = va_arg(ap, int);
}
length = PrintNum(buf, num, 2, 0, width, ladjust, padc, 0);
OUTPUT(arg, buf, length);
break;
case 'd':
case 'D':
if (longFlag) {
num = va_arg(ap, long int);
} else {
num = va_arg(ap, int);
}
if (num < 0) {
num = - num;
negFlag = 1;
}
length = PrintNum(buf, num, 10, negFlag, width, ladjust, padc, 0);
OUTPUT(arg, buf, length);
break;
case 'o':
case 'O':
if (longFlag) {
num = va_arg(ap, long int);
} else {
num = va_arg(ap, int);
}
length = PrintNum(buf, num, 8, 0, width, ladjust, padc, 0);
OUTPUT(arg, buf, length);
break;
case 'u':
case 'U':
if (longFlag) {
num = va_arg(ap, long int);
} else {
num = va_arg(ap, int);
}
length = PrintNum(buf, num, 10, 0, width, ladjust, padc, 0);
OUTPUT(arg, buf, length);
break;
case 'x':
if (longFlag) {
num = va_arg(ap, long int);
} else {
num = va_arg(ap, int);
}
length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 0);
OUTPUT(arg, buf, length);
break;
case 'X':
if (longFlag) {
num = va_arg(ap, long int);
} else {
num = va_arg(ap, int);
}
length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 1);
OUTPUT(arg, buf, length);
break;
case 'c':
c = (char)va_arg(ap, int);
length = PrintChar(buf, c, width, ladjust);
OUTPUT(arg, buf, length);
break;
case 's':
s = (char*)va_arg(ap, char *);
length = PrintString(buf, s, width, ladjust);
OUTPUT(arg, buf, length);
break;
case '\0':
fmt --;
break;
default:
/* output this char as it is */
OUTPUT(arg, fmt, 1);
} /* switch (*fmt) */
fmt ++;
} /* for(;;) */
/* special termination call */
OUTPUT(arg, "\0", 1);
}
/* --------------- local help functions --------------------- */
static int
PrintChar(char * buf, char c, int length, int ladjust)
{
int i;
if (length < 1) length = 1;
if (ladjust) {
*buf = c;
for (i=1; i< length; i++) buf[i] = ' ';
} else {
for (i=0; i< length-1; i++) buf[i] = ' ';
buf[length - 1] = c;
}
return length;
}
static int
PrintString(char * buf, char* s, int length, int ladjust)
{
int i;
int len=0;
char* s1 = s;
while (*s1++) len++;
if (length < len) length = len;
if (ladjust) {
for (i=0; i< len; i++) buf[i] = s[i];
for (i=len; i< length; i++) buf[i] = ' ';
} else {
for (i=0; i< length-len; i++) buf[i] = ' ';
for (i=length-len; i < length; i++) buf[i] = s[i-length+len];
}
return length;
}
static int
PrintNum(char * buf, unsigned long u, int base, int negFlag,
int length, int ladjust, char padc, int upcase)
{
/* algorithm :
* 1. prints the number from left to right in reverse form.
* 2. fill the remaining spaces with padc if length is longer than
* the actual length
* TRICKY : if left adjusted, no "0" padding.
* if negtive, insert "0" padding between "0" and number.
* 3. if (!ladjust) we reverse the whole string including paddings
* 4. otherwise we only reverse the actual string representing the num.
*/
int actualLength =0;
char *p = buf;
int i;
do {
int tmp = u %base;
if (tmp <= 9) {
*p++ = '0' + tmp;
} else if (upcase) {
*p++ = 'A' + tmp - 10;
} else {
*p++ = 'a' + tmp - 10;
}
u /= base;
} while (u != 0);
if (negFlag) {
*p++ = '-';
}
/* figure out actual length and adjust the maximum length */
actualLength = p - buf;
if (length < actualLength) length = actualLength;
/* add padding */
if (ladjust) {
padc = ' ';
}
if (negFlag && !ladjust && (padc == '0')) {
for (i = actualLength-1; i< length-1; i++) buf[i] = padc;
buf[length -1] = '-';
} else {
for (i = actualLength; i< length; i++) buf[i] = padc;
}
/* prepare to reverse the string */
{
int begin = 0;
int end;
if (ladjust) {
end = actualLength - 1;
} else {
end = length -1;
}
while (end > begin) {
char tmp = buf[begin];
buf[begin] = buf[end];
buf[end] = tmp;
begin ++;
end --;
}
}
/* adjust the string pointer */
return length;
}
static void printf_output(void *arg, char *s, int l)
{
int i;
// special termination call
if ((l==1) && (s[0] == '\0')) return;
for (i=0; i< l; i++) {
board_putc(s[i]);
if (s[i] == '\n') board_putc('\r');
}
}
void printf(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
lp_Print(printf_output, 0, fmt, ap);
va_end(ap);
}

View file

@ -0,0 +1,18 @@
/*
* Copyright (C) 2001 MontaVista Software Inc.
* Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#ifndef _printf_h_
#define _printf_h_
#include <stdarg.h>
void printf(char *fmt, ...);
#endif /* _printf_h_ */