From: Mathias Kresin Date: Sat, 13 Nov 2021 13:55:13 +0000 (+0100) Subject: lantiq: bring back okli loader X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=a328b6831c0f1e47e4fd4da4e00c0b9cb53cf2e4;p=openwrt%2Fstaging%2Fmans0n.git lantiq: bring back okli loader Removed due to being unused with 1f7a03a70603, but now required for the ar7 FRITZ!Box. Could be used for the ARV7519RW22 as well, for which the image generation was disabled due to a stock u-boot issue with kernel bigger than 2 MByte. The code is combination of the ath79 and ramips okli loader. Signed-off-by: Mathias Kresin --- diff --git a/target/linux/lantiq/image/lzma-loader/Makefile b/target/linux/lantiq/image/lzma-loader/Makefile new file mode 100644 index 0000000000..b455e6f63d --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/Makefile @@ -0,0 +1,72 @@ +# +# Copyright (C) 2011 OpenWrt.org +# Copyright (C) 2011 Gabor Juhos +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +LZMA_TEXT_START := +LOADADDR := +LOADER := loader.bin +LOADER_NAME := $(basename $(notdir $(LOADER))) +LOADER_DATA := +KERNEL_MAGIC := +TARGET_DIR := +FLASH_START := +FLASH_OFFS := +FLASH_MAX := +BOARD := +PLATFORM := + +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_BUILD_DIR := $(KDIR)/$(PKG_NAME) + +.PHONY : loader-compile loader.bin loader.elf loader.gz + +$(PKG_BUILD_DIR)/.prepared: + mkdir $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ + touch $@ + +loader-compile: $(PKG_BUILD_DIR)/.prepared + $(MAKE) -C $(PKG_BUILD_DIR) CROSS_COMPILE="$(TARGET_CROSS)" \ + LZMA_TEXT_START=$(LZMA_TEXT_START) \ + LOADADDR=$(LOADADDR) \ + LOADER_DATA=$(LOADER_DATA) \ + KERNEL_MAGIC=$(KERNEL_MAGIC) \ + FLASH_START=$(FLASH_START) \ + FLASH_OFFS=$(FLASH_OFFS) \ + FLASH_MAX=$(FLASH_MAX) \ + BOARD="$(BOARD)" \ + PLATFORM="$(PLATFORM)" \ + clean all + +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 +compile: loader-compile + +install: + +clean: + rm -rf $(PKG_BUILD_DIR) + diff --git a/target/linux/lantiq/image/lzma-loader/src/LzmaDecode.c b/target/linux/lantiq/image/lzma-loader/src/LzmaDecode.c new file mode 100644 index 0000000000..cb8345377e --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/src/LzmaDecode.c @@ -0,0 +1,584 @@ +/* + 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; }} + +#ifdef _LZMA_IN_CB + +#define RC_TEST { if (Buffer == BufferLim) \ + { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \ + BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }} + +#define RC_INIT Buffer = BufferLim = 0; RC_INIT2 + +#else + +#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; } + +#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2 + +#endif + +#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; + */ + } + + #ifdef _LZMA_OUT_READ + { + int i; + propsRes->DictionarySize = 0; + for (i = 0; i < 4; i++) + propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8); + if (propsRes->DictionarySize == 0) + propsRes->DictionarySize = 1; + } + #endif + return LZMA_RESULT_OK; +} + +#define kLzmaStreamWasFinishedId (-1) + +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) +{ + 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; + + #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; + UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3]; + int len = vs->RemainLen; + UInt32 globalPos = vs->GlobalPos; + UInt32 distanceLimit = vs->DistanceLimit; + + Byte *dictionary = vs->Dictionary; + UInt32 dictionarySize = vs->Properties.DictionarySize; + UInt32 dictionaryPos = vs->DictionaryPos; + + Byte tempDictionary[4]; + + #ifndef _LZMA_IN_CB + *inSizeProcessed = 0; + #endif + *outSizeProcessed = 0; + if (len == kLzmaStreamWasFinishedId) + return LZMA_RESULT_OK; + + if (dictionarySize == 0) + { + dictionary = tempDictionary; + dictionarySize = 1; + tempDictionary[0] = vs->TempDictionary[0]; + } + + 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; + if (pos >= dictionarySize) + pos += dictionarySize; + outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos]; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + len--; + } + if (dictionaryPos == 0) + previousByte = dictionary[dictionarySize - 1]; + else + previousByte = dictionary[dictionaryPos - 1]; + + #else /* if !_LZMA_OUT_READ */ + + 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; + + #ifndef _LZMA_IN_CB + *inSizeProcessed = 0; + #endif + *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) + { + CProb *prob; + UInt32 bound; + int posState = (int)( + (nowPos + #ifdef _LZMA_OUT_READ + + globalPos + #endif + ) + & posStateMask); + + prob = p + IsMatch + (state << kNumPosBitsMax) + posState; + IfBit0(prob) + { + int symbol = 1; + UpdateBit0(prob) + prob = p + Literal + (LZMA_LIT_SIZE * + ((( + (nowPos + #ifdef _LZMA_OUT_READ + + globalPos + #endif + ) + & literalPosMask) << lc) + (previousByte >> (8 - lc)))); + + if (state >= kNumLitStates) + { + int matchByte; + #ifdef _LZMA_OUT_READ + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + matchByte = dictionary[pos]; + #else + matchByte = outStream[nowPos - rep0]; + #endif + 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; + #ifdef _LZMA_OUT_READ + if (distanceLimit < dictionarySize) + distanceLimit++; + + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #endif + 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) + { + #ifdef _LZMA_OUT_READ + UInt32 pos; + #endif + UpdateBit0(prob); + + #ifdef _LZMA_OUT_READ + if (distanceLimit == 0) + #else + if (nowPos == 0) + #endif + return LZMA_RESULT_DATA_ERROR; + + state = state < kNumLitStates ? 9 : 11; + #ifdef _LZMA_OUT_READ + pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + previousByte = dictionary[pos]; + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #else + previousByte = outStream[nowPos - rep0]; + #endif + outStream[nowPos++] = previousByte; + #ifdef _LZMA_OUT_READ + if (distanceLimit < dictionarySize) + distanceLimit++; + #endif + + 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; + #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 + { + #ifdef _LZMA_OUT_READ + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + previousByte = dictionary[pos]; + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #else + previousByte = outStream[nowPos - rep0]; + #endif + len--; + outStream[nowPos++] = previousByte; + } + while(len != 0 && nowPos < outSize); + } + } + RC_NORMALIZE; + + #ifdef _LZMA_OUT_READ + vs->Range = Range; + vs->Code = Code; + vs->DictionaryPos = dictionaryPos; + vs->GlobalPos = globalPos + (UInt32)nowPos; + vs->DistanceLimit = distanceLimit; + vs->Reps[0] = rep0; + vs->Reps[1] = rep1; + vs->Reps[2] = rep2; + vs->Reps[3] = rep3; + vs->State = state; + vs->RemainLen = len; + vs->TempDictionary[0] = tempDictionary[0]; + #endif + + #ifdef _LZMA_IN_CB + vs->Buffer = Buffer; + vs->BufferLim = BufferLim; + #else + *inSizeProcessed = (SizeT)(Buffer - inStream); + #endif + *outSizeProcessed = nowPos; + return LZMA_RESULT_OK; +} diff --git a/target/linux/lantiq/image/lzma-loader/src/LzmaDecode.h b/target/linux/lantiq/image/lzma-loader/src/LzmaDecode.h new file mode 100644 index 0000000000..2870eeb9c9 --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/src/LzmaDecode.h @@ -0,0 +1,113 @@ +/* + 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 + +#include "LzmaTypes.h" + +/* #define _LZMA_IN_CB */ +/* Use callback for input data */ + +/* #define _LZMA_OUT_READ */ +/* Use read function for output data */ + +/* #define _LZMA_PROB32 */ +/* It can increase speed on some 32-bit CPUs, + but memory usage will be doubled in that case */ + +/* #define _LZMA_LOC_OPT */ +/* Enable local speed optimizations inside code */ + +#ifdef _LZMA_PROB32 +#define CProb UInt32 +#else +#define CProb UInt16 +#endif + +#define LZMA_RESULT_OK 0 +#define LZMA_RESULT_DATA_ERROR 1 + +#ifdef _LZMA_IN_CB +typedef struct _ILzmaInCallback +{ + int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize); +} ILzmaInCallback; +#endif + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +#define LZMA_PROPERTIES_SIZE 5 + +typedef struct _CLzmaProperties +{ + 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 +#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; } +#endif + +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); + +#endif diff --git a/target/linux/lantiq/image/lzma-loader/src/LzmaTypes.h b/target/linux/lantiq/image/lzma-loader/src/LzmaTypes.h new file mode 100644 index 0000000000..9c27290757 --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/src/LzmaTypes.h @@ -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 */ + +#ifndef _7ZIP_SIZET_DEFINED +#define _7ZIP_SIZET_DEFINED +#ifdef _LZMA_NO_SYSTEM_SIZE_T +typedef UInt32 SizeT; +#else +#include +typedef size_t SizeT; +#endif +#endif + +#endif diff --git a/target/linux/lantiq/image/lzma-loader/src/Makefile b/target/linux/lantiq/image/lzma-loader/src/Makefile new file mode 100644 index 0000000000..d3f6ca4049 --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/src/Makefile @@ -0,0 +1,125 @@ +# +# Makefile for the LZMA compressed kernel loader for +# Atheros AR7XXX/AR9XXX based boards +# +# Copyright (C) 2011 Gabor Juhos +# +# Some parts of this file 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 +# Copyright (C) 2005 by Oleg I. Vdovikin +# +# 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. +# + +LOADADDR := +LZMA_TEXT_START := +LOADER_DATA := +KERNEL_MAGIC := +BOARD := +FLASH_START := +FLASH_OFFS := +FLASH_MAX := +PLATFORM := +CACHE_FLAGS := + +CC := $(CROSS_COMPILE)gcc +LD := $(CROSS_COMPILE)ld +OBJCOPY := $(CROSS_COMPILE)objcopy +OBJDUMP := $(CROSS_COMPILE)objdump +include $(PLATFORM).mk + +BIN_FLAGS := -O binary -R .reginfo -R .note -R .comment -R .mdebug \ + -R .MIPS.abiflags -S + +CFLAGS = -D__KERNEL__ -Wall -Wstrict-prototypes -Wno-trigraphs -Os \ + -fno-strict-aliasing -fno-common -fomit-frame-pointer -G 0 \ + -mno-abicalls -fno-pic -ffunction-sections -pipe -mlong-calls \ + -fno-common -ffreestanding -fhonour-copts -nostartfiles \ + -mabi=32 -march=mips32r2 \ + -Wa,-32 -Wa,-march=mips32r2 -Wa,-mips32r2 -Wa,--trap +CFLAGS += -D_LZMA_PROB32 +CFLAGS += -DARCH=$(PLATFORM) +CFLAGS += -flto + +ASFLAGS = $(CFLAGS) -D__ASSEMBLY__ + +LDFLAGS = -static -Wl,--gc-sections -Wl,-no-warn-mismatch +LDFLAGS += -Wl,-e,startup -T loader.lds -Wl,-Ttext,$(LZMA_TEXT_START) +LDFLAGS += -flto -fwhole-program + +O_FORMAT = $(shell $(OBJDUMP) -i | head -2 | grep elf32) + +OBJECTS := head.o loader.o cache.o board-$(PLATFORM).o printf.o LzmaDecode.o + +include $(PLATFORM).mk +CFLAGS+=$(CACHE_FLAGS) +ASFLAGS+=$(CACHE_FLAGS) + +ifneq ($(strip $(LOADER_DATA)),) +OBJECTS += data.o +CFLAGS += -DLZMA_WRAPPER=1 -DLOADADDR=$(LOADADDR) +endif + +ifneq ($(strip $(KERNEL_MAGIC)),) +CFLAGS += -DCONFIG_KERNEL_MAGIC=$(KERNEL_MAGIC) +endif + +ifneq ($(strip $(KERNEL_CMDLINE)),) +CFLAGS += -DCONFIG_KERNEL_CMDLINE='"$(KERNEL_CMDLINE)"' +endif + +ifneq ($(strip $(FLASH_START)),) +CFLAGS += -DCONFIG_FLASH_START=$(FLASH_START) +endif +ifneq ($(strip $(FLASH_OFFS)),) +CFLAGS += -DCONFIG_FLASH_OFFS=$(FLASH_OFFS) +endif + +ifneq ($(strip $(FLASH_MAX)),) +CFLAGS += -DCONFIG_FLASH_MAX=$(FLASH_MAX) +endif + +BOARD_DEF := $(shell echo $(strip $(BOARD)) | tr a-z A-Z | tr - _) +ifneq ($(BOARD_DEF),) +CFLAGS += -DCONFIG_BOARD_$(BOARD_DEF) +endif + +all: loader.elf + +# Don't build dependencies, this may die if $(CC) isn't gcc +dep: + +install: + +%.o : %.c + $(CC) $(CFLAGS) -c -o $@ $< + +%.o : %.S + $(CC) $(ASFLAGS) -c -o $@ $< + +data.o: $(LOADER_DATA) + $(LD) -r -b binary --oformat $(O_FORMAT) -T lzma-data.lds -o $@ $< + +loader: $(OBJECTS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) + +loader.bin: loader + $(OBJCOPY) $(BIN_FLAGS) $< $@ + +loader2.o: loader.bin + $(LD) -r -b binary --oformat $(O_FORMAT) -o $@ $< + +loader.elf: loader2.o + $(LD) -z max-page-size=0x1000 -e startup -T loader2.lds -Ttext $(LOADADDR) -o $@ $< + +mrproper: clean + +clean: + rm -f loader *.elf *.bin *.o + + + diff --git a/target/linux/lantiq/image/lzma-loader/src/board-lantiq.c b/target/linux/lantiq/image/lzma-loader/src/board-lantiq.c new file mode 100644 index 0000000000..b1b4373493 --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/src/board-lantiq.c @@ -0,0 +1,33 @@ +/* + * Arch specific code for Lantiq based boards + * + * Copyright (C) 2013 John Crispin + * + * 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 +#include "config.h" + +#define READREG(r) *(volatile unsigned int *)(r) +#define WRITEREG(r,v) *(volatile unsigned int *)(r) = v + +#define UART_BASE 0xbe100c00 +#define ASC_TBUF (UART_BASE | 0x20) +#define ASC_FSTAT (UART_BASE | 0x48) + +#define TXMASK 0x3F00 +#define TXOFFSET 8 + +void board_putc(char c) +{ + while ((READREG(ASC_FSTAT) & TXMASK) >> TXOFFSET); + + WRITEREG(ASC_TBUF, c); +} + +void board_init(void) +{ +} diff --git a/target/linux/lantiq/image/lzma-loader/src/cache.c b/target/linux/lantiq/image/lzma-loader/src/cache.c new file mode 100644 index 0000000000..28cc848333 --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/src/cache.c @@ -0,0 +1,43 @@ +/* + * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards + * + * Copyright (C) 2011 Gabor Juhos + * + * The cache manipulation routine has been taken from the U-Boot project. + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, + * + * 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" + +#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 - 1) & ~(lsize - 1); + + while (1) { + cache_op(Hit_Writeback_Inv_D, addr); + cache_op(Hit_Invalidate_I, addr); + if (addr == aend) + break; + addr += lsize; + } +} diff --git a/target/linux/lantiq/image/lzma-loader/src/cache.h b/target/linux/lantiq/image/lzma-loader/src/cache.h new file mode 100644 index 0000000000..506a235884 --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/src/cache.h @@ -0,0 +1,17 @@ +/* + * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards + * + * Copyright (C) 2011 Gabor Juhos + * + * 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 */ diff --git a/target/linux/lantiq/image/lzma-loader/src/cacheops.h b/target/linux/lantiq/image/lzma-loader/src/cacheops.h new file mode 100644 index 0000000000..70bcad7694 --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/src/cacheops.h @@ -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 */ diff --git a/target/linux/lantiq/image/lzma-loader/src/config.h b/target/linux/lantiq/image/lzma-loader/src/config.h new file mode 100644 index 0000000000..b7719e9ca8 --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/src/config.h @@ -0,0 +1,27 @@ +/* + * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards + * + * Copyright (C) 2011 Gabor Juhos + * + * 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_ + +#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_ */ diff --git a/target/linux/lantiq/image/lzma-loader/src/cp0regdef.h b/target/linux/lantiq/image/lzma-loader/src/cp0regdef.h new file mode 100644 index 0000000000..c1188ad8c8 --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/src/cp0regdef.h @@ -0,0 +1,39 @@ +/* + * 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 + +#endif diff --git a/target/linux/lantiq/image/lzma-loader/src/head.S b/target/linux/lantiq/image/lzma-loader/src/head.S new file mode 100644 index 0000000000..d414b14d11 --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/src/head.S @@ -0,0 +1,134 @@ +/* + * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards + * + * Copyright (C) 2011 Gabor Juhos + * + * 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 + * + * 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 +#include +#include "cp0regdef.h" +#include "cacheops.h" +#include "config.h" + +#define KSEG0 0x80000000 + + .macro ehb + sll zero, 3 + .endm + + .text + +LEAF(startup) + .set noreorder + .set mips32 + + mtc0 zero, CP0_WATCHLO # clear watch registers + mtc0 zero, CP0_WATCHHI + mtc0 zero, CP0_CAUSE # clear before writing status register + + mfc0 t0, CP0_STATUS + li t1, 0x1000001f + or t0, t1 + xori t0, 0x1f + mtc0 t0, CP0_STATUS + ehb + + /* + * Some bootloaders set the 'Kseg0 coherency algorithm' to + * 'Cacheable, noncoherent, write-through, no write allocate' + * and this cause performance issues. Let's go and change it to + * 'Cacheable, noncoherent, write-back, write allocate' + */ + mfc0 t0, CP0_CONFIG + li t1, ~7 #~CONF_CM_CMASK + and t0, t1 + ori t0, 3 #CONF_CM_CACHABLE_NONCOHERENT + mtc0 t0, CP0_CONFIG + nop + + 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 + + /* Copy our code to the right place */ + la t1, _code_start # get linked address of _code_start + la t2, _code_end # get linked address of _code_end + addu t0, t0, t1 # calculate actual address of _code_start + +__reloc_copy: + lw t3, 0(t0) + sw t3, 0(t1) + add t1, 4 + blt t1, t2, __reloc_copy + add t0, 4 + + /* flush cache */ + la t0, _code_start + la t1, _code_end + + li t2, ~(CONFIG_CACHELINE_SIZE - 1) + and t0, t2 + and t1, t2 + li t2, CONFIG_CACHELINE_SIZE + + b __flush_check + nop + +__flush_line: + cache Hit_Writeback_Inv_D, 0(t0) + cache Hit_Invalidate_I, 0(t0) + add t0, t2 + +__flush_check: + bne t0, t1, __flush_line + nop + + sync + +__reloc_done: + + /* clear bss */ + la t0, _bss_start + la t1, _bss_end + b __bss_check + nop + +__bss_fill: + sw zero, 0(t0) + addi t0, 4 + +__bss_check: + bne t0, t1, __bss_fill + nop + + /* Setup new "C" stack */ + la sp, _stack + + /* reserve stack space for a0-a3 registers */ + subu sp, 16 + + /* jump to the decompressor routine */ + la t0, loader_main + jr t0 + nop + + .set reorder +END(startup) diff --git a/target/linux/lantiq/image/lzma-loader/src/lantiq.mk b/target/linux/lantiq/image/lzma-loader/src/lantiq.mk new file mode 100644 index 0000000000..413764593b --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/src/lantiq.mk @@ -0,0 +1 @@ +CACHE_FLAGS+=-DCONFIG_ICACHE_SIZE="(32 * 1024)" -DCONFIG_DCACHE_SIZE="(32 * 1024)" -DCONFIG_CACHELINE_SIZE=32 diff --git a/target/linux/lantiq/image/lzma-loader/src/loader.c b/target/linux/lantiq/image/lzma-loader/src/loader.c new file mode 100644 index 0000000000..7881b84b26 --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/src/loader.c @@ -0,0 +1,266 @@ +/* + * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards + * + * Copyright (C) 2011 Gabor Juhos + * + * 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 + * Copyright (C) 2005 by Oleg I. Vdovikin + * + * 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 +#include + +#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 + +#define IH_MAGIC_OKLI 0x4f4b4c49 /* 'OKLI' */ + +#define IH_NMLEN 32 /* Image Name Length */ + +typedef struct image_header { + uint32_t ih_magic; /* Image Header Magic Number */ + uint32_t ih_hcrc; /* Image Header CRC Checksum */ + uint32_t ih_time; /* Image Creation Timestamp */ + uint32_t ih_size; /* Image Data Size */ + uint32_t ih_load; /* Data Load Address */ + uint32_t ih_ep; /* Entry Point Address */ + uint32_t ih_dcrc; /* Image Data CRC Checksum */ + uint8_t ih_os; /* Operating System */ + uint8_t ih_arch; /* CPU architecture */ + uint8_t ih_type; /* Image Type */ + uint8_t ih_comp; /* Compression Type */ + uint8_t ih_name[IH_NMLEN]; /* Image Name */ +} image_header_t; + +/* 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; + +#ifdef CONFIG_KERNEL_CMDLINE +#define kernel_argc 2 +static const char kernel_cmdline[] = CONFIG_KERNEL_CMDLINE; +static const char *const kernel_argv[] = { + NULL, + kernel_cmdline, + NULL, +}; +#endif /* CONFIG_KERNEL_CMDLINE */ + +static void halt(void) +{ + printf("\nSystem halted!\n"); + for(;;); +} + +static __inline__ unsigned long get_be32(void *buf) +{ + unsigned char *p = buf; + + return (((unsigned long) p[0] << 24) + + ((unsigned long) p[1] << 16) + + ((unsigned long) p[2] << 8) + + (unsigned long) p[3]); +} + +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; +} + +#if (LZMA_WRAPPER) +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; +} +#else +static void lzma_init_data(void) +{ + struct image_header *hdr = NULL; + unsigned char *flash_base; + unsigned long flash_ofs; + unsigned long kernel_ofs; + unsigned long kernel_size; + + flash_base = (unsigned char *) KSEG1ADDR(CONFIG_FLASH_START); + + printf("Looking for OpenWrt image... "); + + for (flash_ofs = CONFIG_FLASH_OFFS; + flash_ofs <= (CONFIG_FLASH_OFFS + CONFIG_FLASH_MAX); + flash_ofs += CONFIG_FLASH_STEP) { + unsigned long magic; + unsigned char *p; + + p = flash_base + flash_ofs; + magic = get_be32(p); +#ifdef CONFIG_KERNEL_MAGIC + if (magic == CONFIG_KERNEL_MAGIC) { +#else + if (magic == IH_MAGIC_OKLI) { +#endif + hdr = (struct image_header *) p; + break; + } + } + + if (hdr == NULL) { + printf("not found!\n"); + halt(); + } + + printf("found at 0x%08x\n", flash_base + flash_ofs); + + kernel_ofs = sizeof(struct image_header); + kernel_size = get_be32(&hdr->ih_size); + kernel_la = get_be32(&hdr->ih_load); + + lzma_data = flash_base + flash_ofs + kernel_ofs; + lzma_datasize = kernel_size; +} +#endif /* (LZMA_WRAPPER) */ + +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 MIPS based SoC\n"); + printf("Copyright (C) 2011 Gabor Juhos \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); + +#ifdef CONFIG_KERNEL_CMDLINE + reg_a0 = kernel_argc; + reg_a1 = (unsigned long) kernel_argv; + reg_a2 = 0; + reg_a3 = 0; +#endif + + kernel_entry = (void *) kernel_la; + kernel_entry(reg_a0, reg_a1, reg_a2, reg_a3); +} diff --git a/target/linux/lantiq/image/lzma-loader/src/loader.lds b/target/linux/lantiq/image/lzma-loader/src/loader.lds new file mode 100644 index 0000000000..01ff852361 --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/src/loader.lds @@ -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 = .; +} diff --git a/target/linux/lantiq/image/lzma-loader/src/loader2.lds b/target/linux/lantiq/image/lzma-loader/src/loader2.lds new file mode 100644 index 0000000000..db0bb46424 --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/src/loader2.lds @@ -0,0 +1,10 @@ +OUTPUT_ARCH(mips) +SECTIONS { + .text : { + startup = .; + *(.text) + *(.text.*) + *(.data) + *(.data.*) + } +} diff --git a/target/linux/lantiq/image/lzma-loader/src/lzma-data.lds b/target/linux/lantiq/image/lzma-loader/src/lzma-data.lds new file mode 100644 index 0000000000..abf756ba13 --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/src/lzma-data.lds @@ -0,0 +1,8 @@ +OUTPUT_ARCH(mips) +SECTIONS { + .data.lzma : { + _lzma_data_start = .; + *(.data) + _lzma_data_end = .; + } +} diff --git a/target/linux/lantiq/image/lzma-loader/src/printf.c b/target/linux/lantiq/image/lzma-loader/src/printf.c new file mode 100644 index 0000000000..7bb5a86e18 --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/src/printf.c @@ -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); +} diff --git a/target/linux/lantiq/image/lzma-loader/src/printf.h b/target/linux/lantiq/image/lzma-loader/src/printf.h new file mode 100644 index 0000000000..9b1c1df232 --- /dev/null +++ b/target/linux/lantiq/image/lzma-loader/src/printf.h @@ -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 +void printf(char *fmt, ...); + +#endif /* _printf_h_ */