Files
kunlun/sbl/lzma/LzmaTools.c

319 lines
7.8 KiB
C
Raw Normal View History

2024-09-28 14:24:04 +08:00
/*
* Usefuls routines based on the LzmaTest.c file from LZMA SDK 4.65
*
* Copyright (C) 2007-2009 Industrie Dial Face S.p.A.
* Luigi 'Comio' Mantellini (luigi.mantellini@idf-hit.com)
*
* Copyright (C) 1999-2005 Igor Pavlov
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*
* LZMA_Alone stream format:
*
* uchar Properties[5]
* uint64 Uncompressed size
* uchar data[*]
*
*/
#define LZMA_PROPERTIES_OFFSET 0
#define LZMA_SIZE_OFFSET LZMA_PROPS_SIZE
#define LZMA_DATA_OFFSET LZMA_SIZE_OFFSET+sizeof(uint64_t)
#include "os_types.h"
#include "LzmaTools.h"
#include "LzmaDec.h"
#include <string.h>
#include "7zAlloc.h"
#include "iot_config.h"
#include "flash.h"
#include "ahb.h"
#include "iot_mtd.h"
#include "sbl_boot_hw.h"
#define min(a, b) (((a) < (b)) ? (a) : (b))
/* LZMA decoder need 1M size buffer */
#define BUF_SZ LZMA_BUF_SIZE
#define BUF_ADDR LZMA_BUF_ADDR
static unsigned char *heap_buf = (unsigned char*)BUF_ADDR;
static void *SzAlloc(void *p, size_t size) { return buffer_alloc_malloc(size); }
static void SzFree(void *p, void *address) { buffer_alloc_free(address); }
struct dataStream
{
const unsigned char * inData;
size_t inLen;
unsigned char * outData;
size_t outLen;
};
struct dataStream ds;
static uint32_t start_addr = 0, end_addr = 0;
static void flash_erase_blocks(uint32_t addr, uint32_t size)
{
flash_write_param_t param = {
.sw_mode = MOD_SW_MODE_DIS,
.erase_mode = MODE_ERASE_BLOCK64
};
start_addr = (addr + BLOCK_ERASE_64K_MASK) & (~BLOCK_ERASE_64K_MASK);
end_addr = (addr + size) & (~BLOCK_ERASE_64K_MASK);
/* disable cache space */
ahb_cache_space_dis_for_flash_write();
for (uint32_t erase_addr = start_addr; erase_addr < end_addr;
erase_addr += BLOCK_ERASE_64K_SIZE) {
flash_erase(erase_addr, &param);
}
/* enable cache space again */
ahb_cache_space_ena_for_flash_write();
}
static int
inputCallback(void *ctx, void *buf, size_t * size)
{
size_t rd = 0;
rd = (ds.inLen < *size) ? ds.inLen : *size;
if (rd > 0) {
memcpy(buf, (void *) ds.inData, rd);
ds.inData += rd;
ds.inLen -= rd;
}
*size = rd;
return 0;
}
static size_t
outputCallback(void *ctx, const void *buf, size_t size)
{
#if RUN_IN_PSRAM
if (size > 0) {
memcpy((void *) (ds.outData + ds.outLen), buf, size);
ds.outLen += size;
}
#else
flash_write_param_t param = {0};
/*write to the FW addr in flash*/
param.read_mode = MOD_SFC_READ_QUAD_IO_FAST;
param.write_mode = MOD_SFC_PROG_STAND;
param.is_erase = 1;
param.sw_mode = MOD_SW_MODE_DIS;
/* disable cache space */
ahb_cache_space_dis_for_flash_write();
if ((start_addr <= (uint32_t)(ds.outData + ds.outLen)) &&
((uint32_t)(ds.outData + ds.outLen + size) <= end_addr)) {
param.is_erase = 0;
}
flash_write(buf, (uint32_t)(ds.outData + ds.outLen), (uint32_t)size, &param);
/* enable cache space again */
ahb_cache_space_ena_for_flash_write();
ds.outLen += (uint32_t)size;
#endif
return size;
}
#define IN_BUF_SIZE (1 << 14)
#define OUT_BUF_SIZE (1 << 14)
Byte inBuf[IN_BUF_SIZE];
Byte outBuf[OUT_BUF_SIZE];
static SRes Decode2(CLzmaDec *state, ISeqOutStream *outStream, ISeqInStream *inStream,
UInt64 unpackSize)
{
int thereIsSize = (unpackSize != (UInt64)(Int64)-1);
size_t inPos = 0, inSize = 0, outPos = 0;
LzmaDec_Init(state);
for (;;)
{
if (inPos == inSize)
{
inSize = IN_BUF_SIZE;
RINOK(inStream->Read(inStream, inBuf, &inSize));
inPos = 0;
}
{
SRes res;
SizeT inProcessed = inSize - inPos;
SizeT outProcessed = OUT_BUF_SIZE - outPos;
ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
ELzmaStatus status;
if (thereIsSize && outProcessed > unpackSize)
{
outProcessed = (SizeT)unpackSize;
finishMode = LZMA_FINISH_END;
}
res = LzmaDec_DecodeToBuf(state, outBuf + outPos, &outProcessed,
inBuf + inPos, &inProcessed, finishMode, &status);
inPos += inProcessed;
outPos += outProcessed;
unpackSize -= outProcessed;
if (outStream)
if (outStream->Write(outStream, outBuf, outPos) != outPos)
return SZ_ERROR_WRITE;
outPos = 0;
if (res != SZ_OK || (thereIsSize && unpackSize == 0))
return res;
if (inProcessed == 0 && outProcessed == 0)
{
if (thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK)
return SZ_ERROR_DATA;
return res;
}
}
}
}
int BufferDecode(uint8_t *dst, uint32_t *dstLen, uint8_t *src, uint32_t srcLen )
{
ISeqOutStream outStream;
ISeqInStream inStream;
ISzAlloc g_Alloc;
UInt64 unpackSize;
int i;
size_t header_size;
SRes res = 0;
CLzmaDec state;
outStream.Write= outputCallback;
inStream.Read = inputCallback;
ds.inData = src;
ds.inLen = srcLen;
ds.outData = dst;
ds.outLen = 0;
/* header: 5 bytes of LZMA properties and 8 bytes of uncompressed size */
unsigned char header[LZMA_PROPS_SIZE + 8];
/* Read and parse header */
header_size = sizeof(header);
inStream.Read(&inStream, header, &header_size);
unpackSize = 0;
for (i = 0; i < 8; i++)
unpackSize += (UInt64)header[LZMA_PROPS_SIZE + i] << (i * 8);
flash_erase_blocks((uint32_t)dst, (uint32_t)unpackSize);
memory_buffer_alloc_init(heap_buf, BUF_SZ);
g_Alloc.Alloc = SzAlloc;
g_Alloc.Free = SzFree;
LzmaDec_Construct(&state);
LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc);
res = Decode2(&state, &outStream, &inStream, unpackSize);
LzmaDec_Free(&state, &g_Alloc);
*dstLen = ds.outLen;
return res;
}
int lzmaBuffToBuffDecompress (unsigned char *outStream, uint32_t *uncompressedSize,
unsigned char *inStream, uint32_t length)
{
#if RUN_IN_PSRAM
int res = SZ_ERROR_DATA;
int i;
ISzAlloc g_Alloc;
SizeT outSizeFull = 0xFFFFFFFF; /* 4GBytes limit */
SizeT outProcessed;
SizeT outSize;
SizeT outSizeHigh;
ELzmaStatus state;
SizeT compressedSize = (SizeT)(length - LZMA_PROPS_SIZE);
memset(&state, 0, sizeof(state));
outSize = 0;
outSizeHigh = 0;
/* Read the uncompressed size */
for (i = 0; i < 8; i++) {
unsigned char b = inStream[LZMA_SIZE_OFFSET + i];
if (i < 4) {
outSize += (UInt32)(b) << (i * 8);
} else {
outSizeHigh += (UInt32)(b) << ((i - 4) * 8);
}
}
outSizeFull = (SizeT)outSize;
if (sizeof(SizeT) >= 8) {
/*
* SizeT is a 64 bit uint => We can manage files larger than 4GB!
*
*/
outSizeFull |= (((SizeT)outSizeHigh << 16) << 16);
} else if (outSizeHigh != 0 || (UInt32)(SizeT)outSize != outSize) {
/*
* SizeT is a 32 bit uint => We cannot manage files larger than
* 4GB! Assume however that all 0xf values is "unknown size" and
* not actually a file of 2^64 bits.
*
*/
if (outSizeHigh != (SizeT)-1 || outSize != (SizeT)-1) {
return SZ_ERROR_DATA;
}
}
memory_buffer_alloc_init(heap_buf, BUF_SZ);
g_Alloc.Alloc = SzAlloc;
g_Alloc.Free = SzFree;
/* Short-circuit early if we know the buffer can't hold the results. */
if (outSizeFull != (SizeT)-1 && *uncompressedSize < outSizeFull)
return SZ_ERROR_OUTPUT_EOF;
/* Decompress */
outProcessed = min(outSizeFull, *uncompressedSize);
res = LzmaDecode(
outStream, &outProcessed,
inStream + LZMA_DATA_OFFSET, &compressedSize,
inStream, LZMA_PROPS_SIZE, LZMA_FINISH_END, &state, &g_Alloc);
*uncompressedSize = outProcessed;
if (res != SZ_OK) {
return res;
}
return res;
#else
return BufferDecode(outStream, uncompressedSize, inStream, length);
#endif
}