arm-trusted-firmware/lib/zlib/tf_gunzip.c
Masahiro Yamada c43d68510e zlib: add gunzip() support
This commit adds some more files to use zlib from TF.

To use zlib, ->zalloc and ->zfree hooks are needed.  The implementation
depends on the system.  For user-space, the libc provides malloc() and
friends.  Unfortunately, ARM Trusted Firmware does not provide malloc()
or any concept of dynamic memory allocation.

I implemented very simple calloc() and free() for this.  Stupidly,
zfree() never frees memory, but it works enough for this.

The purpose of using zlib is to implement gunzip() - this function
takes compressed data from in_buf, then dumps the decompressed data
to oub_buf.  The work_buf is used for memory allocation during the
decompress.  Upon exit, it updates in_buf and out_buf.  If successful,
in_buf points to the end of input data, out_buf to the end of the
decompressed data.

To use this feature, you need to do:

 - include lib/zlib/zlib.mk from your platform.mk

 - add $(ZLIB_SOURCES) to your BL*_SOURCES

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2018-02-02 00:18:54 +09:00

101 lines
2.2 KiB
C

/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <debug.h>
#include <errno.h>
#include <string.h>
#include <tf_gunzip.h>
#include <utils.h>
#include "zutil.h"
/*
* memory allocated by malloc() is supposed to be aligned for any built-in type
*/
#define ZALLOC_ALIGNMENT sizeof(void *)
static uintptr_t zalloc_start;
static uintptr_t zalloc_end;
static uintptr_t zalloc_current;
static void * ZLIB_INTERNAL zcalloc(void *opaque, unsigned int items,
unsigned int size)
{
uintptr_t p, p_end;
size *= items;
p = round_up(zalloc_current, ZALLOC_ALIGNMENT);
p_end = p + size;
if (p_end > zalloc_end)
return NULL;
memset((void *)p, 0, size);
zalloc_current = p_end;
return (void *)p;
}
static void ZLIB_INTERNAL zfree(void *opaque, void *ptr)
{
}
/*
* gunzip - decompress gzip data
* @in_buf: source of compressed input. Upon exit, the end of input.
* @in_len: length of in_buf
* @out_buf: destination of decompressed output. Upon exit, the end of output.
* @out_len: length of out_buf
* @work_buf: workspace
* @work_len: length of workspace
*/
int gunzip(uintptr_t *in_buf, size_t in_len, uintptr_t *out_buf,
size_t out_len, uintptr_t work_buf, size_t work_len)
{
z_stream stream;
int zret, ret;
zalloc_start = work_buf;
zalloc_end = work_buf + work_len;
zalloc_current = zalloc_start;
stream.next_in = (typeof(stream.next_in))*in_buf;
stream.avail_in = in_len;
stream.next_out = (typeof(stream.next_out))*out_buf;
stream.avail_out = out_len;
stream.zalloc = zcalloc;
stream.zfree = zfree;
stream.opaque = (voidpf)0;
zret = inflateInit(&stream);
if (zret != Z_OK) {
ERROR("zlib: inflate init failed (ret = %d)\n", zret);
return (zret == Z_MEM_ERROR) ? -ENOMEM : -EIO;
}
zret = inflate(&stream, Z_NO_FLUSH);
if (zret == Z_STREAM_END) {
ret = 0;
} else {
if (stream.msg)
ERROR("%s\n", stream.msg);
ERROR("zlib: inflate failed (ret = %d)\n", zret);
ret = (zret == Z_MEM_ERROR) ? -ENOMEM : -EIO;
}
VERBOSE("zlib: %d byte input\n", stream.total_in);
VERBOSE("zlib: %d byte output\n", stream.total_out);
*in_buf = (uintptr_t)stream.next_in;
*out_buf = (uintptr_t)stream.next_out;
inflateEnd(&stream);
return ret;
}