aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2009-05-26 11:07:45 +0300
committerLasse Collin <lasse.collin@tukaani.org>2009-05-26 11:07:45 +0300
commit28892358dcf724b13bf0c49b1e3fa5b29e2d4f09 (patch)
tree14ffeb8325a175475c8bbf188da5e6e1d07f561a
parentf88bf0850d6eace21ecdfc43d079093d205599e2 (diff)
downloadxz-embedded-28892358dcf724b13bf0c49b1e3fa5b29e2d4f09.tar.gz
Reworked the code that is inteded to be usable for kernel
and initramfs decompression. Linux 2.6.30 will have bzip2 and lzma support. This commit adds a wrapper to convert the native XZ decompressor API to the decompressor API that is used for kernel and initramfs decompression in 2.6.30.
-rw-r--r--linux/include/linux/decompress/unxz.h20
-rw-r--r--linux/lib/decompress_unxz.c439
-rw-r--r--linux/lib/xz/xz_boot.c226
-rw-r--r--linux/lib/xz/xz_private.h4
-rw-r--r--userspace/boottest.c76
-rw-r--r--userspace/xz_config.h22
6 files changed, 537 insertions, 250 deletions
diff --git a/linux/include/linux/decompress/unxz.h b/linux/include/linux/decompress/unxz.h
new file mode 100644
index 0000000..bed2bbf
--- /dev/null
+++ b/linux/include/linux/decompress/unxz.h
@@ -0,0 +1,20 @@
+/*
+ * Wrapper for XZ decompressor to make it usable for kernel and initramfs
+ * decompression
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef DECOMPRESS_UNXZ_H
+#define DECOMPRESS_UNXZ_H
+
+int unxz(unsigned char *in, int in_size,
+ int (*fill)(void *dest, unsigned int size),
+ int (*flush)(/*const*/ void *src, unsigned int size),
+ unsigned char *out, int *in_used,
+ void (*error)(/*const*/ char *x));
+
+#endif
diff --git a/linux/lib/decompress_unxz.c b/linux/lib/decompress_unxz.c
new file mode 100644
index 0000000..8f2df85
--- /dev/null
+++ b/linux/lib/decompress_unxz.c
@@ -0,0 +1,439 @@
+/*
+ * XZ decoder as a single file for uncompressing the kernel and initramfs
+ *
+ * NOTE: This file hasn't been tested in kernel space yet!
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+/*
+ * Important notes about in-place decompression
+ *
+ * At least on x86, the kernel is decompressed in place: the compressed data
+ * is placed to the end of the output buffer, and the decompressor overwrites
+ * most of the compressed data. There must be enough safety margin to
+ * guarantee that the write position is always behind the read position.
+ * The optimal safety margin for XZ with LZMA2 or BCJ+LZMA2 is calculated
+ * below. Note that the margin with XZ is bigger than with Deflate (gzip)!
+ *
+ * The worst case for in-place decompression is that the beginning of
+ * the file is compressed extremely well, and the rest of the file is
+ * uncompressible. Thus, we must look for worst-case expansion when the
+ * compressor is encoding uncompressible data.
+ *
+ * The structure of the .xz file in case of a compresed kernel is as follows.
+ * Sizes (as bytes) of the fields are in parenthesis.
+ *
+ * Stream Header (12)
+ * Block Header:
+ * Block Header (8-12)
+ * Compressed Data (N)
+ * Block Padding (0-3)
+ * CRC32 (4)
+ * Index (8-20)
+ * Stream Footer (12)
+ *
+ * Normally there is exactly one Block, but let's assume that there are
+ * 2-4 Blocks just in case. Because Stream Header and also Block Header
+ * of the first Block don't make the decompressor produce any uncompressed
+ * data, we can ignore them from our calculations. Block Headers of possible
+ * additional Blocks have to be taken into account still. With these
+ * assumptions, it is safe to assume that the total header overhead is
+ * less than 128 bytes.
+ *
+ * Compressed Data contains LZMA2 or BCJ+LZMA2 encoded data. Since BCJ
+ * doesn't change the size of the data, it is enough to calculate the
+ * safety margin for LZMA2.
+ *
+ * LZMA2 stores the data in chunks. Each chunk has a header whose size is
+ * at maximum of 6 bytes, but to get round 2^n numbers, let's assume that
+ * the maximum chunk header size is 8 bytes. After the chunk header, there
+ * may be up to 64 KiB of actual payload in the chunk. Often the payload is
+ * quite a bit smaller though; to be safe, let's assume that an average
+ * chunk has only 32 KiB of payload.
+ *
+ * The maximum uncompressed size of the payload is 2 MiB. The minimum
+ * uncompressed size of the payload is in practice never less than the
+ * payload size itself. The LZMA2 format would allow uncompressed size
+ * to be less than the payload size, but no sane compressor creates such
+ * files. LZMA2 supports storing uncompressible data in uncompressed form,
+ * so there's never a need to create payloads whose uncompressed size is
+ * smaller than the compressed size.
+ *
+ * The assumption, that the uncompressed size of the payload is never
+ * smaller than the payload itself, is valid only when talking about
+ * the payload as a whole. It is possible that the payload has parts where
+ * the decompressor consumes more input than it produces output. Calculating
+ * the worst case for this would be tricky. Instead of trying to do that,
+ * let's simply make sure that the decompressor never overwrites any bytes
+ * of the payload which it is currently reading.
+ *
+ * Now we have enough information to calculate the safety margin. We need
+ * - 128 bytes for the .xz file format headers;
+ * - 8 bytes per every 32 KiB of uncompressed size (one LZMA2 chunk header
+ * per chunk, each chunk having average payload size of 32 KiB); and
+ * - 64 KiB (biggest possible LZMA2 chunk payload size) to make sure that
+ * the decompressor never overwrites anything from the LZMA2 chunk
+ * payload it is currently reading.
+ *
+ * We get the following formula:
+ *
+ * safety_margin = 128 + uncompressed_size * 8 / 32768 + 65536
+ * = 128 + (uncompressed_size >> 12) + 65536
+ *
+ * For comparision, according to arch/x86/boot/compressed/misc.c, the
+ * equivalent formula for Deflate is this:
+ *
+ * safety_margin = 18 + (uncompressed_size >> 12) + 32768
+ *
+ * Thus, when updating Deflate-only in-place kernel decompressor to
+ * support XZ, the fixed overhead has to be increased from 18+32768 bytes
+ * to 128+65536 bytes.
+ */
+
+/*
+ * Set the linkage of normally extern functions to static when compiling
+ * the decompressor the kernel image. This must be done before including
+ * <linux/decompress/mm.h>, which defines STATIC to be empty if it wasn't
+ * already defined. We also define XZ_STATIC which is used only in ifdefs
+ * to test if STATIC was defined before <linux/decompress/mm.h> was included.
+ */
+#ifdef STATIC
+# define XZ_EXTERN STATIC
+# define XZ_STATIC
+#endif
+
+#ifdef __KERNEL__
+# include <linux/decompress/mm.h>
+# include <linux/decompress/generic.h>
+#endif
+
+/*
+ * Use INIT defined in <linux/decompress/mm.h> to possibly add __init
+ * to every function.
+ */
+#ifdef INIT
+# define XZ_FUNC INIT
+#endif
+
+/*
+ * Use the internal CRC32 code instead of kernel's CRC32 module, which
+ * is not available in early phase of booting.
+ */
+#define XZ_INTERNAL_CRC32
+
+/*
+ * Ignore the configuration specified in the kernel config for the xz_dec
+ * module. For boot time use, we enable only the BCJ filter of the current
+ * architecture, or none if no BCJ filter is available for the architecture.
+ */
+#define XZ_IGNORE_KCONFIG
+#ifdef CONFIG_X86
+# define XZ_DEC_X86
+#endif
+#ifdef CONFIG_PPC
+# define XZ_DEC_POWERPC
+#endif
+#ifdef CONFIG_ARM
+# define XZ_DEC_ARM
+#endif
+#ifdef CONFIG_IA64
+# define XZ_DEC_IA64
+#endif
+#ifdef CONFIG_SPARC
+# define XZ_DEC_SPARC
+#endif
+
+#include "xz/xz_private.h"
+
+#ifdef XZ_STATIC
+/*
+ * Replace the normal allocation functions with the versions
+ * from <linux/decompress/mm.h>.
+ */
+#undef kmalloc
+#undef kfree
+#undef vmalloc
+#undef vfree
+#define kmalloc(size, flags) malloc(size)
+#define kfree(ptr) free(ptr)
+#define vmalloc(size) malloc(size)
+#define vfree(ptr) free(ptr)
+
+/*
+ * FIXME: Not all basic memory functions are provided in architecture-specific
+ * files (yet). We define our own versions here for now, but this should be
+ * only a temporary solution.
+ *
+ * memeq and memzero are not used much and any remotely sane implementation
+ * is fast enough. memcpy/memmove speed matters in multi-call mode, but
+ * the kernel image is decompressed in single-call mode, in which only
+ * memcpy speed can matter and only if there is a lot of uncompressible data
+ * (LZMA2 stores uncompressible chunks in uncompressed form). Thus, the
+ * functions below should just be kept small; it's probably not worth
+ * optimizing for speed.
+ */
+
+#ifndef memeq
+static bool XZ_FUNC memeq(const void *a, const void *b, size_t size)
+{
+ const uint8_t *x = a;
+ const uint8_t *y = b;
+ size_t i;
+
+ for (i = 0; i < size; ++i)
+ if (x[i] != y[i])
+ return false;
+
+ return true;
+}
+#endif
+
+#ifndef memzero
+static void XZ_FUNC memzero(void *buf, size_t size)
+{
+ uint8_t *b = buf;
+ uint8_t *e = b + size;
+ while (b != e)
+ *b++ = '\0';
+}
+#endif
+
+#ifndef memmove
+static void * XZ_FUNC memmove(void *dest, const void *src, size_t size)
+{
+ uint8_t *d = dest;
+ const uint8_t *s = src;
+ size_t i;
+
+ if (d < s) {
+ for (i = 0; i < size; ++i)
+ d[i] = s[i];
+ } else if (d > s) {
+ i = size;
+ while (i-- > 0)
+ d[i] = s[i];
+ }
+
+ return dest;
+}
+#endif
+
+/* Since we need memmove anyway, use it as memcpy too. */
+#ifndef memcpy
+# define memcpy memmove
+#endif
+#endif /* XZ_STATIC */
+
+#include "xz/xz_crc32.c"
+#include "xz/xz_dec_stream.c"
+#include "xz/xz_dec_lzma2.c"
+#ifdef XZ_DEC_BCJ
+# include "xz/xz_dec_bcj.c"
+#endif
+
+/*
+ * Maximum LZMA2 dictionary size. This matters only in multi-call mode.
+ * If you change this, remember to update also the error message in
+ * "case XZ_MEMLIMIT_ERROR".
+ */
+#define DICT_MAX (1024 * 1024)
+
+/*
+ * This function implements the API defined in <linux/decompress/generic.h>.
+ *
+ * This wrapper will automatically choose single-call or multi-call mode
+ * of the native XZ decoder API. The single-call mode can be used only when
+ * both input and output buffers are available as a single chunk, i.e. when
+ * fill() and flush() won't be used.
+ *
+ * This API doesn't provide a way to specify the maximum dictionary size
+ * for the multi-call mode of the native XZ decoder API. We will use
+ * DICT_MAX bytes, which will be allocated with vmalloc().
+ *
+ * Input:
+ * - If in_size > 0, in is assumed to have in_size bytes of data that should
+ * be decompressed.
+ * - If in_size == 0 and in != NULL, in is assumed to have COMPR_IOBUF_SIZE
+ * bytes of space that we can use with fill(). (COMPR_IOBUF_SIZE is
+ * defined in <linux/decompress/generic.h>.)
+ * - If in_size == 0 and in == NULL, we will kmalloc() a temporary buffer
+ * of COMPR_IOBUF_SIZE bytes to be used with fill().
+ * - If in_used != NULL, the amount of input used after successful
+ * decompression will be stored in *in_used. If an error occurs,
+ * the value of *in_used is undefined.
+ *
+ * Output:
+ * - If flush == NULL, out is used the output buffer and flush() is not
+ * used. We don't know the size of the output buffer though, so we just
+ * hope that we don't overflow it. We also don't have any way to tell
+ * the caller how much uncompressed output we produced. This is OK when
+ * decompressing the kernel image.
+ * - If flush != NULL, out is ignored. We will kmalloc() a temporary buffer
+ * of COMPR_IOBUF_SIZE bytes to be used with flush().
+ *
+ * Memory usage:
+ * - If fill() and flush() are not used, about 30 KiB of memory is needed.
+ * - If fill() or flush() is used, about 30 KiB + DICT_SIZE bytes of memory
+ * is needed.
+ * - The memory allocator should return 8-byte aligned pointers, because
+ * there are a few uint64_t variables in the XZ decompressor.
+ *
+ * Error handling:
+ * - If decompression is successful, this function returns zero.
+ * - If an error occurs, error() is called with a string constant describing
+ * the error. If error() returns, this function returns -1.
+ */
+XZ_EXTERN int XZ_FUNC unxz(unsigned char *in, int in_size,
+ int (*fill)(void *dest, unsigned int size),
+ int (*flush)(/*const*/ void *src, unsigned int size),
+ unsigned char *out, int *in_used,
+ void (*error)(/*const*/ char *x))
+{
+ struct xz_buf b;
+ struct xz_dec *s;
+ enum xz_ret ret;
+ int tmp;
+ bool in_allocated = false;
+
+ xz_crc32_init();
+
+ if (in_size > 0 && flush == NULL)
+ s = xz_dec_init(0);
+ else
+ s = xz_dec_init(DICT_MAX);
+
+ if (s == NULL)
+ goto error_alloc_state;
+
+ b.in = in;
+ b.in_pos = 0;
+ b.in_size = in_size;
+ b.out = out;
+ b.out_pos = 0;
+ b.out_size = (size_t)-1;
+
+ if (in_used != NULL)
+ *in_used = 0;
+
+ if (in_size > 0 && flush == NULL) {
+ ret = xz_dec_run(s, &b);
+ } else {
+ if (in == NULL) {
+ in = kmalloc(COMPR_IOBUF_SIZE, GFP_KERNEL);
+ if (in == NULL)
+ goto error_alloc_in;
+
+ in_allocated = true;
+ b.in = in;
+ }
+
+ if (flush != NULL) {
+ b.out = kmalloc(COMPR_IOBUF_SIZE, GFP_KERNEL);
+ if (b.out == NULL)
+ goto error_alloc_out;
+
+ b.out_size = COMPR_IOBUF_SIZE;
+ }
+
+ do {
+ if (b.in_pos == b.in_size && in_size == 0) {
+ if (in_used != NULL)
+ *in_used += b.in_pos;
+
+ b.in_pos = 0;
+
+ tmp = fill(in, COMPR_IOBUF_SIZE);
+ if (tmp < 0) {
+ /*
+ * This isn't an optimal error code
+ * but it probably isn't worth making
+ * a new one either.
+ */
+ ret = XZ_BUF_ERROR;
+ break;
+ }
+
+ b.in_size = tmp;
+ }
+
+ ret = xz_dec_run(s, &b);
+
+ if (flush != NULL) {
+ if (b.out_pos == b.out_size || ret != XZ_OK) {
+ if (flush(b.out, b.out_pos)
+ != b.out_pos)
+ ret = XZ_BUF_ERROR;
+
+ b.out_pos = 0;
+ }
+ }
+ } while (ret == XZ_OK);
+
+ if (flush != NULL)
+ kfree(b.out);
+
+ if (in_allocated)
+ kfree(in);
+ }
+
+ if (in_used != NULL)
+ *in_used += b.in_pos;
+
+ xz_dec_end(s);
+
+ switch (ret) {
+ case XZ_STREAM_END:
+ return 0;
+
+ case XZ_MEMLIMIT_ERROR:
+ /* This can occur only in multi-call mode. */
+ error("Multi-call XZ decompressor limits "
+ "the LZMA2 dictionary to 1 MiB");
+ break;
+
+ case XZ_FORMAT_ERROR:
+ error("Input is not in the XZ format (wrong magic bytes)");
+ break;
+
+ case XZ_OPTIONS_ERROR:
+ error("Input was encoded with settings that are not "
+ "supported by this XZ decoder");
+ break;
+
+ case XZ_DATA_ERROR:
+ error("XZ-compressed data is corrupt");
+ break;
+
+ case XZ_BUF_ERROR:
+ error("Output buffer is too small or the "
+ "XZ-compressed data is corrupt");
+ break;
+
+ default:
+ error("Bug in the XZ decoder");
+ break;
+ }
+
+ return -1;
+
+error_alloc_out:
+ if (in_allocated)
+ kfree(in);
+
+error_alloc_in:
+ xz_dec_end(s);
+
+error_alloc_state:
+ error("XZ decoder ran out of memory");
+ return -1;
+}
+
+/*
+ * This macro is used by architecture-specific files to decompress
+ * the kernel image.
+ */
+#define decompress unxz
diff --git a/linux/lib/xz/xz_boot.c b/linux/lib/xz/xz_boot.c
deleted file mode 100644
index 685fc4b..0000000
--- a/linux/lib/xz/xz_boot.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * XZ decoder as a single file for uncompressing the kernel and initramfs
- *
- * Author: Lasse Collin <lasse.collin@tukaani.org>
- *
- * This file has been put into the public domain.
- * You can do whatever you want with this file.
- */
-
-/*
- * Before #including this file, void error(char *) or void error(const char *)
- * must have been declared. It is called from xz_dec_buf() if an error
- * occurs; if error() returns, xz_dec_buf() will return false. On success,
- * xz_dec_buf() returns true, but if error() would never return, there's no
- * need to check the return value of xz_dec_buf().
- *
- * In the early phase of boot where kmalloc, memmove, and friends are not
- * available, you need to #define XZ_MEM_FUNCS before #including this file.
- * Before calling xz_dec_buf, set malloc_buf to the beginning of a workspace
- * buffer, and malloc_avail to the size of the workspace buffer. malloc_buf
- * must be aligned to a multiple of 8 bytes. About 30 KiB of space is
- * currently needed, but to be future-proof, having 40-50 KiB of space would
- * be good.
- *
- * Example:
- *
- * static void error(const char *message);
- * #define XZ_MEM_FUNCS
- * #include "../../../../lib/xz/xz_boot.c"
- * ...
- * struct xz_buf b;
- * b.in = (const uint8_t *)in_buf;
- * b.in_pos = 0;
- * b.in_size = in_buf_size;
- * b.out = (uint8_t *)out_buf;
- * b.out_pos = 0;
- * b.out_size = out_buf_size_max;
- * malloc_buf = (uint8_t *)free_mem_begin;
- * malloc_avail = free_mem_avail;
- * if (!xz_dec_buf(&b))
- * goto error_handler;
- *
- * If xz_dec_buf() succeeded (it returned true), the amount if input consumed
- * is in b.in_pos and the amount of output used is in b.out_pos.
- */
-
-/*
- * Allow using the macro INIT to mark all functions with __init.
- * INIT is already used for this purporse in the Deflate decoder,
- * so this should ease things a little.
- */
-#if !defined(XZ_FUNC) && defined(INIT)
-# define XZ_FUNC INIT
-#endif
-
-/*
- * Use the internal CRC32 code instead of kernel's CRC32 module, which
- * is not available in early phase of booting.
- */
-#define XZ_INTERNAL_CRC32
-
-/*
- * Ignore the configuration specified in the kernel config for the xz_dec
- * module. For boot time use, we enable only the BCJ filter of the current
- * architecture, or none if no BCJ filter is available for the architecture.
- */
-#define XZ_IGNORE_KCONFIG
-#ifdef CONFIG_X86
-# define XZ_DEC_X86
-#endif
-#ifdef CONFIG_PPC
-# define XZ_DEC_POWERPC
-#endif
-#ifdef CONFIG_ARM
-# define XZ_DEC_ARM
-#endif
-#ifdef CONFIG_IA64
-# define XZ_DEC_IA64
-#endif
-#ifdef CONFIG_SPARC
-# define XZ_DEC_SPARC
-#endif
-
-#include "xz_private.h"
-
-#ifdef XZ_MEM_FUNCS
-/* Replace the normal allocation functions with our simple version. */
-#undef kmalloc
-#undef kfree
-#undef vmalloc
-#undef vfree
-#define kmalloc(size, flags) malloc(size)
-#define kfree(ptr) ((void)0)
-#define vmalloc(size) malloc(size)
-#define vfree(ptr) ((void)0)
-
-/*
- * Very simple malloc, which just picks big enough chunk from a preallocated
- * buffer. There's no free(), because the decoder is (at least for now) used
- * only once per compilation unit. Thus, free() would be just waste of space.
- */
-static uint8_t *malloc_buf;
-static size_t malloc_avail;
-
-static void * XZ_FUNC malloc(size_t size)
-{
- void *ptr = malloc_buf;
- size = (size + 7) & ~(size_t)7;
- if (size > malloc_avail)
- return NULL;
-
- malloc_buf += size;
- malloc_avail -= size;
- return ptr;
-}
-
-/*
- * memeq and memzero are not used much and any remotely sane implementation
- * is fast enough. memcpy/memmove speed matters in multi-call mode, but
- * xz_dec_buf() uses only the single-call mode, in which only memcpy speed
- * can matter and only if there is a lot of uncompressible data (LZMA2 stores
- * uncompressible chunks in uncompressed form). Thus, the functions below
- * should just be kept small; it's probably not worth optimizing for speed.
- */
-static bool XZ_FUNC memeq(const void *a, const void *b, size_t size)
-{
- const uint8_t *x = a;
- const uint8_t *y = b;
- size_t i;
-
- for (i = 0; i < size; ++i)
- if (x[i] != y[i])
- return false;
-
- return true;
-}
-
-static void XZ_FUNC memzero(void *buf, size_t size)
-{
- uint8_t *b = buf;
- uint8_t *e = b + size;
- while (b != e)
- *b++ = '\0';
-}
-
-static void * XZ_FUNC memmove(void *dest, const void *src, size_t size)
-{
- uint8_t *d = dest;
- const uint8_t *s = src;
- size_t i;
-
- if (d < s) {
- for (i = 0; i < size; ++i)
- d[i] = s[i];
- } else if (d > s) {
- i = size;
- while (i-- > 0)
- d[i] = s[i];
- }
-
- return dest;
-}
-
-/* Since we need memmove anyway, use it as memcpy too. */
-#define memcpy memmove
-#endif
-
-#include "xz_crc32.c"
-#include "xz_dec_stream.c"
-#include "xz_dec_lzma2.c"
-#ifdef XZ_DEC_BCJ
-# include "xz_dec_bcj.c"
-#endif
-
-/**
- * xz_dec_buf() - Single-call XZ decoder
- * @b: Input and output buffers
- *
- * On success, true is returned. On error, error() is called and false is
- * returned in case error() returns.
- */
-static bool XZ_FUNC xz_dec_buf(struct xz_buf *b)
-{
- struct xz_dec *s;
- enum xz_ret ret;
-
- xz_crc32_init();
-
- s = xz_dec_init(0);
- if (s == NULL) {
- error("XZ decoder ran out of memory");
- return false;
- }
-
- ret = xz_dec_run(s, b);
- xz_dec_end(s);
-
- switch (ret) {
- case XZ_STREAM_END:
- return true;
-
- case XZ_FORMAT_ERROR:
- error("Input is not in the XZ format (wrong magic bytes)");
- break;
-
- case XZ_OPTIONS_ERROR:
- error("Input was encoded with settings that are not "
- "supported by this XZ decoder");
- break;
-
- case XZ_DATA_ERROR:
- error("XZ-compressed data is corrupt");
- break;
-
- case XZ_BUF_ERROR:
- error("Output buffer is too small or the "
- "XZ-compressed data is corrupt");
- break;
-
- default:
- error("Bug in the XZ decoder");
- break;
- }
-
- return false;
-}
diff --git a/linux/lib/xz/xz_private.h b/linux/lib/xz/xz_private.h
index 866954b..f5f4bf4 100644
--- a/linux/lib/xz/xz_private.h
+++ b/linux/lib/xz/xz_private.h
@@ -11,7 +11,8 @@
#define XZ_PRIVATE_H
#ifdef __KERNEL__
-# ifndef XZ_MEM_FUNCS
+ /* XZ_STATIC may be defined only via decompress_unxz.c. */
+# ifndef XZ_STATIC
# include <linux/slab.h>
# include <linux/vmalloc.h>
# include <linux/string.h>
@@ -21,6 +22,7 @@
# include <asm/byteorder.h>
# include <asm/unaligned.h>
# define get_le32(p) le32_to_cpup((const uint32_t *)(p))
+ /* XZ_IGNORE_KCONFIG may be defined only via decompress_unxz.c. */
# ifndef XZ_IGNORE_KCONFIG
# ifdef CONFIG_XZ_DEC_X86
# define XZ_DEC_X86
diff --git a/userspace/boottest.c b/userspace/boottest.c
index 971194e..1b59311 100644
--- a/userspace/boottest.c
+++ b/userspace/boottest.c
@@ -7,31 +7,83 @@
* You can do whatever you want with this file.
*/
+#include <stdlib.h>
+#include <string.h>
#include <stdio.h>
-static void error(const char *msg)
+#define XZ_EXTERN static
+#define COMPR_IOBUF_SIZE 4096
+
+static void error(/*const*/ char *msg)
{
fprintf(stderr, "%s\n", msg);
}
-#define XZ_MEM_FUNCS
-#include "../linux/lib/xz/xz_boot.c"
+#include "../linux/lib/decompress_unxz.c"
static uint8_t in[1024 * 1024];
static uint8_t out[1024 * 1024];
-static uint8_t heap[40 * 1024];
-int main(void)
+static int fill(void *buf, unsigned int size)
+{
+ return fread(buf, 1, size, stdin);
+}
+
+static int flush(/*const*/ void *buf, unsigned int size)
{
+ return fwrite(buf, 1, size, stdout);
+}
+
+static void test_buf_to_buf(void)
+{
+ size_t in_size;
int ret;
- struct xz_buf b = { in, 0, 0, out, 0, sizeof(out) };
- b.in_size = fread(in, 1, sizeof(in), stdin);
+ in_size = fread(in, 1, sizeof(in), stdin);
+ ret = decompress(in, in_size, NULL, NULL, out, NULL, &error);
+ /* fwrite(out, 1, FIXME, stdout); */
+ fprintf(stderr, "ret = %d\n", ret);
+}
- malloc_buf = heap;
- malloc_avail = sizeof(heap);
- ret = xz_dec_buf(&b);
+static void test_buf_to_cb(void)
+{
+ size_t in_size;
+ int in_used;
+ int ret;
+ in_size = fread(in, 1, sizeof(in), stdin);
+ ret = decompress(in, in_size, NULL, &flush, NULL, &in_used, &error);
+ fprintf(stderr, "ret = %d; in_used = %d\n", ret, in_used);
+}
+
+static void test_cb_to_buf(void)
+{
+ int in_used;
+ int ret;
+ ret = decompress(in, 0, fill, NULL, out, &in_used, &error);
+ /* fwrite(out, 1, FIXME, stdout); */
+ fprintf(stderr, "ret = %d; in_used = %d\n", ret, in_used);
+}
+
+static void test_cb_to_cb(void)
+{
+ int ret;
+ ret = decompress(NULL, 0, &fill, &flush, NULL, NULL, &error);
+ fprintf(stderr, "ret = %d\n", ret);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 2)
+ fprintf(stderr, "Usage: %s [bb|bc|cb|cc]\n", argv[0]);
+ else if (strcmp(argv[1], "bb") == 0)
+ test_buf_to_buf();
+ else if (strcmp(argv[1], "bc") == 0)
+ test_buf_to_cb();
+ else if (strcmp(argv[1], "cb") == 0)
+ test_cb_to_buf();
+ else if (strcmp(argv[1], "cc") == 0)
+ test_cb_to_cb();
+ else
+ fprintf(stderr, "Usage: %s [bb|bc|cb|cc]\n", argv[0]);
- fwrite(out, 1, b.out_pos, stdout);
- fprintf(stderr, "%d\n", ret);
return 0;
}
diff --git a/userspace/xz_config.h b/userspace/xz_config.h
index 0768089..a372442 100644
--- a/userspace/xz_config.h
+++ b/userspace/xz_config.h
@@ -18,20 +18,20 @@
/* #define XZ_DEC_ARMTHUMB */
/* #define XZ_DEC_SPARC */
-#ifndef XZ_MEM_FUNCS
-# include <stdlib.h>
-# include <string.h>
-# define kmalloc(size, flags) malloc(size)
-# define kfree(ptr) free(ptr)
-# define vmalloc(size) malloc(size)
-# define vfree(ptr) free(ptr)
-# define memeq(a, b, size) (memcmp(a, b, size) == 0)
-# define memzero(buf, size) memset(buf, 0, size)
-#endif
-
#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
#include "xz.h"
+#define kmalloc(size, flags) malloc(size)
+#define kfree(ptr) free(ptr)
+#define vmalloc(size) malloc(size)
+#define vfree(ptr) free(ptr)
+
+#define memeq(a, b, size) (memcmp(a, b, size) == 0)
+#define memzero(buf, size) memset(buf, 0, size)
+
#define min(x, y) ((x) < (y) ? (x) : (y))
#define min_t(type, x, y) min(x, y)