commit:     1925b0520f1735eb1c30313f518c521fc5478adf
Author:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
AuthorDate: Wed Apr  8 17:37:44 2020 +0000
Commit:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
CommitDate: Wed Apr  8 17:37:44 2020 +0000
URL:        https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=1925b052

Add support for ZSTD-compressed kernel and initramfs (use=experimental)

Signed-off-by: Mike Pagano <mpagano <AT> gentoo.org>

 0000_README                                        |  32 ++
 ..._ZSTD-v4-1-8-prepare-zstd-for-preboot-env.patch |  82 ++++
 ...STD-v4-2-8-prepare-xxhash-for-preboot-env.patch |  94 +++++
 ...STD-v4-3-8-add-zstd-support-to-decompress.patch | 422 +++++++++++++++++++++
 ...-v4-4-8-add-support-for-zstd-compres-kern.patch |  65 ++++
 ...add-support-for-zstd-compressed-initramfs.patch |  48 +++
 ..._ZSTD-v4-6-8-bump-ZO-z-extra-bytes-margin.patch |  20 +
 ...v4-7-8-support-for-ZSTD-compressed-kernel.patch |  92 +++++
 ...4-8-8-gitignore-add-ZSTD-compressed-files.patch |  12 +
 9 files changed, 867 insertions(+)

diff --git a/0000_README b/0000_README
index abd4b3d..7af0186 100644
--- a/0000_README
+++ b/0000_README
@@ -79,6 +79,38 @@ Patch:  4567_distro-Gentoo-Kconfig.patch
 From:   Tom Wijsman <tom...@gentoo.org>
 Desc:   Add Gentoo Linux support config settings and defaults.
 
+Patch:         5000_ZSTD-v4-1-8-prepare-zstd-for-preboot-env.patch
+From:   https://lkml.org/lkml/2020/4/1/29
+Desc:   lib: prepare zstd for preboot environment
+
+Patch:  5001_ZSTD-v4-2-8-prepare-xxhash-for-preboot-env.patch
+From:   https://lkml.org/lkml/2020/4/1/29
+Desc:   lib: prepare xxhash for preboot environment
+
+Patch:  5002_ZSTD-v4-3-8-add-zstd-support-to-decompress.patch
+From:   https://lkml.org/lkml/2020/4/1/29
+Desc:   lib: add zstd support to decompress
+
+Patch:  5003_ZSTD-v4-4-8-add-support-for-zstd-compres-kern.patch
+From:   https://lkml.org/lkml/2020/4/1/29
+Desc:   init: add support for zstd compressed kernel
+
+Patch:  5004_ZSTD-v4-5-8-add-support-for-zstd-compressed-initramfs.patch
+From:   https://lkml.org/lkml/2020/4/1/29
+Desc:   usr: add support for zstd compressed initramfs
+
+Patch:  5005_ZSTD-v4-6-8-bump-ZO-z-extra-bytes-margin.patch
+From:   https://lkml.org/lkml/2020/4/1/29
+Desc:   x86: bump ZO_z_extra_bytes margin for zstd
+
+Patch:  5006_ZSTD-v4-7-8-support-for-ZSTD-compressed-kernel.patch
+From:   https://lkml.org/lkml/2020/4/1/29
+Desc:   x86: Add support for ZSTD compressed kernel
+
+Patch:  5007_ZSTD-v4-8-8-gitignore-add-ZSTD-compressed-files.patch
+From:   https://lkml.org/lkml/2020/4/1/29
+Desc:   .gitignore: add ZSTD-compressed files
+
 Patch:  5012_enable-cpu-optimizations-for-gcc91.patch
 From:   https://github.com/graysky2/kernel_gcc_patch/
 Desc:   Kernel patch enables gcc >= v9.1 optimizations for additional CPUs.

diff --git a/5000_ZSTD-v4-1-8-prepare-zstd-for-preboot-env.patch 
b/5000_ZSTD-v4-1-8-prepare-zstd-for-preboot-env.patch
new file mode 100644
index 0000000..297a8d4
--- /dev/null
+++ b/5000_ZSTD-v4-1-8-prepare-zstd-for-preboot-env.patch
@@ -0,0 +1,82 @@
+diff --git a/lib/zstd/decompress.c b/lib/zstd/decompress.c
+index 269ee9a796c1..73ded63278cf 100644
+--- a/lib/zstd/decompress.c
++++ b/lib/zstd/decompress.c
+@@ -2490,6 +2490,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream *zds, 
ZSTD_outBuffer *output, ZSTD_inB
+       }
+ }
+ 
++#ifndef ZSTD_PREBOOT
+ EXPORT_SYMBOL(ZSTD_DCtxWorkspaceBound);
+ EXPORT_SYMBOL(ZSTD_initDCtx);
+ EXPORT_SYMBOL(ZSTD_decompressDCtx);
+@@ -2529,3 +2530,4 @@ EXPORT_SYMBOL(ZSTD_insertBlock);
+ 
+ MODULE_LICENSE("Dual BSD/GPL");
+ MODULE_DESCRIPTION("Zstd Decompressor");
++#endif
+diff --git a/lib/zstd/fse_decompress.c b/lib/zstd/fse_decompress.c
+index a84300e5a013..0b353530fb3f 100644
+--- a/lib/zstd/fse_decompress.c
++++ b/lib/zstd/fse_decompress.c
+@@ -47,6 +47,7 @@
+ ****************************************************************/
+ #include "bitstream.h"
+ #include "fse.h"
++#include "zstd_internal.h"
+ #include <linux/compiler.h>
+ #include <linux/kernel.h>
+ #include <linux/string.h> /* memcpy, memset */
+@@ -60,14 +61,6 @@
+               enum { FSE_static_assert = 1 / (int)(!!(c)) }; \
+       } /* use only *after* variable declarations */
+ 
+-/* check and forward error code */
+-#define CHECK_F(f)                  \
+-      {                           \
+-              size_t const e = f; \
+-              if (FSE_isError(e)) \
+-                      return e;   \
+-      }
+-
+ /* **************************************************************
+ *  Templates
+ ****************************************************************/
+diff --git a/lib/zstd/zstd_internal.h b/lib/zstd/zstd_internal.h
+index 1a79fab9e13a..dac753397f86 100644
+--- a/lib/zstd/zstd_internal.h
++++ b/lib/zstd/zstd_internal.h
+@@ -127,7 +127,14 @@ static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG;
+ *  Shared functions to include for inlining
+ *********************************************/
+ ZSTD_STATIC void ZSTD_copy8(void *dst, const void *src) {
+-      memcpy(dst, src, 8);
++      /*
++       * zstd relies heavily on gcc being able to analyze and inline this
++       * memcpy() call, since it is called in a tight loop. Preboot mode
++       * is compiled in freestanding mode, which stops gcc from analyzing
++       * memcpy(). Use __builtin_memcpy() to tell gcc to analyze this as a
++       * regular memcpy().
++       */
++      __builtin_memcpy(dst, src, 8);
+ }
+ /*! ZSTD_wildcopy() :
+ *   custom version of memcpy(), can copy up to 7 bytes too many (8 bytes if 
length==0) */
+@@ -137,13 +144,16 @@ ZSTD_STATIC void ZSTD_wildcopy(void *dst, const void 
*src, ptrdiff_t length)
+       const BYTE* ip = (const BYTE*)src;
+       BYTE* op = (BYTE*)dst;
+       BYTE* const oend = op + length;
+-      /* Work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81388.
++#if defined(GCC_VERSION) && GCC_VERSION >= 70000 && GCC_VERSION < 70200
++      /*
++       * Work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81388.
+        * Avoid the bad case where the loop only runs once by handling the
+        * special case separately. This doesn't trigger the bug because it
+        * doesn't involve pointer/integer overflow.
+        */
+       if (length <= 8)
+               return ZSTD_copy8(dst, src);
++#endif
+       do {
+               ZSTD_copy8(op, ip);
+               op += 8;

diff --git a/5001_ZSTD-v4-2-8-prepare-xxhash-for-preboot-env.patch 
b/5001_ZSTD-v4-2-8-prepare-xxhash-for-preboot-env.patch
new file mode 100644
index 0000000..88e4674
--- /dev/null
+++ b/5001_ZSTD-v4-2-8-prepare-xxhash-for-preboot-env.patch
@@ -0,0 +1,94 @@
+diff --git a/lib/xxhash.c b/lib/xxhash.c
+index aa61e2a3802f..b4364e011392 100644
+--- a/lib/xxhash.c
++++ b/lib/xxhash.c
+@@ -80,13 +80,11 @@ void xxh32_copy_state(struct xxh32_state *dst, const 
struct xxh32_state *src)
+ {
+       memcpy(dst, src, sizeof(*dst));
+ }
+-EXPORT_SYMBOL(xxh32_copy_state);
+ 
+ void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src)
+ {
+       memcpy(dst, src, sizeof(*dst));
+ }
+-EXPORT_SYMBOL(xxh64_copy_state);
+ 
+ /*-***************************
+  * Simple Hash Functions
+@@ -151,7 +149,6 @@ uint32_t xxh32(const void *input, const size_t len, const 
uint32_t seed)
+ 
+       return h32;
+ }
+-EXPORT_SYMBOL(xxh32);
+ 
+ static uint64_t xxh64_round(uint64_t acc, const uint64_t input)
+ {
+@@ -234,7 +231,6 @@ uint64_t xxh64(const void *input, const size_t len, const 
uint64_t seed)
+ 
+       return h64;
+ }
+-EXPORT_SYMBOL(xxh64);
+ 
+ /*-**************************************************
+  * Advanced Hash Functions
+@@ -251,7 +247,6 @@ void xxh32_reset(struct xxh32_state *statePtr, const 
uint32_t seed)
+       state.v4 = seed - PRIME32_1;
+       memcpy(statePtr, &state, sizeof(state));
+ }
+-EXPORT_SYMBOL(xxh32_reset);
+ 
+ void xxh64_reset(struct xxh64_state *statePtr, const uint64_t seed)
+ {
+@@ -265,7 +260,6 @@ void xxh64_reset(struct xxh64_state *statePtr, const 
uint64_t seed)
+       state.v4 = seed - PRIME64_1;
+       memcpy(statePtr, &state, sizeof(state));
+ }
+-EXPORT_SYMBOL(xxh64_reset);
+ 
+ int xxh32_update(struct xxh32_state *state, const void *input, const size_t 
len)
+ {
+@@ -334,7 +328,6 @@ int xxh32_update(struct xxh32_state *state, const void 
*input, const size_t len)
+ 
+       return 0;
+ }
+-EXPORT_SYMBOL(xxh32_update);
+ 
+ uint32_t xxh32_digest(const struct xxh32_state *state)
+ {
+@@ -372,7 +365,6 @@ uint32_t xxh32_digest(const struct xxh32_state *state)
+ 
+       return h32;
+ }
+-EXPORT_SYMBOL(xxh32_digest);
+ 
+ int xxh64_update(struct xxh64_state *state, const void *input, const size_t 
len)
+ {
+@@ -439,7 +431,6 @@ int xxh64_update(struct xxh64_state *state, const void 
*input, const size_t len)
+ 
+       return 0;
+ }
+-EXPORT_SYMBOL(xxh64_update);
+ 
+ uint64_t xxh64_digest(const struct xxh64_state *state)
+ {
+@@ -494,7 +485,19 @@ uint64_t xxh64_digest(const struct xxh64_state *state)
+ 
+       return h64;
+ }
++
++#ifndef XXH_PREBOOT
++EXPORT_SYMBOL(xxh32_copy_state);
++EXPORT_SYMBOL(xxh64_copy_state);
++EXPORT_SYMBOL(xxh32);
++EXPORT_SYMBOL(xxh64);
++EXPORT_SYMBOL(xxh32_reset);
++EXPORT_SYMBOL(xxh64_reset);
++EXPORT_SYMBOL(xxh32_update);
++EXPORT_SYMBOL(xxh32_digest);
++EXPORT_SYMBOL(xxh64_update);
+ EXPORT_SYMBOL(xxh64_digest);
+ 
+ MODULE_LICENSE("Dual BSD/GPL");
+ MODULE_DESCRIPTION("xxHash");
++#endif

diff --git a/5002_ZSTD-v4-3-8-add-zstd-support-to-decompress.patch 
b/5002_ZSTD-v4-3-8-add-zstd-support-to-decompress.patch
new file mode 100644
index 0000000..4f11460
--- /dev/null
+++ b/5002_ZSTD-v4-3-8-add-zstd-support-to-decompress.patch
@@ -0,0 +1,422 @@
+diff --git a/include/linux/decompress/unzstd.h 
b/include/linux/decompress/unzstd.h
+new file mode 100644
+index 000000000000..56d539ae880f
+--- /dev/null
++++ b/include/linux/decompress/unzstd.h
+@@ -0,0 +1,11 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef LINUX_DECOMPRESS_UNZSTD_H
++#define LINUX_DECOMPRESS_UNZSTD_H
++
++int unzstd(unsigned char *inbuf, long len,
++         long (*fill)(void*, unsigned long),
++         long (*flush)(void*, unsigned long),
++         unsigned char *output,
++         long *pos,
++         void (*error_fn)(char *x));
++#endif
+diff --git a/lib/Kconfig b/lib/Kconfig
+index bc7e56370129..11de5fa09a52 100644
+--- a/lib/Kconfig
++++ b/lib/Kconfig
+@@ -336,6 +336,10 @@ config DECOMPRESS_LZ4
+       select LZ4_DECOMPRESS
+       tristate
+ 
++config DECOMPRESS_ZSTD
++      select ZSTD_DECOMPRESS
++      tristate
++
+ #
+ # Generic allocator support is selected if needed
+ #
+diff --git a/lib/Makefile b/lib/Makefile
+index 611872c06926..09ad45ba6883 100644
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -160,6 +160,7 @@ lib-$(CONFIG_DECOMPRESS_LZMA) += decompress_unlzma.o
+ lib-$(CONFIG_DECOMPRESS_XZ) += decompress_unxz.o
+ lib-$(CONFIG_DECOMPRESS_LZO) += decompress_unlzo.o
+ lib-$(CONFIG_DECOMPRESS_LZ4) += decompress_unlz4.o
++lib-$(CONFIG_DECOMPRESS_ZSTD) += decompress_unzstd.o
+ 
+ obj-$(CONFIG_TEXTSEARCH) += textsearch.o
+ obj-$(CONFIG_TEXTSEARCH_KMP) += ts_kmp.o
+diff --git a/lib/decompress.c b/lib/decompress.c
+index 857ab1af1ef3..ab3fc90ffc64 100644
+--- a/lib/decompress.c
++++ b/lib/decompress.c
+@@ -13,6 +13,7 @@
+ #include <linux/decompress/inflate.h>
+ #include <linux/decompress/unlzo.h>
+ #include <linux/decompress/unlz4.h>
++#include <linux/decompress/unzstd.h>
+ 
+ #include <linux/types.h>
+ #include <linux/string.h>
+@@ -37,6 +38,9 @@
+ #ifndef CONFIG_DECOMPRESS_LZ4
+ # define unlz4 NULL
+ #endif
++#ifndef CONFIG_DECOMPRESS_ZSTD
++# define unzstd NULL
++#endif
+ 
+ struct compress_format {
+       unsigned char magic[2];
+@@ -52,6 +56,7 @@ static const struct compress_format compressed_formats[] 
__initconst = {
+       { {0xfd, 0x37}, "xz", unxz },
+       { {0x89, 0x4c}, "lzo", unlzo },
+       { {0x02, 0x21}, "lz4", unlz4 },
++      { {0x28, 0xb5}, "zstd", unzstd },
+       { {0, 0}, NULL, NULL }
+ };
+ 
+diff --git a/lib/decompress_unzstd.c b/lib/decompress_unzstd.c
+new file mode 100644
+index 000000000000..f317afab502f
+--- /dev/null
++++ b/lib/decompress_unzstd.c
+@@ -0,0 +1,342 @@
++// SPDX-License-Identifier: GPL-2.0
++
++/*
++ * 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 safety margin for ZSTD with a 128 KB block size is calculated below.
++ * Note that the margin with ZSTD is bigger than with GZIP or XZ!
++ *
++ * 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 .zst file in case of a compresed kernel is as follows.
++ * Maximum sizes (as bytes) of the fields are in parenthesis.
++ *
++ *    Frame Header: (18)
++ *    Blocks: (N)
++ *    Checksum: (4)
++ *
++ * The frame header and checksum overhead is at most 22 bytes.
++ *
++ * ZSTD stores the data in blocks. Each block has a header whose size is
++ * a 3 bytes. After the block header, there is up to 128 KB of payload.
++ * The maximum uncompressed size of the payload is 128 KB. The minimum
++ * uncompressed size of the payload is never less than the payload size
++ * (excluding the block header).
++ *
++ * 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
++ *   - 22 bytes for the .zst file format headers;
++ *   - 3 bytes per every 128 KiB of uncompressed size (one block header per
++ *     block); and
++ *   - 128 KiB (biggest possible zstd block size) to make sure that the
++ *     decompressor never overwrites anything from the block it is currently
++ *     reading.
++ *
++ * We get the following formula:
++ *
++ *    safety_margin = 22 + uncompressed_size * 3 / 131072 + 131072
++ *                 <= 22 + (uncompressed_size >> 15) + 131072
++ */
++
++/*
++ * Preboot environments #include "path/to/decompress_unzstd.c".
++ * All of the source files we depend on must be #included.
++ * zstd's only source dependeny is xxhash, which has no source
++ * dependencies.
++ *
++ * zstd and xxhash avoid declaring themselves as modules
++ * when ZSTD_PREBOOT and XXH_PREBOOT are defined.
++ */
++#ifdef STATIC
++# define ZSTD_PREBOOT
++# define XXH_PREBOOT
++# include "xxhash.c"
++# include "zstd/entropy_common.c"
++# include "zstd/fse_decompress.c"
++# include "zstd/huf_decompress.c"
++# include "zstd/zstd_common.c"
++# include "zstd/decompress.c"
++#endif
++
++#include <linux/decompress/mm.h>
++#include <linux/kernel.h>
++#include <linux/zstd.h>
++
++/* 128MB is the maximum window size supported by zstd. */
++#define ZSTD_WINDOWSIZE_MAX   (1 << ZSTD_WINDOWLOG_MAX)
++/* Size of the input and output buffers in multi-call mode.
++ * Pick a larger size because it isn't used during kernel decompression,
++ * since that is single pass, and we have to allocate a large buffer for
++ * zstd's window anyways. The larger size speeds up initramfs decompression.
++ */
++#define ZSTD_IOBUF_SIZE               (1 << 17)
++
++static int INIT handle_zstd_error(size_t ret, void (*error)(char *x))
++{
++      const int err = ZSTD_getErrorCode(ret);
++
++      if (!ZSTD_isError(ret))
++              return 0;
++
++      switch (err) {
++      case ZSTD_error_memory_allocation:
++              error("ZSTD decompressor ran out of memory");
++              break;
++      case ZSTD_error_prefix_unknown:
++              error("Input is not in the ZSTD format (wrong magic bytes)");
++              break;
++      case ZSTD_error_dstSize_tooSmall:
++      case ZSTD_error_corruption_detected:
++      case ZSTD_error_checksum_wrong:
++              error("ZSTD-compressed data is corrupt");
++              break;
++      default:
++              error("ZSTD-compressed data is probably corrupt");
++              break;
++      }
++      return -1;
++}
++
++/*
++ * Handle the case where we have the entire input and output in one segment.
++ * We can allocate less memory (no circular buffer for the sliding window),
++ * and avoid some memcpy() calls.
++ */
++static int INIT decompress_single(const u8 *in_buf, long in_len, u8 *out_buf,
++                                long out_len, long *in_pos,
++                                void (*error)(char *x))
++{
++      const size_t wksp_size = ZSTD_DCtxWorkspaceBound();
++      void *wksp = large_malloc(wksp_size);
++      ZSTD_DCtx *dctx = ZSTD_initDCtx(wksp, wksp_size);
++      int err;
++      size_t ret;
++
++      if (dctx == NULL) {
++              error("Out of memory while allocating ZSTD_DCtx");
++              err = -1;
++              goto out;
++      }
++      /*
++       * Find out how large the frame actually is, there may be junk at
++       * the end of the frame that ZSTD_decompressDCtx() can't handle.
++       */
++      ret = ZSTD_findFrameCompressedSize(in_buf, in_len);
++      err = handle_zstd_error(ret, error);
++      if (err)
++              goto out;
++      in_len = (long)ret;
++
++      ret = ZSTD_decompressDCtx(dctx, out_buf, out_len, in_buf, in_len);
++      err = handle_zstd_error(ret, error);
++      if (err)
++              goto out;
++
++      if (in_pos != NULL)
++              *in_pos = in_len;
++
++      err = 0;
++out:
++      if (wksp != NULL)
++              large_free(wksp);
++      return err;
++}
++
++static int INIT __unzstd(unsigned char *in_buf, long in_len,
++                       long (*fill)(void*, unsigned long),
++                       long (*flush)(void*, unsigned long),
++                       unsigned char *out_buf, long out_len,
++                       long *in_pos,
++                       void (*error)(char *x))
++{
++      ZSTD_inBuffer in;
++      ZSTD_outBuffer out;
++      ZSTD_frameParams params;
++      void *in_allocated = NULL;
++      void *out_allocated = NULL;
++      void *wksp = NULL;
++      size_t wksp_size;
++      ZSTD_DStream *dstream;
++      int err;
++      size_t ret;
++
++      if (out_len == 0)
++              out_len = LONG_MAX; /* no limit */
++
++      if (fill == NULL && flush == NULL)
++              /*
++               * We can decompress faster and with less memory when we have a
++               * single chunk.
++               */
++              return decompress_single(in_buf, in_len, out_buf, out_len,
++                                       in_pos, error);
++
++      /*
++       * If in_buf is not provided, we must be using fill(), so allocate
++       * a large enough buffer. If it is provided, it must be at least
++       * ZSTD_IOBUF_SIZE large.
++       */
++      if (in_buf == NULL) {
++              in_allocated = large_malloc(ZSTD_IOBUF_SIZE);
++              if (in_allocated == NULL) {
++                      error("Out of memory while allocating input buffer");
++                      err = -1;
++                      goto out;
++              }
++              in_buf = in_allocated;
++              in_len = 0;
++      }
++      /* Read the first chunk, since we need to decode the frame header. */
++      if (fill != NULL)
++              in_len = fill(in_buf, ZSTD_IOBUF_SIZE);
++      if (in_len < 0) {
++              error("ZSTD-compressed data is truncated");
++              err = -1;
++              goto out;
++      }
++      /* Set the first non-empty input buffer. */
++      in.src = in_buf;
++      in.pos = 0;
++      in.size = in_len;
++      /* Allocate the output buffer if we are using flush(). */
++      if (flush != NULL) {
++              out_allocated = large_malloc(ZSTD_IOBUF_SIZE);
++              if (out_allocated == NULL) {
++                      error("Out of memory while allocating output buffer");
++                      err = -1;
++                      goto out;
++              }
++              out_buf = out_allocated;
++              out_len = ZSTD_IOBUF_SIZE;
++      }
++      /* Set the output buffer. */
++      out.dst = out_buf;
++      out.pos = 0;
++      out.size = out_len;
++
++      /*
++       * We need to know the window size to allocate the ZSTD_DStream.
++       * Since we are streaming, we need to allocate a buffer for the sliding
++       * window. The window size varies from 1 KB to ZSTD_WINDOWSIZE_MAX
++       * (8 MB), so it is important to use the actual value so as not to
++       * waste memory when it is smaller.
++       */
++      ret = ZSTD_getFrameParams(&params, in.src, in.size);
++      err = handle_zstd_error(ret, error);
++      if (err)
++              goto out;
++      if (ret != 0) {
++              error("ZSTD-compressed data has an incomplete frame header");
++              err = -1;
++              goto out;
++      }
++      if (params.windowSize > ZSTD_WINDOWSIZE_MAX) {
++              error("ZSTD-compressed data has too large a window size");
++              err = -1;
++              goto out;
++      }
++
++      /*
++       * Allocate the ZSTD_DStream now that we know how much memory is
++       * required.
++       */
++      wksp_size = ZSTD_DStreamWorkspaceBound(params.windowSize);
++      wksp = large_malloc(wksp_size);
++      dstream = ZSTD_initDStream(params.windowSize, wksp, wksp_size);
++      if (dstream == NULL) {
++              error("Out of memory while allocating ZSTD_DStream");
++              err = -1;
++              goto out;
++      }
++
++      /*
++       * Decompression loop:
++       * Read more data if necessary (error if no more data can be read).
++       * Call the decompression function, which returns 0 when finished.
++       * Flush any data produced if using flush().
++       */
++      if (in_pos != NULL)
++              *in_pos = 0;
++      do {
++              /*
++               * If we need to reload data, either we have fill() and can
++               * try to get more data, or we don't and the input is truncated.
++               */
++              if (in.pos == in.size) {
++                      if (in_pos != NULL)
++                              *in_pos += in.pos;
++                      in_len = fill ? fill(in_buf, ZSTD_IOBUF_SIZE) : -1;
++                      if (in_len < 0) {
++                              error("ZSTD-compressed data is truncated");
++                              err = -1;
++                              goto out;
++                      }
++                      in.pos = 0;
++                      in.size = in_len;
++              }
++              /* Returns zero when the frame is complete. */
++              ret = ZSTD_decompressStream(dstream, &out, &in);
++              err = handle_zstd_error(ret, error);
++              if (err)
++                      goto out;
++              /* Flush all of the data produced if using flush(). */
++              if (flush != NULL && out.pos > 0) {
++                      if (out.pos != flush(out.dst, out.pos)) {
++                              error("Failed to flush()");
++                              err = -1;
++                              goto out;
++                      }
++                      out.pos = 0;
++              }
++      } while (ret != 0);
++
++      if (in_pos != NULL)
++              *in_pos += in.pos;
++
++      err = 0;
++out:
++      if (in_allocated != NULL)
++              large_free(in_allocated);
++      if (out_allocated != NULL)
++              large_free(out_allocated);
++      if (wksp != NULL)
++              large_free(wksp);
++      return err;
++}
++
++#ifndef ZSTD_PREBOOT
++STATIC int INIT unzstd(unsigned char *buf, long len,
++                     long (*fill)(void*, unsigned long),
++                     long (*flush)(void*, unsigned long),
++                     unsigned char *out_buf,
++                     long *pos,
++                     void (*error)(char *x))
++{
++      return __unzstd(buf, len, fill, flush, out_buf, 0, pos, error);
++}
++#else
++STATIC int INIT __decompress(unsigned char *buf, long len,
++                           long (*fill)(void*, unsigned long),
++                           long (*flush)(void*, unsigned long),
++                           unsigned char *out_buf, long out_len,
++                           long *pos,
++                           void (*error)(char *x))
++{
++      return __unzstd(buf, len, fill, flush, out_buf, out_len, pos, error);
++}
++#endif

diff --git a/5003_ZSTD-v4-4-8-add-support-for-zstd-compres-kern.patch 
b/5003_ZSTD-v4-4-8-add-support-for-zstd-compres-kern.patch
new file mode 100644
index 0000000..e6598e6
--- /dev/null
+++ b/5003_ZSTD-v4-4-8-add-support-for-zstd-compres-kern.patch
@@ -0,0 +1,65 @@
+diff --git a/init/Kconfig b/init/Kconfig
+index 20a6ac33761c..9b646a25918e 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -173,13 +173,16 @@ config HAVE_KERNEL_LZO
+ config HAVE_KERNEL_LZ4
+       bool
+ 
++config HAVE_KERNEL_ZSTD
++      bool
++
+ config HAVE_KERNEL_UNCOMPRESSED
+       bool
+ 
+ choice
+       prompt "Kernel compression mode"
+       default KERNEL_GZIP
+-      depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || 
HAVE_KERNEL_XZ || HAVE_KERNEL_LZO || HAVE_KERNEL_LZ4 || HAVE_KERNEL_UNCOMPRESSED
++      depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || 
HAVE_KERNEL_XZ || HAVE_KERNEL_LZO || HAVE_KERNEL_LZ4 || HAVE_KERNEL_ZSTD || 
HAVE_KERNEL_UNCOMPRESSED
+       help
+         The linux kernel is a kind of self-extracting executable.
+         Several compression algorithms are available, which differ
+@@ -258,6 +261,16 @@ config KERNEL_LZ4
+         is about 8% bigger than LZO. But the decompression speed is
+         faster than LZO.
+ 
++config KERNEL_ZSTD
++      bool "ZSTD"
++      depends on HAVE_KERNEL_ZSTD
++      help
++        ZSTD is a compression algorithm targeting intermediate compression
++        with fast decompression speed. It will compress better than GZIP and
++        decompress around the same speed as LZO, but slower than LZ4. You
++        will need at least 192 KB RAM or more for booting. The zstd command
++        line tools is required for compression.
++
+ config KERNEL_UNCOMPRESSED
+       bool "None"
+       depends on HAVE_KERNEL_UNCOMPRESSED
+diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
+index 752ff0a225a9..4b99893efa3d 100644
+--- a/scripts/Makefile.lib
++++ b/scripts/Makefile.lib
+@@ -394,6 +394,21 @@ quiet_cmd_xzkern = XZKERN  $@
+ quiet_cmd_xzmisc = XZMISC  $@
+       cmd_xzmisc = cat $(real-prereqs) | xz --check=crc32 --lzma2=dict=1MiB > 
$@
+ 
++# ZSTD
++# ---------------------------------------------------------------------------
++# Appends the uncompressed size of the data using size_append. The .zst
++# format has the size information available at the beginning of the file too,
++# but it's in a more complex format and it's good to avoid changing the part
++# of the boot code that reads the uncompressed size.
++# Note that the bytes added by size_append will make the zstd tool think that
++# the file is corrupt. This is expected.
++
++quiet_cmd_zstd = ZSTD    $@
++cmd_zstd = (cat $(filter-out FORCE,$^) | \
++      zstd -19 && \
++        $(call size_append, $(filter-out FORCE,$^))) > $@ || \
++      (rm -f $@ ; false)
++
+ # ASM offsets
+ # ---------------------------------------------------------------------------
+ 

diff --git a/5004_ZSTD-v4-5-8-add-support-for-zstd-compressed-initramfs.patch 
b/5004_ZSTD-v4-5-8-add-support-for-zstd-compressed-initramfs.patch
new file mode 100644
index 0000000..6054414
--- /dev/null
+++ b/5004_ZSTD-v4-5-8-add-support-for-zstd-compressed-initramfs.patch
@@ -0,0 +1,48 @@
+diff --git a/usr/Kconfig b/usr/Kconfig
+index bdf5bbd40727..43aca37d09b5 100644
+--- a/usr/Kconfig
++++ b/usr/Kconfig
+@@ -100,6 +100,15 @@ config RD_LZ4
+         Support loading of a LZ4 encoded initial ramdisk or cpio buffer
+         If unsure, say N.
+ 
++config RD_ZSTD
++      bool "Support initial ramdisk/ramfs compressed using ZSTD"
++      default y
++      depends on BLK_DEV_INITRD
++      select DECOMPRESS_ZSTD
++      help
++        Support loading of a ZSTD encoded initial ramdisk or cpio buffer.
++        If unsure, say N.
++
+ choice
+       prompt "Built-in initramfs compression mode"
+       depends on INITRAMFS_SOURCE != ""
+@@ -207,4 +216,15 @@ config INITRAMFS_COMPRESSION_LZ4
+         If you choose this, keep in mind that most distros don't provide lz4
+         by default which could cause a build failure.
+ 
++config INITRAMFS_COMPRESSION_ZSTD
++      bool "ZSTD"
++      depends on RD_ZSTD
++      help
++        ZSTD is a compression algorithm targeting intermediate compression
++        with fast decompression speed. It will compress better than GZIP and
++        decompress around the same speed as LZO, but slower than LZ4.
++
++        If you choose this, keep in mind that you may need to install the zstd
++        tool to be able to compress the initram.
++
+ endchoice
+diff --git a/usr/Makefile b/usr/Makefile
+index c12e6b15ce72..b1a81a40eab1 100644
+--- a/usr/Makefile
++++ b/usr/Makefile
+@@ -15,6 +15,7 @@ compress-$(CONFIG_INITRAMFS_COMPRESSION_LZMA)        := lzma
+ compress-$(CONFIG_INITRAMFS_COMPRESSION_XZ)   := xzmisc
+ compress-$(CONFIG_INITRAMFS_COMPRESSION_LZO)  := lzo
+ compress-$(CONFIG_INITRAMFS_COMPRESSION_LZ4)  := lz4
++compress-$(CONFIG_INITRAMFS_COMPRESSION_ZSTD) := zstd
+ 
+ obj-$(CONFIG_BLK_DEV_INITRD) := initramfs_data.o
+ 

diff --git a/5005_ZSTD-v4-6-8-bump-ZO-z-extra-bytes-margin.patch 
b/5005_ZSTD-v4-6-8-bump-ZO-z-extra-bytes-margin.patch
new file mode 100644
index 0000000..b4fd239
--- /dev/null
+++ b/5005_ZSTD-v4-6-8-bump-ZO-z-extra-bytes-margin.patch
@@ -0,0 +1,20 @@
+diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
+index 97d9b6d6c1af..b820875c5c95 100644
+--- a/arch/x86/boot/header.S
++++ b/arch/x86/boot/header.S
+@@ -536,8 +536,14 @@ pref_address:             .quad LOAD_PHYSICAL_ADDR        
# preferred load addr
+ # the size-dependent part now grows so fast.
+ #
+ # extra_bytes = (uncompressed_size >> 8) + 65536
++#
++# ZSTD compressed data grows by at most 3 bytes per 128K, and only has a 22
++# byte fixed overhead but has a maximum block size of 128K, so it needs a
++# larger margin.
++#
++# extra_bytes = (uncompressed_size >> 8) + 131072
+ 
+-#define ZO_z_extra_bytes      ((ZO_z_output_len >> 8) + 65536)
++#define ZO_z_extra_bytes      ((ZO_z_output_len >> 8) + 131072)
+ #if ZO_z_output_len > ZO_z_input_len
+ # define ZO_z_extract_offset  (ZO_z_output_len + ZO_z_extra_bytes - \
+                                ZO_z_input_len)

diff --git a/5006_ZSTD-v4-7-8-support-for-ZSTD-compressed-kernel.patch 
b/5006_ZSTD-v4-7-8-support-for-ZSTD-compressed-kernel.patch
new file mode 100644
index 0000000..5fc8a77
--- /dev/null
+++ b/5006_ZSTD-v4-7-8-support-for-ZSTD-compressed-kernel.patch
@@ -0,0 +1,92 @@
+diff --git a/Documentation/x86/boot.rst b/Documentation/x86/boot.rst
+index c9c201596c3e..cedcf4d49bf0 100644
+--- a/Documentation/x86/boot.rst
++++ b/Documentation/x86/boot.rst
+@@ -786,9 +786,9 @@ Protocol:  2.08+
+   uncompressed data should be determined using the standard magic
+   numbers.  The currently supported compression formats are gzip
+   (magic numbers 1F 8B or 1F 9E), bzip2 (magic number 42 5A), LZMA
+-  (magic number 5D 00), XZ (magic number FD 37), and LZ4 (magic number
+-  02 21).  The uncompressed payload is currently always ELF (magic
+-  number 7F 45 4C 46).
++  (magic number 5D 00), XZ (magic number FD 37), LZ4 (magic number
++  02 21) and ZSTD (magic number 28 B5). The uncompressed payload is
++  currently always ELF (magic number 7F 45 4C 46).
+ 
+ ============  ==============
+ Field name:   payload_length
+diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
+index beea77046f9b..12d88997a3a6 100644
+--- a/arch/x86/Kconfig
++++ b/arch/x86/Kconfig
+@@ -183,6 +183,7 @@ config X86
+       select HAVE_KERNEL_LZMA
+       select HAVE_KERNEL_LZO
+       select HAVE_KERNEL_XZ
++      select HAVE_KERNEL_ZSTD
+       select HAVE_KPROBES
+       select HAVE_KPROBES_ON_FTRACE
+       select HAVE_FUNCTION_ERROR_INJECTION
+diff --git a/arch/x86/boot/compressed/Makefile 
b/arch/x86/boot/compressed/Makefile
+index 26050ae0b27e..8233f598f15b 100644
+--- a/arch/x86/boot/compressed/Makefile
++++ b/arch/x86/boot/compressed/Makefile
+@@ -24,7 +24,7 @@ OBJECT_FILES_NON_STANDARD    := y
+ KCOV_INSTRUMENT               := n
+ 
+ targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 
vmlinux.bin.lzma \
+-      vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4
++      vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4 vmlinux.bin.zst
+ 
+ KBUILD_CFLAGS := -m$(BITS) -O2
+ KBUILD_CFLAGS += -fno-strict-aliasing $(call cc-option, -fPIE, -fPIC)
+@@ -145,6 +145,8 @@ $(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y) FORCE
+       $(call if_changed,lzo)
+ $(obj)/vmlinux.bin.lz4: $(vmlinux.bin.all-y) FORCE
+       $(call if_changed,lz4)
++$(obj)/vmlinux.bin.zst: $(vmlinux.bin.all-y) FORCE
++      $(call if_changed,zstd)
+ 
+ suffix-$(CONFIG_KERNEL_GZIP)  := gz
+ suffix-$(CONFIG_KERNEL_BZIP2) := bz2
+@@ -152,6 +154,7 @@ suffix-$(CONFIG_KERNEL_LZMA)       := lzma
+ suffix-$(CONFIG_KERNEL_XZ)    := xz
+ suffix-$(CONFIG_KERNEL_LZO)   := lzo
+ suffix-$(CONFIG_KERNEL_LZ4)   := lz4
++suffix-$(CONFIG_KERNEL_ZSTD)  := zst
+ 
+ quiet_cmd_mkpiggy = MKPIGGY $@
+       cmd_mkpiggy = $(obj)/mkpiggy $< > $@
+diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
+index 9652d5c2afda..39e592d0e0b4 100644
+--- a/arch/x86/boot/compressed/misc.c
++++ b/arch/x86/boot/compressed/misc.c
+@@ -77,6 +77,10 @@ static int lines, cols;
+ #ifdef CONFIG_KERNEL_LZ4
+ #include "../../../../lib/decompress_unlz4.c"
+ #endif
++
++#ifdef CONFIG_KERNEL_ZSTD
++#include "../../../../lib/decompress_unzstd.c"
++#endif
+ /*
+  * NOTE: When adding a new decompressor, please update the analysis in
+  * ../header.S.
+diff --git a/arch/x86/include/asm/boot.h b/arch/x86/include/asm/boot.h
+index 680c320363db..d6dd43d25d9f 100644
+--- a/arch/x86/include/asm/boot.h
++++ b/arch/x86/include/asm/boot.h
+@@ -24,9 +24,11 @@
+ # error "Invalid value for CONFIG_PHYSICAL_ALIGN"
+ #endif
+ 
+-#ifdef CONFIG_KERNEL_BZIP2
++#if defined(CONFIG_KERNEL_BZIP2)
+ # define BOOT_HEAP_SIZE               0x400000
+-#else /* !CONFIG_KERNEL_BZIP2 */
++#elif defined(CONFIG_KERNEL_ZSTD)
++# define BOOT_HEAP_SIZE                0x30000
++#else
+ # define BOOT_HEAP_SIZE                0x10000
+ #endif
+ 

diff --git a/5007_ZSTD-v4-8-8-gitignore-add-ZSTD-compressed-files.patch 
b/5007_ZSTD-v4-8-8-gitignore-add-ZSTD-compressed-files.patch
new file mode 100644
index 0000000..7506899
--- /dev/null
+++ b/5007_ZSTD-v4-8-8-gitignore-add-ZSTD-compressed-files.patch
@@ -0,0 +1,12 @@
+diff --git a/.gitignore b/.gitignore
+index 72ef86a5570d..edb0191c294f 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -43,6 +43,7 @@
+ *.tab.[ch]
+ *.tar
+ *.xz
++*.zst
+ Module.symvers
+ modules.builtin
+ modules.order

Reply via email to