coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
lz4_wrapper.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-only */
2 
6 #include <stdint.h>
7 #include <string.h>
8 
9 /* LZ4 comes with its own supposedly portable memory access functions, but they
10  * seem to be very inefficient in practice (at least on ARM64). Since coreboot
11  * knows about endinaness and allows some basic assumptions (such as unaligned
12  * access support), we can easily write the ones we need ourselves. */
13 static uint16_t LZ4_readLE16(const void *src)
14 {
15  return le16toh(*(const uint16_t *)src);
16 }
17 static void LZ4_copy8(void *dst, const void *src)
18 {
19 /* ARM32 needs to be a special snowflake to prevent GCC from coalescing the
20  * access into LDRD/STRD (which don't support unaligned accesses). */
21 #ifdef __arm__ /* ARMv < 6 doesn't support unaligned accesses at all. */
22  #if defined(__COREBOOT_ARM_ARCH__) && __COREBOOT_ARM_ARCH__ < 6
23  int i;
24  for (i = 0; i < 8; i++)
25  ((uint8_t *)dst)[i] = ((uint8_t *)src)[i];
26  #else
27  uint32_t x0, x1;
28  __asm__ ("ldr %[x0], [%[src]]"
29  : [x0]"=r"(x0)
30  : [src]"r"(src), "m"(*(const uint32_t *)src));
31  __asm__ ("ldr %[x1], [%[src], #4]"
32  : [x1]"=r"(x1)
33  : [src]"r"(src), "m"(*(const uint32_t *)(src + 4)));
34  __asm__ ("str %[x0], [%[dst]]"
35  : "=m"(*(uint32_t *)dst)
36  : [x0]"r"(x0), [dst]"r"(dst));
37  __asm__ ("str %[x1], [%[dst], #4]"
38  : "=m"(*(uint32_t *)(dst + 4))
39  : [x1]"r"(x1), [dst]"r"(dst));
40  #endif
41 #elif defined(__riscv)
42  /* RISC-V implementations may trap on any unaligned access. */
43  int i;
44  for (i = 0; i < 8; i++)
45  ((uint8_t *)dst)[i] = ((uint8_t *)src)[i];
46 #else
47  *(uint64_t *)dst = *(const uint64_t *)src;
48 #endif
49 }
50 
51 typedef uint8_t BYTE;
52 typedef uint16_t U16;
53 typedef uint32_t U32;
54 typedef int32_t S32;
55 typedef uint64_t U64;
56 
57 #define FORCE_INLINE static __always_inline
58 #define likely(expr) __builtin_expect((expr) != 0, 1)
59 #define unlikely(expr) __builtin_expect((expr) != 0, 0)
60 
61 /* Unaltered (just removed unrelated code) from github.com/Cyan4973/lz4/dev. */
62 #include "lz4.c.inc" /* #include for inlining, do not link! */
63 
64 #define LZ4F_MAGICNUMBER 0x184D2204
65 
66 /* Bit field endianness is implementation-defined. Use masks instead.
67  * https://stackoverflow.com/a/6044223 */
68 #define RESERVED0 0x03
69 #define HAS_CONTENT_CHECKSUM 0x04
70 #define HAS_CONTENT_SIZE 0x08
71 #define HAS_BLOCK_CHECKSUM 0x10
72 #define INDEPENDENT_BLOCKS 0x20
73 #define VERSION 0xC0
74 #define VERSION_SHIFT 6
75 
76 #define RESERVED1_2 0x8F
77 #define MAX_BLOCK_SIZE 0x70
78 
83  /* + uint64_t content_size iff has_content_size is set */
84  /* + uint8_t header_checksum */
86 
87 #define BH_SIZE 0x7FFFFFFF
88 #define NOT_COMPRESSED 0x80000000
89 
92  /* + size bytes of data */
93  /* + uint32_t block_checksum iff has_block_checksum is set */
94 } __packed;
95 
96 size_t ulz4fn(const void *src, size_t srcn, void *dst, size_t dstn)
97 {
98  const void *in = src;
99  void *out = dst;
100  size_t out_size = 0;
101  int has_block_checksum;
102 
103  { /* With in-place decompression the header may become invalid later. */
104  const struct lz4_frame_header *h = in;
105 
106  if (srcn < sizeof(*h) + sizeof(uint64_t) + sizeof(uint8_t))
107  return 0; /* input overrun */
108 
109  /* We assume there's always only a single, standard frame. */
110  if (le32toh(h->magic) != LZ4F_MAGICNUMBER
111  || (h->flags & VERSION) != (1 << VERSION_SHIFT))
112  return 0; /* unknown format */
113  if ((h->flags & RESERVED0) || (h->block_descriptor & RESERVED1_2))
114  return 0; /* reserved must be zero */
115  if (!(h->flags & INDEPENDENT_BLOCKS))
116  return 0; /* we don't support block dependency */
117  has_block_checksum = h->flags & HAS_BLOCK_CHECKSUM;
118 
119  in += sizeof(*h);
120  if (h->flags & HAS_CONTENT_SIZE)
121  in += sizeof(uint64_t);
122  in += sizeof(uint8_t);
123  }
124 
125  while (1) {
126  if ((size_t)(in - src) + sizeof(struct lz4_block_header) > srcn)
127  break; /* input overrun */
128 
129  struct lz4_block_header b = {
130  .raw = le32toh(*(const uint32_t *)in)
131  };
132  in += sizeof(struct lz4_block_header);
133 
134  if ((size_t)(in - src) + (b.raw & BH_SIZE) > srcn)
135  break; /* input overrun */
136 
137  if (!(b.raw & BH_SIZE)) {
138  out_size = out - dst;
139  break; /* decompression successful */
140  }
141 
142  if (b.raw & NOT_COMPRESSED) {
143  size_t size = MIN((uintptr_t)(b.raw & BH_SIZE), (uintptr_t)dst
144  + dstn - (uintptr_t)out);
145  memcpy(out, in, size);
146  if (size < (b.raw & BH_SIZE))
147  break; /* output overrun */
148  out += size;
149  } else {
150  /* constant folding essential, do not touch params! */
151  int ret = LZ4_decompress_generic(in, out, (b.raw & BH_SIZE),
152  dst + dstn - out, endOnInputSize,
153  full, 0, noDict, out, NULL, 0);
154  if (ret < 0)
155  break; /* decompression error */
156  out += ret;
157  }
158 
159  in += (b.raw & BH_SIZE);
160  if (has_block_checksum)
161  in += sizeof(uint32_t);
162  }
163 
164  return out_size;
165 }
166 
167 size_t ulz4f(const void *src, void *dst)
168 {
169  /* LZ4 uses signed size parameters, so can't just use ((u32)-1) here. */
170  return ulz4fn(src, 1*GiB, dst, 1*GiB);
171 }
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
#define MIN(a, b)
Definition: helpers.h:37
#define GiB
Definition: helpers.h:77
static uint16_t le16toh(uint16_t little_endian_16bits)
Definition: endian.h:115
static uint32_t le32toh(uint32_t little_endian_32bits)
Definition: endian.h:135
struct lz4_frame_header __packed
uint16_t U16
Definition: lz4_wrapper.c:52
#define VERSION
Definition: lz4_wrapper.c:73
static uint16_t LZ4_readLE16(const void *src)
Definition: lz4_wrapper.c:13
uint64_t U64
Definition: lz4_wrapper.c:55
#define RESERVED1_2
Definition: lz4_wrapper.c:76
#define VERSION_SHIFT
Definition: lz4_wrapper.c:74
#define RESERVED0
Definition: lz4_wrapper.c:68
int32_t S32
Definition: lz4_wrapper.c:54
#define HAS_BLOCK_CHECKSUM
Definition: lz4_wrapper.c:71
size_t ulz4f(const void *src, void *dst)
Definition: lz4_wrapper.c:167
#define BH_SIZE
Definition: lz4_wrapper.c:87
#define HAS_CONTENT_SIZE
Definition: lz4_wrapper.c:70
uint32_t U32
Definition: lz4_wrapper.c:53
size_t ulz4fn(const void *src, size_t srcn, void *dst, size_t dstn)
Definition: lz4_wrapper.c:96
static void LZ4_copy8(void *dst, const void *src)
Definition: lz4_wrapper.c:17
#define NOT_COMPRESSED
Definition: lz4_wrapper.c:88
#define LZ4F_MAGICNUMBER
Definition: lz4_wrapper.c:64
uint8_t BYTE
Definition: lz4_wrapper.c:51
#define INDEPENDENT_BLOCKS
Definition: lz4_wrapper.c:72
#define NULL
Definition: stddef.h:19
unsigned short uint16_t
Definition: stdint.h:11
unsigned int uint32_t
Definition: stdint.h:14
unsigned long uintptr_t
Definition: stdint.h:21
unsigned long long uint64_t
Definition: stdint.h:17
signed int int32_t
Definition: stdint.h:13
unsigned char uint8_t
Definition: stdint.h:8
Definition: jpeg.c:27
uint32_t magic
Definition: lz4_wrapper.c:80
uint8_t block_descriptor
Definition: lz4_wrapper.c:82