brcm63xx: add working lzma-loader and use it for initramfs
authorjogo <jogo@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Fri, 1 Aug 2014 21:56:31 +0000 (21:56 +0000)
committerjogo <jogo@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Fri, 1 Aug 2014 21:56:31 +0000 (21:56 +0000)
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>
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@41940 3c298f89-4303-0410-b956-a3cf2f4a3e73

23 files changed:
target/linux/brcm63xx/image/Makefile
target/linux/brcm63xx/image/lzma-loader/Makefile
target/linux/brcm63xx/image/lzma-loader/src/LzmaDecode.c
target/linux/brcm63xx/image/lzma-loader/src/LzmaDecode.h
target/linux/brcm63xx/image/lzma-loader/src/LzmaTypes.h [new file with mode: 0644]
target/linux/brcm63xx/image/lzma-loader/src/Makefile
target/linux/brcm63xx/image/lzma-loader/src/README [deleted file]
target/linux/brcm63xx/image/lzma-loader/src/board.c [new file with mode: 0644]
target/linux/brcm63xx/image/lzma-loader/src/cache.c [new file with mode: 0644]
target/linux/brcm63xx/image/lzma-loader/src/cache.h [new file with mode: 0644]
target/linux/brcm63xx/image/lzma-loader/src/cacheops.h [new file with mode: 0644]
target/linux/brcm63xx/image/lzma-loader/src/config.h [new file with mode: 0644]
target/linux/brcm63xx/image/lzma-loader/src/cp0regdef.h [new file with mode: 0644]
target/linux/brcm63xx/image/lzma-loader/src/decompress.c [deleted file]
target/linux/brcm63xx/image/lzma-loader/src/decompress.lds.in [deleted file]
target/linux/brcm63xx/image/lzma-loader/src/head.S
target/linux/brcm63xx/image/lzma-loader/src/loader.c [new file with mode: 0644]
target/linux/brcm63xx/image/lzma-loader/src/loader.lds [new file with mode: 0644]
target/linux/brcm63xx/image/lzma-loader/src/loader.lds.in [deleted file]
target/linux/brcm63xx/image/lzma-loader/src/loader2.lds [new file with mode: 0644]
target/linux/brcm63xx/image/lzma-loader/src/lzma-data.lds [new file with mode: 0644]
target/linux/brcm63xx/image/lzma-loader/src/printf.c [new file with mode: 0644]
target/linux/brcm63xx/image/lzma-loader/src/printf.h [new file with mode: 0644]

index 781425f..807eebf 100755 (executable)
@@ -143,9 +143,25 @@ define Build/Clean
        $(MAKE) -C lzma-loader clean
 endef
 
-define Image/Prepare
+define Image/PrepareLoader
        # 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!
        # 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
        rm -f $(KDIR)/vmlinux.lzma.tmp
 
-       # Build the LZMA loader
-       rm -f $(KDIR)/loader.gz
-       $(MAKE) -C lzma-loader \
-               BUILD_DIR="$(KDIR)" \
-               TARGET="$(KDIR)" \
-               clean install
-
-       echo -ne "\\x00" >> $(KDIR)/loader.gz
+ ifeq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),y)
+       $(call Image/PrepareLoader,-initramfs)
+ endif
        rm -f $(KDIR)/fs_mark
        touch $(KDIR)/fs_mark
        $(call prepare_generic_squashfs,$(KDIR)/fs_mark)
index 5dd6f50..8d36691 100644 (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.
 # See /LICENSE for more information.
@@ -7,27 +8,55 @@
 
 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_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:
        mkdir $(PKG_BUILD_DIR)
        $(CP) ./src/* $(PKG_BUILD_DIR)/
        touch $@
 
-$(PKG_BUILD_DIR)/loader.gz: $(PKG_BUILD_DIR)/.prepared
-       $(MAKE) -C $(PKG_BUILD_DIR) CC="$(TARGET_CC)" \
-               LD="$(TARGET_CROSS)ld" CROSS_COMPILE="$(TARGET_CROSS)"
+loader-compile: $(PKG_BUILD_DIR)/.prepared
+       $(MAKE) -C $(PKG_BUILD_DIR) CROSS_COMPILE="$(TARGET_CROSS)" \
+               LZMA_TEXT_START=$(LZMA_TEXT_START) \
+               LOADER_DATA=$(LOADER_DATA) \
+               FLASH_OFFS=$(FLASH_OFFS) \
+               FLASH_MAX=$(FLASH_MAX) \
+               clean all
+
+loader.gz: $(PKG_BUILD_DIR)/loader.bin
+       gzip -nc9 $< > $(LOADER_GZ)
 
-download: 
+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: $(PKG_BUILD_DIR)/loader.gz
-install:
+compile: loader-compile
 
-ifneq ($(TARGET),)
-install: compile
-       $(CP) $(PKG_BUILD_DIR)/loader.gz $(PKG_BUILD_DIR)/loader.elf $(TARGET)/
-endif
+install:
 
 clean:
        rm -rf $(PKG_BUILD_DIR)
+
index 951700b..cb83453 100644 (file)
@@ -1,8 +1,8 @@
 /*
   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/
 
   LZMA SDK is licensed under two licenses:
   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 
+  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"
 
-#ifndef Byte
-#define Byte unsigned char
-#endif
-
 #define kNumTopBits 24
 #define kTopValue ((UInt32)1 << kNumTopBits)
 
 #define kBitModelTotal (1 << kNumBitModelTotalBits)
 #define kNumMoveBits 5
 
-typedef struct _CRangeDecoder
-{
-  Byte *Buffer;
-  Byte *BufferLim;
-  UInt32 Range;
-  UInt32 Code;
-  #ifdef _LZMA_IN_CB
-  ILzmaInCallback *InCallback;
-  int Result;
-  #endif
-  int ExtraBytes;
-} CRangeDecoder;
-
-Byte RangeDecoderReadByte(CRangeDecoder *rd)
-{
-  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 RC_READ_BYTE (*Buffer++)
 
-/* #define ReadByte (*rd->Buffer++) */
-#define ReadByte (RangeDecoderReadByte(rd))
+#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
+  { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
 
-void RangeDecoderInit(CRangeDecoder *rd,
-  #ifdef _LZMA_IN_CB
-    ILzmaInCallback *inCallback
-  #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;
-}
+#ifdef _LZMA_IN_CB
 
-#define RC_INIT_VAR UInt32 range = rd->Range; UInt32 code = rd->Code;        
-#define RC_FLUSH_VAR rd->Range = range; rd->Code = code;
-#define RC_NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | ReadByte; }
+#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; }}
 
-UInt32 RangeDecoderDecodeDirectBits(CRangeDecoder *rd, int numTotalBits)
-{
-  RC_INIT_VAR
-  UInt32 result = 0;
-  int i;
-  for (i = numTotalBits; i > 0; i--)
-  {
-    /* UInt32 t; */
-    range >>= 1;
+#define RC_INIT Buffer = BufferLim = 0; RC_INIT2
 
-    result <<= 1;
-    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;
-}
+#else
 
-int RangeDecoderBitDecode(CProb *prob, CRangeDecoder *rd)
-{
-  UInt32 bound = (rd->Range >> kNumBitModelTotalBits) * *prob;
-  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_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
 
-#define RC_GET_BIT2(prob, mi, A0, A1) \
-  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_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
+#endif
 
-#define RC_GET_BIT(prob, mi) RC_GET_BIT2(prob, mi, ; , ;)               
+#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
 
-int RangeDecoderBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
-{
-  int mi = 1;
-  int i;
-  #ifdef _LZMA_LOC_OPT
-  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);
-}
+#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 RangeDecoderReverseBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
-{
-  int mi = 1;
-  int i;
-  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;
-}
+#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, ; , ;)               
 
-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;
-}
+#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); }
 
-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 kNumPosStatesMax (1 << kNumPosBitsMax)
@@ -286,19 +84,9 @@ Byte LzmaLiteralDecodeMatch(CProb *probs, CRangeDecoder *rd, Byte matchByte)
 #define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
 #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 kNumLitStates 7
 
 #define kStartPosModelIndex 4
 #define kEndPosModelIndex 14
@@ -329,94 +117,115 @@ int LzmaLenDecode(CProb *p, CRangeDecoder *rd, int posState)
 StopCompilingDueBUG
 #endif
 
-#ifdef _LZMA_OUT_READ
-
-typedef struct _LzmaVarState
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
 {
-  CRangeDecoder RangeDecoder;
-  Byte *Dictionary;
-  UInt32 DictionarySize;
-  UInt32 DictionaryPos;
-  UInt32 GlobalPos;
-  UInt32 Reps[4];
-  int lc;
-  int lp;
-  int pb;
-  int State;
-  int PreviousIsMatch;
-  int RemainLen;
-} LzmaVarState;
-
-int LzmaDecoderInit(
-    unsigned char *buffer, UInt32 bufferSize,
-    int lc, int lp, int pb,
-    unsigned char *dictionary, UInt32 dictionarySize,
+  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
+    ILzmaInCallback *InCallback,
     #else
-    unsigned char *inStream, UInt32 inSize
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
     #endif
-    )
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
 {
-  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;
-}
+  CProb *p = vs->Probs;
+  SizeT nowPos = 0;
+  Byte previousByte = 0;
+  UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+  UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+  int lc = vs->Properties.lc;
 
-int LzmaDecode(unsigned char *buffer, 
-    unsigned char *outStream, UInt32 outSize,
-    UInt32 *outSizeProcessed)
-{
-  LzmaVarState *vs = (LzmaVarState *)buffer;
-  CProb *p = (CProb *)(buffer + sizeof(LzmaVarState));
-  CRangeDecoder rd = vs->RangeDecoder;
+  #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 previousIsMatch = vs->PreviousIsMatch;
-  Byte previousByte;
   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;
   UInt32 globalPos = vs->GlobalPos;
+  UInt32 distanceLimit = vs->DistanceLimit;
 
   Byte *dictionary = vs->Dictionary;
-  UInt32 dictionarySize = vs->DictionarySize;
+  UInt32 dictionarySize = vs->Properties.DictionarySize;
   UInt32 dictionaryPos = vs->DictionaryPos;
 
-  if (len == -1)
-  {
-    *outSizeProcessed = 0;
+  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];
   }
 
-  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;
     if (pos >= dictionarySize)
@@ -430,47 +239,41 @@ int LzmaDecode(unsigned char *buffer,
     previousByte = dictionary[dictionarySize - 1];
   else
     previousByte = dictionary[dictionaryPos - 1];
-#else
 
-int LzmaDecode(
-    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;
+  #else /* if !_LZMA_OUT_READ */
+
   int state = 0;
-  int previousIsMatch = 0;
-  Byte previousByte = 0;
   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;
-  if (bufferSize < numProbs * sizeof(CProb))
-    return LZMA_RESULT_NOT_ENOUGH_MEM;
-  for (i = 0; i < numProbs; i++)
-    p[i] = kBitModelTotal >> 1; 
-  RangeDecoderInit(&rd, 
-      #ifdef _LZMA_IN_CB
-      inCallback
-      #else
-      inStream, inSize
-      #endif
-      );
-#endif
+  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
@@ -478,15 +281,13 @@ int LzmaDecode(
         #endif
         )
         & posStateMask);
-    #ifdef _LZMA_IN_CB
-    if (rd.Result != LZMA_RESULT_OK)
-      return rd.Result;
-    #endif
-    if (rd.ExtraBytes != 0)
-      return LZMA_RESULT_DATA_ERROR;
-    if (RangeDecoderBitDecode(p + IsMatch + (state << kNumPosBitsMax) + posState, &rd) == 0)
+
+    prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+    IfBit0(prob)
     {
-      CProb *probs = p + Literal + (LZMA_LIT_SIZE * 
+      int symbol = 1;
+      UpdateBit0(prob)
+      prob = p + Literal + (LZMA_LIT_SIZE * 
         (((
         (nowPos 
         #ifdef _LZMA_OUT_READ
@@ -495,12 +296,9 @@ int LzmaDecode(
         )
         & literalPosMask) << lc) + (previousByte >> (8 - lc))));
 
-      if (state < 4) state = 0;
-      else if (state < 10) state -= 3;
-      else state -= 6;
-      if (previousIsMatch)
+      if (state >= kNumLitStates)
       {
-        Byte matchByte;
+        int matchByte;
         #ifdef _LZMA_OUT_READ
         UInt32 pos = dictionaryPos - rep0;
         if (pos >= dictionarySize)
@@ -509,39 +307,73 @@ int LzmaDecode(
         #else
         matchByte = outStream[nowPos - rep0];
         #endif
-        previousByte = LzmaLiteralDecodeMatch(probs, &rd, matchByte);
-        previousIsMatch = 0;
+        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);
       }
-      else
-        previousByte = LzmaLiteralDecode(probs, &rd);
+      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             
     {
-      previousIsMatch = 1;
-      if (RangeDecoderBitDecode(p + IsRep + state, &rd) == 1)
+      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
       {
-        if (RangeDecoderBitDecode(p + IsRepG0 + state, &rd) == 0)
+        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
             UInt32 pos;
             #endif
-            if (
-               (nowPos 
-                #ifdef _LZMA_OUT_READ
-                + globalPos
-                #endif
-               )
-               == 0)
+            UpdateBit0(prob);
+            
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit == 0)
+            #else
+            if (nowPos == 0)
+            #endif
               return LZMA_RESULT_DATA_ERROR;
-            state = state < 7 ? 9 : 11;
+            
+            state = state < kNumLitStates ? 9 : 11;
             #ifdef _LZMA_OUT_READ
             pos = dictionaryPos - rep0;
             if (pos >= dictionarySize)
@@ -554,20 +386,40 @@ int LzmaDecode(
             previousByte = outStream[nowPos - rep0];
             #endif
             outStream[nowPos++] = previousByte;
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit < dictionarySize)
+              distanceLimit++;
+            #endif
+
             continue;
           }
+          else
+          {
+            UpdateBit1(prob);
+          }
         }
         else
         {
           UInt32 distance;
-          if(RangeDecoderBitDecode(p + IsRepG1 + state, &rd) == 0)
+          UpdateBit1(prob);
+          prob = p + IsRepG1 + state;
+          IfBit0(prob)
+          {
+            UpdateBit0(prob);
             distance = rep1;
+          }
           else 
           {
-            if(RangeDecoderBitDecode(p + IsRepG2 + state, &rd) == 0)
+            UpdateBit1(prob);
+            prob = p + IsRepG2 + state;
+            IfBit0(prob)
+            {
+              UpdateBit0(prob);
               distance = rep2;
+            }
             else
             {
+              UpdateBit1(prob);
               distance = rep3;
               rep3 = rep2;
             }
@@ -576,55 +428,115 @@ int LzmaDecode(
           rep1 = rep0;
           rep0 = distance;
         }
-        len = LzmaLenDecode(p + RepLenCoder, &rd, posState);
-        state = state < 7 ? 8 : 11;
+        state = state < kNumLitStates ? 8 : 11;
+        prob = p + RepLenCoder;
       }
-      else
+      {
+        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;
-        rep3 = rep2;
-        rep2 = rep1;
-        rep1 = rep0;
-        state = state < 7 ? 7 : 10;
-        len = LzmaLenDecode(p + LenCoder, &rd, posState);
-        posSlot = RangeDecoderBitTreeDecode(p + PosSlot +
+        state += kNumLitStates;
+        prob = p + PosSlot +
             ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 
-            kNumPosSlotBits), kNumPosSlotBits, &rd);
+            kNumPosSlotBits);
+        RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
         if (posSlot >= kStartPosModelIndex)
         {
           int numDirectBits = ((posSlot >> 1) - 1);
-          rep0 = ((2 | ((UInt32)posSlot & 1)) << numDirectBits);
+          rep0 = (2 | ((UInt32)posSlot & 1));
           if (posSlot < kEndPosModelIndex)
           {
-            rep0 += RangeDecoderReverseBitTreeDecode(
-                p + SpecPos + rep0 - posSlot - 1, numDirectBits, &rd);
+            rep0 <<= numDirectBits;
+            prob = p + SpecPos + rep0 - posSlot - 1;
           }
           else
           {
-            rep0 += RangeDecoderDecodeDirectBits(&rd, 
-                numDirectBits - kNumAlignBits) << kNumAlignBits;
-            rep0 += RangeDecoderReverseBitTreeDecode(p + Align, kNumAlignBits, &rd);
+            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;
-        rep0++;
-      }
-      if (rep0 == (UInt32)(0))
-      {
-        /* it's for stream version */
-        len = -1;
-        break;
-      }
-      if (rep0 > nowPos 
-        #ifdef _LZMA_OUT_READ
-        + globalPos
-        #endif
-        )
-      {
-        return LZMA_RESULT_DATA_ERROR;
+        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
@@ -638,26 +550,35 @@ int LzmaDecode(
         #else
         previousByte = outStream[nowPos - rep0];
         #endif
-        outStream[nowPos++] = previousByte;
         len--;
+        outStream[nowPos++] = previousByte;
       }
-      while(len > 0 && nowPos < outSize);
+      while(len != 0 && nowPos < outSize);
     }
   }
+  RC_NORMALIZE;
 
   #ifdef _LZMA_OUT_READ
-  vs->RangeDecoder = rd;
+  vs->Range = Range;
+  vs->Code = Code;
   vs->DictionaryPos = dictionaryPos;
-  vs->GlobalPos = globalPos + nowPos;
+  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->PreviousIsMatch = previousIsMatch;
   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;
 }
index f58944e..2870eeb 100644 (file)
@@ -2,7 +2,7 @@
   LzmaDecode.h
   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/
 
   LZMA SDK is licensed under two licenses:
@@ -22,6 +22,8 @@
 #ifndef __LZMADECODE_H
 #define __LZMADECODE_H
 
+#include "LzmaTypes.h"
+
 /* #define _LZMA_IN_CB */
 /* Use callback for input data */
 
 /* #define _LZMA_LOC_OPT */
 /* 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
 #define CProb UInt32
 #else
-#define CProb unsigned short
+#define CProb UInt16
 #endif
 
 #define LZMA_RESULT_OK 0
 #define LZMA_RESULT_DATA_ERROR 1
-#define LZMA_RESULT_NOT_ENOUGH_MEM 2
 
 #ifdef _LZMA_IN_CB
 typedef struct _ILzmaInCallback
 {
-  int (*Read)(void *object, unsigned char **buffer, UInt32 *bufferSize);
+  int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize);
 } ILzmaInCallback;
 #endif
 
 #define LZMA_BASE_SIZE 1846
 #define LZMA_LIT_SIZE 768
 
-/* 
-bufferSize = (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)))* sizeof(CProb)
-bufferSize += 100 in case of _LZMA_OUT_READ
-by default CProb is unsigned short, 
-but if specify _LZMA_PROB_32, CProb will be UInt32(unsigned int)
-*/
+#define LZMA_PROPERTIES_SIZE 5
 
-#ifdef _LZMA_OUT_READ
-int LzmaDecoderInit(
-    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
+typedef struct _CLzmaProperties
+{
+  int lc;
+  int lp;
+  int pb;
+  #ifdef _LZMA_OUT_READ
+  UInt32 DictionarySize;
   #endif
-);
-#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;
 
-int LzmaDecode(
-    unsigned char *buffer, 
-  #ifndef _LZMA_OUT_READ
-    UInt32 bufferSize,
-    int lc, int lp, int pb,
   #ifdef _LZMA_IN_CB
-    ILzmaInCallback *inCallback,
-  #else
-    unsigned char *inStream, UInt32 inSize,
+  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
-    unsigned char *outStream, UInt32 outSize,
-    UInt32 *outSizeProcessed);
+} 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/brcm63xx/image/lzma-loader/src/LzmaTypes.h b/target/linux/brcm63xx/image/lzma-loader/src/LzmaTypes.h
new file mode 100644 (file)
index 0000000..9c27290
--- /dev/null
@@ -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
index 83e2c52..50c22d8 100644 (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
-# 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 (C) 2011 Gabor Juhos <juhosg@openwrt.org>
 #
-# Copyright 2004  Manuel Novoa III <mjn3@codepoet.org>
-#   Modified to support bzip'd kernels.
-#   Of course, it would be better to integrate bunzip capability into CFE.
+# 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 <mtakahar@yahoo.com>
+#      Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
 #
-# Copyright 2005  Oleg I. Vdovikin <oleg@cs.msu.su>
-#   Cleaned up, modified for lzma support, removed from kernel
+# 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.
 #
 
-TEXT_START     := 0x80010000
-BZ_TEXT_START  := 0x80300000
+LOADADDR       :=
+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 \
-                 -fno-strict-aliasing -fno-common -fomit-frame-pointer -G 0 -mno-abicalls -fno-pic \
-                 -ffunction-sections -pipe -mlong-calls -fno-common \
-                 -mabi=32 -march=mips32 -Wa,-32 -Wa,-march=mips32 -Wa,-mips32 -Wa,--trap
-CFLAGS         += -DLOADADDR=$(TEXT_START) -D_LZMA_IN_CB
+                 -fno-strict-aliasing -fno-common -fomit-frame-pointer -G 0 \
+                 -mno-abicalls -fno-pic -ffunction-sections -pipe \
+                 -ffreestanding -fhonour-copts \
+                 -mabi=32 -march=mips32 \
+                 -Wa,-32 -Wa,-march=mips32 -Wa,-mips32 -Wa,--trap
+CFLAGS         += -D_LZMA_PROB32
+
+ASFLAGS                = $(CFLAGS) -D__ASSEMBLY__
+
+LDFLAGS                = -static --gc-sections -no-warn-mismatch
+LDFLAGS                += -e startup -T loader.lds -Ttext $(LZMA_TEXT_START)
+
+O_FORMAT       = $(shell $(OBJDUMP) -i | head -2 | grep elf32)
 
-ASFLAGS                = $(CFLAGS) -D__ASSEMBLY__ -DBZ_TEXT_START=$(BZ_TEXT_START)
+OBJECTS                := head.o loader.o cache.o board.o printf.o LzmaDecode.o
 
-SEDFLAGS       := s/BZ_TEXT_START/$(BZ_TEXT_START)/;s/TEXT_START/$(TEXT_START)/
+ifneq ($(strip $(LOADER_DATA)),)
+OBJECTS                += data.o
+CFLAGS         += -DLZMA_WRAPPER=1 -DLOADADDR=$(LOADADDR)
+endif
 
-OBJECTS                := head.o data.o
 
-all: loader.gz loader.elf
+all: loader.elf
 
 # Don't build dependencies, this may die if $(CC) isn't gcc
 dep:
 
 install:
 
-loader.gz: loader
-       gzip -nc9 $< > $@
+%.o : %.c
+       $(CC) $(CFLAGS) -c -o $@ $<
 
-loader.elf: loader.o
-       cp $< $@
+%.o : %.S
+       $(CC) $(ASFLAGS) -c -o $@ $<
 
-loader: loader.o
-       $(OBJCOPY) $< $@
+data.o: $(LOADER_DATA)
+       $(LD) -r -b binary --oformat $(O_FORMAT) -T lzma-data.lds -o $@ $<
 
-loader.o: loader.lds $(OBJECTS)
-       $(LD) -static --gc-sections -no-warn-mismatch -T loader.lds -o $@ $(OBJECTS)
+loader: $(OBJECTS)
+       $(LD) $(LDFLAGS) -o $@ $(OBJECTS)
 
-loader.lds: loader.lds.in Makefile
-       @sed "$(SEDFLAGS)" < $< > $@
+loader.bin: loader
+       $(OBJCOPY) $(BIN_FLAGS) $< $@
 
-data.o: data.lds decompress.image
-       $(LD) -no-warn-mismatch -T data.lds -r -o $@ -b binary decompress.image -b elf32-tradlittlemips
+loader2.o: loader.bin
+       $(LD) -r -b binary --oformat $(O_FORMAT) -o $@ $<
 
-data.lds:
-       @echo "SECTIONS { .data : { code_start = .; *(.data) code_stop = .; }}" > $@
+loader.elf: loader2.o
+       $(LD) -e startup -T loader2.lds -Ttext $(LOADADDR) -o $@ $<
 
-decompress.image: decompress
-       $(OBJCOPY) $< $@
+mrproper: clean
 
-decompress: decompress.lds decompress.o LzmaDecode.o
-       $(LD) -static --gc-sections -no-warn-mismatch -T decompress.lds -o $@ decompress.o LzmaDecode.o
+clean:
+       rm -f loader *.elf *.bin *.o
 
-decompress.lds: decompress.lds.in Makefile
-       @sed "$(SEDFLAGS)" < $< > $@
 
-mrproper: clean
 
-clean:
-       rm -f loader.gz loader decompress *.lds *.o *.image
diff --git a/target/linux/brcm63xx/image/lzma-loader/src/README b/target/linux/brcm63xx/image/lzma-loader/src/README
deleted file mode 100644 (file)
index 16649e9..0000000
+++ /dev/null
@@ -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
diff --git a/target/linux/brcm63xx/image/lzma-loader/src/board.c b/target/linux/brcm63xx/image/lzma-loader/src/board.c
new file mode 100644 (file)
index 0000000..1c715e3
--- /dev/null
@@ -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;
+       }
+}
diff --git a/target/linux/brcm63xx/image/lzma-loader/src/cache.c b/target/linux/brcm63xx/image/lzma-loader/src/cache.c
new file mode 100644 (file)
index 0000000..93751c3
--- /dev/null
@@ -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;
+       }
+}
diff --git a/target/linux/brcm63xx/image/lzma-loader/src/cache.h b/target/linux/brcm63xx/image/lzma-loader/src/cache.h
new file mode 100644 (file)
index 0000000..506a235
--- /dev/null
@@ -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 */
diff --git a/target/linux/brcm63xx/image/lzma-loader/src/cacheops.h b/target/linux/brcm63xx/image/lzma-loader/src/cacheops.h
new file mode 100644 (file)
index 0000000..70bcad7
--- /dev/null
@@ -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/brcm63xx/image/lzma-loader/src/config.h b/target/linux/brcm63xx/image/lzma-loader/src/config.h
new file mode 100644 (file)
index 0000000..ce391f8
--- /dev/null
@@ -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_ */
diff --git a/target/linux/brcm63xx/image/lzma-loader/src/cp0regdef.h b/target/linux/brcm63xx/image/lzma-loader/src/cp0regdef.h
new file mode 100644 (file)
index 0000000..0d824f4
--- /dev/null
@@ -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
diff --git a/target/linux/brcm63xx/image/lzma-loader/src/decompress.c b/target/linux/brcm63xx/image/lzma-loader/src/decompress.c
deleted file mode 100644 (file)
index ec510e2..0000000
+++ /dev/null
@@ -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)();
-       }
-}
diff --git a/target/linux/brcm63xx/image/lzma-loader/src/decompress.lds.in b/target/linux/brcm63xx/image/lzma-loader/src/decompress.lds.in
deleted file mode 100644 (file)
index 33f56f8..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-OUTPUT_ARCH(mips)
-ENTRY(entry)
-SECTIONS {
-       . = BZ_TEXT_START;
-       .text : {
-               *(.text.entry)
-               *(.text)
-               *(.rodata)
-       }
-
-       .data : {
-               *(.data)
-       }
-
-       .bss : {
-               *(.bss)
-       }
-
-       workspace = .;
-}
index 9bfbd53..543996a 100644 (file)
-/* Copyright 2005 Oleg I. Vdovikin (oleg@cs.msu.su)    */
-/* cache manipulation adapted from Broadcom code       */
-/* idea taken from original bunzip2 decompressor code  */
-/* Copyright 2004 Manuel Novoa III (mjn3@codepoet.org) */
-/* Licensed under the linux kernel's version of the GPL.*/
+/*
+ * 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 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/regdef.h>
+#include "cp0regdef.h"
+#include "cacheops.h"
+#include "config.h"
 
 #define KSEG0          0x80000000
 
-#define C0_CONFIG      $16
-#define C0_TAGLO       $28
-#define C0_TAGHI       $29
-
-#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
+       .macro  ehb
+       sll     zero, 3
+       .endm
 
        .text
-       LEAF(startup)
+
+LEAF(startup)
        .set noreorder
-       
-       /* 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
+       .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
+
+       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
-       
-       /* At this point we need to invalidate dcache and */
-       /* icache before jumping to new code */
-
-1:     /* Get cache sizes */
-       .set    mips32
-       mfc0    s0,C0_CONFIG,1
-       .set    mips0
-
-       li      s1,CONF1_DL_MASK
-       and     s1,s0
-       beq     s1,zero,nodc
+
+       /* 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
 
-       srl     s1,CONF1_DL_SHIFT
-       li      t0,CONF1_DL_BASE
-       sll     s1,t0,s1                /* s1 has D$ cache line size */
-
-       li      s2,CONF1_DA_MASK
-       and     s2,s0
-       srl     s2,CONF1_DA_SHIFT
-       addiu   s2,CONF1_DA_BASE        /* s2 now has D$ associativity */
-
-       li      t0,CONF1_DS_MASK
-       and     t0,s0
-       srl     t0,CONF1_DS_SHIFT
-       li      s3,CONF1_DS_BASE
-       sll     s3,s3,t0                /* s3 has D$ sets per way */
-
-       multu   s2,s3                   /* sets/way * associativity */
-       mflo    t0                      /* total cache lines */
-
-       multu   s1,t0                   /* D$ linesize * lines */
-       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
+       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
+
+       /* jump to the decompressor routine */
+       la      t0, loader_main
+       jr      t0
        nop
 
-       srl     t0,CONF1_IL_SHIFT
-       li      s3,CONF1_IL_BASE
-       sll     s3,t0                   /* s3 has I$ cache line size */
-
-       li      t0,CONF1_IA_MASK
-       and     t0,s0
-       srl     t0,CONF1_IA_SHIFT
-       addiu   s4,t0,CONF1_IA_BASE     /* s4 now has I$ associativity */
-
-       li      t0,CONF1_IS_MASK
-       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 */
-       mflo    t0                      /* s4 is now total cache lines */
-
-       multu   s3,t0                   /* I$ linesize * lines */
-       mflo    s4                      /* s4 is cache size in bytes */
-
-       /* Initilize the I$: */
-       mtc0    zero,C0_TAGLO
-       mtc0    zero,C0_TAGHI
-
-       li      t0,KSEG0                /* Just an address for the first $ line */
-       addu    t1,t0,s4                /*  + size of cache == end */
-
-       .set    mips3
-1:     cache   Index_Invalidate_I,0(t0)
-       .set    mips0
-       bne     t0,t1,1b
-       addu    t0,s3
-
-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
-       END(startup)
+END(startup)
diff --git a/target/linux/brcm63xx/image/lzma-loader/src/loader.c b/target/linux/brcm63xx/image/lzma-loader/src/loader.c
new file mode 100644 (file)
index 0000000..0848ce6
--- /dev/null
@@ -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);
+}
diff --git a/target/linux/brcm63xx/image/lzma-loader/src/loader.lds b/target/linux/brcm63xx/image/lzma-loader/src/loader.lds
new file mode 100644 (file)
index 0000000..01ff852
--- /dev/null
@@ -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/brcm63xx/image/lzma-loader/src/loader.lds.in b/target/linux/brcm63xx/image/lzma-loader/src/loader.lds.in
deleted file mode 100644 (file)
index 20f2ea9..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-OUTPUT_ARCH(mips)
-ENTRY(startup)
-SECTIONS {
-       . = TEXT_START;
-       .text : {
-               *(.text)
-               *(.rodata)
-       }
-
-       .data : {
-               *(.data)
-       }
-
-       .bss : {
-               *(.bss)
-       }
-}
diff --git a/target/linux/brcm63xx/image/lzma-loader/src/loader2.lds b/target/linux/brcm63xx/image/lzma-loader/src/loader2.lds
new file mode 100644 (file)
index 0000000..db0bb46
--- /dev/null
@@ -0,0 +1,10 @@
+OUTPUT_ARCH(mips)
+SECTIONS {
+       .text : {
+               startup = .;
+               *(.text)
+               *(.text.*)
+               *(.data)
+               *(.data.*)
+       }
+}
diff --git a/target/linux/brcm63xx/image/lzma-loader/src/lzma-data.lds b/target/linux/brcm63xx/image/lzma-loader/src/lzma-data.lds
new file mode 100644 (file)
index 0000000..abf756b
--- /dev/null
@@ -0,0 +1,8 @@
+OUTPUT_ARCH(mips)
+SECTIONS {
+       .data.lzma : {
+               _lzma_data_start = .;
+               *(.data)
+               _lzma_data_end = .;
+       }
+}
diff --git a/target/linux/brcm63xx/image/lzma-loader/src/printf.c b/target/linux/brcm63xx/image/lzma-loader/src/printf.c
new file mode 100644 (file)
index 0000000..7bb5a86
--- /dev/null
@@ -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/brcm63xx/image/lzma-loader/src/printf.h b/target/linux/brcm63xx/image/lzma-loader/src/printf.h
new file mode 100644 (file)
index 0000000..9b1c1df
--- /dev/null
@@ -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_ */