From 79298bf187181e9edc37c5b766ae4020d9972d9f Mon Sep 17 00:00:00 2001
From: Nick Terrell <terrelln@fb.com>
Date: Tue, 4 Apr 2017 11:53:22 -0700
Subject: [PATCH] Add userland test with mock kernel headers

---
 contrib/linux-kernel/test/.gitignore          |   1 +
 contrib/linux-kernel/test/Makefile            |  27 +
 contrib/linux-kernel/test/UserlandTest.cpp    | 479 ++++++++++++++++++
 .../linux-kernel/test/include/asm/unaligned.h | 177 +++++++
 .../test/include/linux/compiler.h             |  12 +
 .../linux-kernel/test/include/linux/kernel.h  |  14 +
 .../linux-kernel/test/include/linux/string.h  |   1 +
 .../linux-kernel/test/include/linux/types.h   |   2 +
 8 files changed, 713 insertions(+)
 create mode 100644 contrib/linux-kernel/test/.gitignore
 create mode 100644 contrib/linux-kernel/test/Makefile
 create mode 100644 contrib/linux-kernel/test/UserlandTest.cpp
 create mode 100644 contrib/linux-kernel/test/include/asm/unaligned.h
 create mode 100644 contrib/linux-kernel/test/include/linux/compiler.h
 create mode 100644 contrib/linux-kernel/test/include/linux/kernel.h
 create mode 100644 contrib/linux-kernel/test/include/linux/string.h
 create mode 100644 contrib/linux-kernel/test/include/linux/types.h

diff --git a/contrib/linux-kernel/test/.gitignore b/contrib/linux-kernel/test/.gitignore
new file mode 100644
index 000000000..4fc10228d
--- /dev/null
+++ b/contrib/linux-kernel/test/.gitignore
@@ -0,0 +1 @@
+*Test
diff --git a/contrib/linux-kernel/test/Makefile b/contrib/linux-kernel/test/Makefile
new file mode 100644
index 000000000..b16964f84
--- /dev/null
+++ b/contrib/linux-kernel/test/Makefile
@@ -0,0 +1,27 @@
+
+IFLAGS := -isystem include/ -I ../include/ -I ../lib/ -isystem googletest/googletest/include
+
+SOURCES := $(wildcard ../lib/*.c)
+OBJECTS := $(patsubst %.c,%.o,$(SOURCES))
+
+ARFLAGS := rcs
+CXXFLAGS += -std=c++11
+CFLAGS += -g -O0
+CPPFLAGS += $(IFLAGS)
+
+../lib/libzstd.a: $(OBJECTS)
+	$(AR) $(ARFLAGS) $@ $^
+
+UserlandTest: UserlandTest.cpp ../lib/libzstd.a
+	$(CXX) $(CXXFLAGS) $(CFLAGS) $(CPPFLAGS) $^ googletest/build/googlemock/gtest/libgtest.a googletest/build/googlemock/gtest/libgtest_main.a -o $@
+
+# Install googletest
+.PHONY: googletest
+googletest:
+	@$(RM) -rf googletest
+	@git clone https://github.com/google/googletest
+	@mkdir -p googletest/build
+	@cd googletest/build && cmake .. && $(MAKE)
+
+clean:
+	$(RM) -f *.{o,a} ../lib/*.{o,a}
diff --git a/contrib/linux-kernel/test/UserlandTest.cpp b/contrib/linux-kernel/test/UserlandTest.cpp
new file mode 100644
index 000000000..7bdbd1bf7
--- /dev/null
+++ b/contrib/linux-kernel/test/UserlandTest.cpp
@@ -0,0 +1,479 @@
+extern "C" {
+#include <zstd.h>
+}
+#include <gtest/gtest.h>
+#include <memory>
+#include <string>
+#include <iostream>
+
+using namespace std;
+
+namespace {
+struct WorkspaceDeleter {
+  void *memory;
+
+  template <typename T> void operator()(T const *) { free(memory); }
+};
+
+std::unique_ptr<ZSTD_CCtx, WorkspaceDeleter>
+createCCtx(ZSTD_compressionParameters cParams) {
+  size_t const workspaceSize = ZSTD_CCtxWorkspaceBound(cParams);
+  void *workspace = malloc(workspaceSize);
+  std::unique_ptr<ZSTD_CCtx, WorkspaceDeleter> cctx{
+      ZSTD_createCCtx(workspace, workspaceSize), WorkspaceDeleter{workspace}};
+  if (!cctx) {
+    throw std::runtime_error{"Bad cctx"};
+  }
+  return cctx;
+}
+
+std::unique_ptr<ZSTD_CCtx, WorkspaceDeleter>
+createCCtx(int level, unsigned long long estimatedSrcSize = 0,
+           size_t dictSize = 0) {
+  auto const cParams = ZSTD_getCParams(level, estimatedSrcSize, dictSize);
+  return createCCtx(cParams);
+}
+
+std::unique_ptr<ZSTD_DCtx, WorkspaceDeleter>
+createDCtx() {
+  size_t const workspaceSize = ZSTD_DCtxWorkspaceBound();
+  void *workspace = malloc(workspaceSize);
+  std::unique_ptr<ZSTD_DCtx, WorkspaceDeleter> dctx{
+      ZSTD_createDCtx(workspace, workspaceSize), WorkspaceDeleter{workspace}};
+  if (!dctx) {
+    throw std::runtime_error{"Bad dctx"};
+  }
+  return dctx;
+}
+
+std::unique_ptr<ZSTD_CDict, WorkspaceDeleter>
+createCDict(std::string const& dict, ZSTD_parameters params) {
+  size_t const workspaceSize = ZSTD_CDictWorkspaceBound(params.cParams);
+  void *workspace = malloc(workspaceSize);
+  std::unique_ptr<ZSTD_CDict, WorkspaceDeleter> cdict{
+      ZSTD_createCDict(dict.data(), dict.size(), params, workspace,
+                       workspaceSize),
+      WorkspaceDeleter{workspace}};
+  if (!cdict) {
+    throw std::runtime_error{"Bad cdict"};
+  }
+  return cdict;
+}
+
+std::unique_ptr<ZSTD_CDict, WorkspaceDeleter>
+createCDict(std::string const& dict, int level) {
+  auto const params = ZSTD_getParams(level, 0, dict.size());
+  return createCDict(dict, params);
+}
+
+std::unique_ptr<ZSTD_DDict, WorkspaceDeleter>
+createDDict(std::string const& dict) {
+  size_t const workspaceSize = ZSTD_DDictWorkspaceBound();
+  void *workspace = malloc(workspaceSize);
+  std::unique_ptr<ZSTD_DDict, WorkspaceDeleter> ddict{
+      ZSTD_createDDict(dict.data(), dict.size(), workspace, workspaceSize),
+      WorkspaceDeleter{workspace}};
+  if (!ddict) {
+    throw std::runtime_error{"Bad ddict"};
+  }
+  return ddict;
+}
+
+std::unique_ptr<ZSTD_CStream, WorkspaceDeleter>
+createCStream(ZSTD_parameters params, unsigned long long pledgedSrcSize = 0) {
+  size_t const workspaceSize = ZSTD_CStreamWorkspaceBound(params.cParams);
+  void *workspace = malloc(workspaceSize);
+  std::unique_ptr<ZSTD_CStream, WorkspaceDeleter> zcs{
+      ZSTD_createCStream(params, pledgedSrcSize, workspace, workspaceSize)};
+  if (!zcs) {
+    throw std::runtime_error{"bad cstream"};
+  }
+  return zcs;
+}
+
+std::unique_ptr<ZSTD_CStream, WorkspaceDeleter>
+createCStream(ZSTD_compressionParameters cParams, ZSTD_CDict const &cdict,
+              unsigned long long pledgedSrcSize = 0) {
+  size_t const workspaceSize = ZSTD_CStreamWorkspaceBound(cParams);
+  void *workspace = malloc(workspaceSize);
+  std::unique_ptr<ZSTD_CStream, WorkspaceDeleter> zcs{
+      ZSTD_createCStream_usingCDict(&cdict, pledgedSrcSize, workspace,
+                                    workspaceSize)};
+  if (!zcs) {
+    throw std::runtime_error{"bad cstream"};
+  }
+  return zcs;
+}
+
+std::unique_ptr<ZSTD_CStream, WorkspaceDeleter>
+createCStream(int level, unsigned long long pledgedSrcSize = 0) {
+  auto const params = ZSTD_getParams(level, pledgedSrcSize, 0);
+  return createCStream(params, pledgedSrcSize);
+}
+
+std::unique_ptr<ZSTD_DStream, WorkspaceDeleter>
+createDStream(size_t maxWindowSize = (1ULL << ZSTD_WINDOWLOG_MAX),
+              ZSTD_DDict const *ddict = nullptr) {
+  size_t const workspaceSize = ZSTD_DStreamWorkspaceBound(maxWindowSize);
+  void *workspace = malloc(workspaceSize);
+  std::unique_ptr<ZSTD_DStream, WorkspaceDeleter> zds{
+      ddict == nullptr
+          ? ZSTD_createDStream(maxWindowSize, workspace, workspaceSize)
+          : ZSTD_createDStream_usingDDict(maxWindowSize, ddict, workspace,
+                                          workspaceSize)};
+  if (!zds) {
+    throw std::runtime_error{"bad dstream"};
+  }
+  return zds;
+}
+
+std::string compress(ZSTD_CCtx &cctx, std::string const &data,
+                     ZSTD_parameters params, std::string const &dict = "") {
+  std::string compressed;
+  compressed.resize(ZSTD_compressBound(data.size()));
+  size_t const rc =
+      dict.empty()
+          ? ZSTD_compressCCtx(&cctx, &compressed[0], compressed.size(),
+                              data.data(), data.size(), params)
+          : ZSTD_compress_usingDict(&cctx, &compressed[0], compressed.size(),
+                                    data.data(), data.size(), dict.data(),
+                                    dict.size(), params);
+  if (ZSTD_isError(rc)) {
+    throw std::runtime_error{"compression error"};
+  }
+  compressed.resize(rc);
+  return compressed;
+}
+
+std::string compress(ZSTD_CCtx& cctx, std::string const& data, int level, std::string const& dict = "") {
+  auto const params = ZSTD_getParams(level, 0, dict.size());
+  return compress(cctx, data, params, dict);
+}
+
+std::string decompress(ZSTD_DCtx& dctx, std::string const& compressed, size_t decompressedSize, std::string const& dict = "") {
+  std::string decompressed;
+  decompressed.resize(decompressedSize);
+  size_t const rc =
+      dict.empty()
+          ? ZSTD_decompressDCtx(&dctx, &decompressed[0], decompressed.size(),
+                                compressed.data(), compressed.size())
+          : ZSTD_decompress_usingDict(
+                &dctx, &decompressed[0], decompressed.size(), compressed.data(),
+                compressed.size(), dict.data(), dict.size());
+  if (ZSTD_isError(rc)) {
+    throw std::runtime_error{"decompression error"};
+  }
+  decompressed.resize(rc);
+  return decompressed;
+}
+
+std::string compress(ZSTD_CCtx& cctx, std::string const& data, ZSTD_CDict& cdict) {
+  std::string compressed;
+  compressed.resize(ZSTD_compressBound(data.size()));
+  size_t const rc =
+      ZSTD_compress_usingCDict(&cctx, &compressed[0], compressed.size(),
+                               data.data(), data.size(), &cdict);
+  if (ZSTD_isError(rc)) {
+    throw std::runtime_error{"compression error"};
+  }
+  compressed.resize(rc);
+  return compressed;
+}
+
+std::string decompress(ZSTD_DCtx& dctx, std::string const& compressed, size_t decompressedSize, ZSTD_DDict& ddict) {
+  std::string decompressed;
+  decompressed.resize(decompressedSize);
+  size_t const rc =
+      ZSTD_decompress_usingDDict(&dctx, &decompressed[0], decompressed.size(),
+                                 compressed.data(), compressed.size(), &ddict);
+  if (ZSTD_isError(rc)) {
+    throw std::runtime_error{"decompression error"};
+  }
+  decompressed.resize(rc);
+  return decompressed;
+}
+
+std::string compress(ZSTD_CStream& zcs, std::string const& data) {
+  std::string compressed;
+  compressed.resize(ZSTD_compressBound(data.size()));
+  ZSTD_inBuffer in = {data.data(), data.size(), 0};
+  ZSTD_outBuffer out = {&compressed[0], compressed.size(), 0};
+  while (in.pos != in.size) {
+    size_t const rc = ZSTD_compressStream(&zcs, &out, &in);
+    if (ZSTD_isError(rc)) {
+      throw std::runtime_error{"compress stream failed"};
+    }
+  }
+  size_t const rc = ZSTD_endStream(&zcs, &out);
+  if (rc != 0) {
+    throw std::runtime_error{"compress end failed"};
+  }
+  compressed.resize(out.pos);
+  return compressed;
+}
+
+std::string decompress(ZSTD_DStream &zds, std::string const &compressed,
+                       size_t decompressedSize) {
+  std::string decompressed;
+  decompressed.resize(decompressedSize);
+  ZSTD_inBuffer in = {compressed.data(), compressed.size(), 0};
+  ZSTD_outBuffer out = {&decompressed[0], decompressed.size(), 0};
+  while (in.pos != in.size) {
+    size_t const rc = ZSTD_decompressStream(&zds, &out, &in);
+    if (ZSTD_isError(rc)) {
+      throw std::runtime_error{"decompress stream failed"};
+    }
+  }
+  decompressed.resize(out.pos);
+  return decompressed;
+}
+
+std::string makeData(size_t size) {
+  std::string result;
+  result.reserve(size + 20);
+  while (result.size() < size) {
+    result += "Hello world";
+  }
+  return result;
+}
+
+std::string const kData = "Hello world";
+std::string const kPlainDict = makeData(10000);
+std::string const kZstdDict{
+    "\x37\xA4\x30\xEC\x99\x69\x58\x1C\x21\x10\xD8\x4A\x84\x01\xCC\xF3"
+    "\x3C\xCF\x9B\x25\xBB\xC9\x6E\xB2\x9B\xEC\x26\xAD\xCF\xDF\x4E\xCD"
+    "\xF3\x2C\x3A\x21\x84\x10\x42\x08\x21\x01\x33\xF1\x78\x3C\x1E\x8F"
+    "\xC7\xE3\xF1\x78\x3C\xCF\xF3\xBC\xF7\xD4\x42\x41\x41\x41\x41\x41"
+    "\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41"
+    "\x41\x41\x41\x41\xA1\x50\x28\x14\x0A\x85\x42\xA1\x50\x28\x14\x0A"
+    "\x85\xA2\x28\x8A\xA2\x28\x4A\x29\x7D\x74\xE1\xE1\xE1\xE1\xE1\xE1"
+    "\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xF1\x78\x3C"
+    "\x1E\x8F\xC7\xE3\xF1\x78\x9E\xE7\x79\xEF\x01\x01\x00\x00\x00\x04"
+    "\x00\x00\x00\x08\x00\x00\x00"
+    "0123456789",
+    161};
+}
+
+TEST(Block, CCtx) {
+  auto cctx = createCCtx(1);
+  auto const compressed = compress(*cctx, kData, 1);
+  auto dctx = createDCtx();
+  auto const decompressed = decompress(*dctx, compressed, kData.size());
+  EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Block, NoContentSize) {
+  auto cctx = createCCtx(1);
+  auto const c = compress(*cctx, kData, 1);
+  auto const size = ZSTD_findDecompressedSize(c.data(), c.size());
+  EXPECT_EQ(ZSTD_CONTENTSIZE_UNKNOWN, size);
+}
+
+TEST(Block, ContentSize) {
+  auto cctx = createCCtx(1);
+  auto params = ZSTD_getParams(1, 0, 0);
+  params.fParams.contentSizeFlag = 1;
+  auto const c = compress(*cctx, kData, params);
+  auto const size = ZSTD_findDecompressedSize(c.data(), c.size());
+  EXPECT_EQ(kData.size(), size);
+}
+
+TEST(Block, CCtxLevelIncrease) {
+  std::string c;
+  auto cctx = createCCtx(6);
+  auto dctx = createDCtx();
+  for (int level = 1; level <= 6; ++level) {
+    auto compressed = compress(*cctx, kData, level);
+    auto const decompressed = decompress(*dctx, compressed, kData.size());
+    EXPECT_EQ(kData, decompressed);
+  }
+}
+
+TEST(Block, PlainDict) {
+  auto cctx = createCCtx(1);
+  auto const compressed = compress(*cctx, kData, 1, kPlainDict);
+  auto dctx = createDCtx();
+  EXPECT_ANY_THROW(decompress(*dctx, compressed, kData.size()));
+  auto const decompressed =
+      decompress(*dctx, compressed, kData.size(), kPlainDict);
+  EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Block, ZstdDict) {
+  auto cctx = createCCtx(1);
+  auto const compressed = compress(*cctx, kData, 1, kZstdDict);
+  auto dctx = createDCtx();
+  EXPECT_ANY_THROW(decompress(*dctx, compressed, kData.size()));
+  auto const decompressed =
+      decompress(*dctx, compressed, kData.size(), kZstdDict);
+  EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Block, PreprocessedPlainDict) {
+  auto cctx = createCCtx(1);
+  auto const cdict = createCDict(kPlainDict, 1);
+  auto const compressed = compress(*cctx, kData, *cdict);
+  auto dctx = createDCtx();
+  auto const ddict = createDDict(kPlainDict);
+  EXPECT_ANY_THROW(decompress(*dctx, compressed, kData.size()));
+  auto const decompressed =
+      decompress(*dctx, compressed, kData.size(), *ddict);
+  EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Block, PreprocessedZstdDict) {
+  auto cctx = createCCtx(1);
+  auto const cdict = createCDict(kZstdDict, 1);
+  auto const compressed = compress(*cctx, kData, *cdict);
+  auto dctx = createDCtx();
+  auto const ddict = createDDict(kZstdDict);
+  EXPECT_ANY_THROW(decompress(*dctx, compressed, kData.size()));
+  auto const decompressed =
+      decompress(*dctx, compressed, kData.size(), *ddict);
+  EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Block, RecreateCCtx) {
+  auto cctx = createCCtx(1);
+  {
+    auto const compressed = compress(*cctx, kData, 1);
+    auto dctx = createDCtx();
+    auto const decompressed = decompress(*dctx, compressed, kData.size());
+    EXPECT_EQ(kData, decompressed);
+  }
+  // Create the cctx with the same memory
+  auto d = cctx.get_deleter();
+  auto raw = cctx.release();
+  auto params = ZSTD_getParams(1, 0, 0);
+  cctx.reset(
+      ZSTD_createCCtx(d.memory, ZSTD_CCtxWorkspaceBound(params.cParams)));
+  // Repeat
+  {
+    auto const compressed = compress(*cctx, kData, 1);
+    auto dctx = createDCtx();
+    auto const decompressed = decompress(*dctx, compressed, kData.size());
+    EXPECT_EQ(kData, decompressed);
+  }
+}
+
+TEST(Block, RecreateDCtx) {
+  auto dctx = createDCtx();
+  {
+    auto cctx = createCCtx(1);
+    auto const compressed = compress(*cctx, kData, 1);
+    auto const decompressed = decompress(*dctx, compressed, kData.size());
+    EXPECT_EQ(kData, decompressed);
+  }
+  // Create the cctx with the same memory
+  auto d = dctx.get_deleter();
+  auto raw = dctx.release();
+  dctx.reset(ZSTD_createDCtx(d.memory, ZSTD_DCtxWorkspaceBound()));
+  // Repeat
+  {
+    auto cctx = createCCtx(1);
+    auto const compressed = compress(*cctx, kData, 1);
+    auto dctx = createDCtx();
+    auto const decompressed = decompress(*dctx, compressed, kData.size());
+    EXPECT_EQ(kData, decompressed);
+  }
+}
+
+TEST(Stream, Basic) {
+  auto zcs = createCStream(1);
+  auto const compressed = compress(*zcs, kData);
+  auto zds = createDStream();
+  auto const decompressed = decompress(*zds, compressed, kData.size());
+  EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Stream, PlainDict) {
+  auto params = ZSTD_getParams(1, kData.size(), kPlainDict.size());
+  params.cParams.windowLog = 17;
+  auto cdict = createCDict(kPlainDict, params);
+  auto zcs = createCStream(params.cParams, *cdict, kData.size());
+  auto const compressed = compress(*zcs, kData);
+  auto const contentSize =
+      ZSTD_findDecompressedSize(compressed.data(), compressed.size());
+  EXPECT_ANY_THROW(decompress(*createDStream(), compressed, kData.size()));
+  auto ddict = createDDict(kPlainDict);
+  auto zds = createDStream(1 << 17, ddict.get());
+  auto const decompressed = decompress(*zds, compressed, kData.size());
+  EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Stream, ZstdDict) {
+  auto params = ZSTD_getParams(1, 0, 0);
+  params.cParams.windowLog = 17;
+  auto cdict = createCDict(kZstdDict, 1);
+  auto zcs = createCStream(params.cParams, *cdict);
+  auto const compressed = compress(*zcs, kData);
+  EXPECT_ANY_THROW(decompress(*createDStream(), compressed, kData.size()));
+  auto ddict = createDDict(kZstdDict);
+  auto zds = createDStream(1 << 17, ddict.get());
+  auto const decompressed = decompress(*zds, compressed, kData.size());
+  EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Stream, ResetCStream) {
+  auto zcs = createCStream(1);
+  auto zds = createDStream();
+  {
+    auto const compressed = compress(*zcs, kData);
+    auto const decompressed = decompress(*zds, compressed, kData.size());
+    EXPECT_EQ(kData, decompressed);
+  }
+  {
+    ZSTD_resetCStream(zcs.get(), 0);
+    auto const compressed = compress(*zcs, kData);
+    auto const decompressed = decompress(*zds, compressed, kData.size());
+    EXPECT_EQ(kData, decompressed);
+  }
+}
+
+TEST(Stream, ResetDStream) {
+  auto zcs = createCStream(1);
+  auto zds = createDStream();
+  auto const compressed = compress(*zcs, kData);
+  EXPECT_ANY_THROW(decompress(*zds, kData, kData.size()));
+  EXPECT_ANY_THROW(decompress(*zds, compressed, kData.size()));
+  ZSTD_resetDStream(zds.get());
+  auto const decompressed = decompress(*zds, compressed, kData.size());
+  EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Stream, Flush) {
+  auto zcs = createCStream(1);
+  auto zds = createDStream();
+  std::string compressed;
+  {
+    compressed.resize(ZSTD_compressBound(kData.size()));
+    ZSTD_inBuffer in = {kData.data(), kData.size(), 0};
+    ZSTD_outBuffer out = {&compressed[0], compressed.size(), 0};
+    while (in.pos != in.size) {
+      size_t const rc = ZSTD_compressStream(zcs.get(), &out, &in);
+      if (ZSTD_isError(rc)) {
+        throw std::runtime_error{"compress stream failed"};
+      }
+    }
+    EXPECT_EQ(0, out.pos);
+    size_t const rc = ZSTD_flushStream(zcs.get(), &out);
+    if (rc != 0) {
+      throw std::runtime_error{"compress end failed"};
+    }
+    compressed.resize(out.pos);
+    EXPECT_LT(0, out.pos);
+  }
+  std::string decompressed;
+  {
+    decompressed.resize(kData.size());
+    ZSTD_inBuffer in = {compressed.data(), compressed.size(), 0};
+    ZSTD_outBuffer out = {&decompressed[0], decompressed.size(), 0};
+    while (in.pos != in.size) {
+      size_t const rc = ZSTD_decompressStream(zds.get(), &out, &in);
+      if (ZSTD_isError(rc)) {
+        throw std::runtime_error{"decompress stream failed"};
+      }
+    }
+  }
+  EXPECT_EQ(kData, decompressed);
+}
diff --git a/contrib/linux-kernel/test/include/asm/unaligned.h b/contrib/linux-kernel/test/include/asm/unaligned.h
new file mode 100644
index 000000000..4f4828126
--- /dev/null
+++ b/contrib/linux-kernel/test/include/asm/unaligned.h
@@ -0,0 +1,177 @@
+#ifndef ASM_UNALIGNED_H
+#define ASM_UNALIGNED_H
+
+#include <assert.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#define _LITTLE_ENDIAN 1
+
+static unsigned _isLittleEndian(void)
+{
+    const union { uint32_t u; uint8_t c[4]; } one = { 1 };
+    assert(_LITTLE_ENDIAN == one.c[0]);
+    return _LITTLE_ENDIAN;
+}
+
+static uint16_t _swap16(uint16_t in)
+{
+    return ((in & 0xF) << 8) + ((in & 0xF0) >> 8);
+}
+
+static uint32_t _swap32(uint32_t in)
+{
+    return __builtin_bswap32(in);
+}
+
+static uint64_t _swap64(uint64_t in)
+{
+    return __builtin_bswap64(in);
+}
+
+/* Little endian */
+static uint16_t get_unaligned_le16(const void* memPtr)
+{
+    uint16_t val;
+    memcpy(&val, memPtr, sizeof(val));
+    if (!_isLittleEndian()) _swap16(val);
+    return val;
+}
+
+static uint32_t get_unaligned_le32(const void* memPtr)
+{
+    uint32_t val;
+    memcpy(&val, memPtr, sizeof(val));
+    if (!_isLittleEndian()) _swap32(val);
+    return val;
+}
+
+static uint64_t get_unaligned_le64(const void* memPtr)
+{
+    uint64_t val;
+    memcpy(&val, memPtr, sizeof(val));
+    if (!_isLittleEndian()) _swap64(val);
+    return val;
+}
+
+static void put_unaligned_le16(uint16_t value, void* memPtr)
+{
+    if (!_isLittleEndian()) value = _swap16(value);
+    memcpy(memPtr, &value, sizeof(value));
+}
+
+static void put_unaligned_le32(uint32_t value, void* memPtr)
+{
+    if (!_isLittleEndian()) value = _swap32(value);
+    memcpy(memPtr, &value, sizeof(value));
+}
+
+static void put_unaligned_le64(uint64_t value, void* memPtr)
+{
+    if (!_isLittleEndian()) value = _swap64(value);
+    memcpy(memPtr, &value, sizeof(value));
+}
+
+/* big endian */
+static uint32_t get_unaligned_be32(const void* memPtr)
+{
+    uint32_t val;
+    memcpy(&val, memPtr, sizeof(val));
+    if (_isLittleEndian()) _swap32(val);
+    return val;
+}
+
+static uint64_t get_unaligned_be64(const void* memPtr)
+{
+    uint64_t val;
+    memcpy(&val, memPtr, sizeof(val));
+    if (_isLittleEndian()) _swap64(val);
+    return val;
+}
+
+static void put_unaligned_be32(uint32_t value, void* memPtr)
+{
+    if (_isLittleEndian()) value = _swap32(value);
+    memcpy(memPtr, &value, sizeof(value));
+}
+
+static void put_unaligned_be64(uint64_t value, void* memPtr)
+{
+    if (_isLittleEndian()) value = _swap64(value);
+    memcpy(memPtr, &value, sizeof(value));
+}
+
+/* generic */
+extern void __bad_unaligned_access_size(void);
+
+#define __get_unaligned_le(ptr) ((typeof(*(ptr)))({                            \
+    __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr),                         \
+    __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_le16((ptr)),      \
+    __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_le32((ptr)),      \
+    __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_le64((ptr)),      \
+    __bad_unaligned_access_size()))));                                         \
+    }))
+
+#define __get_unaligned_be(ptr) ((typeof(*(ptr)))({                            \
+    __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr),                         \
+    __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_be16((ptr)),      \
+    __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_be32((ptr)),      \
+    __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_be64((ptr)),      \
+    __bad_unaligned_access_size()))));                                         \
+    }))
+
+#define __put_unaligned_le(val, ptr)                                           \
+  ({                                                                           \
+    void *__gu_p = (ptr);                                                      \
+    switch (sizeof(*(ptr))) {                                                  \
+    case 1:                                                                    \
+      *(uint8_t *)__gu_p = (uint8_t)(val);                                     \
+      break;                                                                   \
+    case 2:                                                                    \
+      put_unaligned_le16((uint16_t)(val), __gu_p);                             \
+      break;                                                                   \
+    case 4:                                                                    \
+      put_unaligned_le32((uint32_t)(val), __gu_p);                             \
+      break;                                                                   \
+    case 8:                                                                    \
+      put_unaligned_le64((uint64_t)(val), __gu_p);                             \
+      break;                                                                   \
+    default:                                                                   \
+      __bad_unaligned_access_size();                                           \
+      break;                                                                   \
+    }                                                                          \
+    (void)0;                                                                   \
+  })
+
+#define __put_unaligned_be(val, ptr)                                           \
+  ({                                                                           \
+    void *__gu_p = (ptr);                                                      \
+    switch (sizeof(*(ptr))) {                                                  \
+    case 1:                                                                    \
+      *(uint8_t *)__gu_p = (uint8_t)(val);                                     \
+      break;                                                                   \
+    case 2:                                                                    \
+      put_unaligned_be16((uint16_t)(val), __gu_p);                             \
+      break;                                                                   \
+    case 4:                                                                    \
+      put_unaligned_be32((uint32_t)(val), __gu_p);                             \
+      break;                                                                   \
+    case 8:                                                                    \
+      put_unaligned_be64((uint64_t)(val), __gu_p);                             \
+      break;                                                                   \
+    default:                                                                   \
+      __bad_unaligned_access_size();                                           \
+      break;                                                                   \
+    }                                                                          \
+    (void)0;                                                                   \
+  })
+
+#if _LITTLE_ENDIAN
+#  define get_unaligned __get_unaligned_le
+#  define put_unaligned __put_unaligned_le
+#else
+#  define get_unaligned __get_unaligned_be
+#  define put_unaligned __put_unaligned_be
+#endif
+
+#endif // ASM_UNALIGNED_H
diff --git a/contrib/linux-kernel/test/include/linux/compiler.h b/contrib/linux-kernel/test/include/linux/compiler.h
new file mode 100644
index 000000000..7991b8b29
--- /dev/null
+++ b/contrib/linux-kernel/test/include/linux/compiler.h
@@ -0,0 +1,12 @@
+#ifndef LINUX_COMIPLER_H_
+#define LINUX_COMIPLER_H_
+
+#ifndef __always_inline
+#  define __always_inline inline
+#endif
+
+#ifndef noinline
+#  define noinline __attribute__((__noinline__))
+#endif
+
+#endif // LINUX_COMIPLER_H_
diff --git a/contrib/linux-kernel/test/include/linux/kernel.h b/contrib/linux-kernel/test/include/linux/kernel.h
new file mode 100644
index 000000000..b208e23ba
--- /dev/null
+++ b/contrib/linux-kernel/test/include/linux/kernel.h
@@ -0,0 +1,14 @@
+#ifndef LINUX_KERNEL_H_
+#define LINUX_KERNEL_H_
+
+#define ALIGN(x, a) ({                                                         \
+    typeof(x) const __xe = (x);                                                \
+    typeof(a) const __ae = (a);                                                \
+    typeof(a) const __m = __ae - 1;                                            \
+    typeof(x) const __r = __xe & __m;                                          \
+    __xe + (__r ? (__ae - __r) : 0);                                           \
+  })
+
+#define PTR_ALIGN(p, a) (typeof(p))ALIGN((unsigned long long)(p), (a))
+
+#endif // LINUX_KERNEL_H_
diff --git a/contrib/linux-kernel/test/include/linux/string.h b/contrib/linux-kernel/test/include/linux/string.h
new file mode 100644
index 000000000..3b2f59002
--- /dev/null
+++ b/contrib/linux-kernel/test/include/linux/string.h
@@ -0,0 +1 @@
+#include <string.h>
diff --git a/contrib/linux-kernel/test/include/linux/types.h b/contrib/linux-kernel/test/include/linux/types.h
new file mode 100644
index 000000000..c2d4f4b72
--- /dev/null
+++ b/contrib/linux-kernel/test/include/linux/types.h
@@ -0,0 +1,2 @@
+#include <stddef.h>
+#include <stdint.h>
-- 
GitLab