decompress_unlz4.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Wrapper for decompressing LZ4-compressed kernel, initramfs, and initrd
  4. *
  5. * Copyright (C) 2013, LG Electronics, Kyungsik Lee <kyungsik.lee@lge.com>
  6. */
  7. #ifdef STATIC
  8. #define PREBOOT
  9. #include "lz4/lz4_decompress.c"
  10. #else
  11. #include <linux/decompress/unlz4.h>
  12. #endif
  13. #include <linux/types.h>
  14. #include <linux/lz4.h>
  15. #include <linux/decompress/mm.h>
  16. #include <linux/compiler.h>
  17. #include <asm/unaligned.h>
  18. /*
  19. * Note: Uncompressed chunk size is used in the compressor side
  20. * (userspace side for compression).
  21. * It is hardcoded because there is not proper way to extract it
  22. * from the binary stream which is generated by the preliminary
  23. * version of LZ4 tool so far.
  24. */
  25. #define LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE (8 << 20)
  26. #define ARCHIVE_MAGICNUMBER 0x184C2102
  27. STATIC inline int INIT unlz4(u8 *input, long in_len,
  28. long (*fill)(void *, unsigned long),
  29. long (*flush)(void *, unsigned long),
  30. u8 *output, long *posp,
  31. void (*error) (char *x))
  32. {
  33. int ret = -1;
  34. size_t chunksize = 0;
  35. size_t uncomp_chunksize = LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE;
  36. u8 *inp;
  37. u8 *inp_start;
  38. u8 *outp;
  39. long size = in_len;
  40. #ifdef PREBOOT
  41. size_t out_len = get_unaligned_le32(input + in_len);
  42. #endif
  43. size_t dest_len;
  44. if (output) {
  45. outp = output;
  46. } else if (!flush) {
  47. error("NULL output pointer and no flush function provided");
  48. goto exit_0;
  49. } else {
  50. outp = large_malloc(uncomp_chunksize);
  51. if (!outp) {
  52. error("Could not allocate output buffer");
  53. goto exit_0;
  54. }
  55. }
  56. if (input && fill) {
  57. error("Both input pointer and fill function provided,");
  58. goto exit_1;
  59. } else if (input) {
  60. inp = input;
  61. } else if (!fill) {
  62. error("NULL input pointer and missing fill function");
  63. goto exit_1;
  64. } else {
  65. inp = large_malloc(LZ4_compressBound(uncomp_chunksize));
  66. if (!inp) {
  67. error("Could not allocate input buffer");
  68. goto exit_1;
  69. }
  70. }
  71. inp_start = inp;
  72. if (posp)
  73. *posp = 0;
  74. if (fill) {
  75. size = fill(inp, 4);
  76. if (size < 4) {
  77. error("data corrupted");
  78. goto exit_2;
  79. }
  80. }
  81. chunksize = get_unaligned_le32(inp);
  82. if (chunksize == ARCHIVE_MAGICNUMBER) {
  83. if (!fill) {
  84. inp += 4;
  85. size -= 4;
  86. }
  87. } else {
  88. error("invalid header");
  89. goto exit_2;
  90. }
  91. if (posp)
  92. *posp += 4;
  93. for (;;) {
  94. if (fill) {
  95. size = fill(inp, 4);
  96. if (size == 0)
  97. break;
  98. if (size < 4) {
  99. error("data corrupted");
  100. goto exit_2;
  101. }
  102. } else if (size < 4) {
  103. /* empty or end-of-file */
  104. goto exit_3;
  105. }
  106. chunksize = get_unaligned_le32(inp);
  107. if (chunksize == ARCHIVE_MAGICNUMBER) {
  108. if (!fill) {
  109. inp += 4;
  110. size -= 4;
  111. }
  112. if (posp)
  113. *posp += 4;
  114. continue;
  115. }
  116. if (!fill && chunksize == 0) {
  117. /* empty or end-of-file */
  118. goto exit_3;
  119. }
  120. if (posp)
  121. *posp += 4;
  122. if (!fill) {
  123. inp += 4;
  124. size -= 4;
  125. } else {
  126. if (chunksize > LZ4_compressBound(uncomp_chunksize)) {
  127. error("chunk length is longer than allocated");
  128. goto exit_2;
  129. }
  130. size = fill(inp, chunksize);
  131. if (size < chunksize) {
  132. error("data corrupted");
  133. goto exit_2;
  134. }
  135. }
  136. #ifdef PREBOOT
  137. if (out_len >= uncomp_chunksize) {
  138. dest_len = uncomp_chunksize;
  139. out_len -= dest_len;
  140. } else
  141. dest_len = out_len;
  142. ret = LZ4_decompress_fast(inp, outp, dest_len);
  143. chunksize = ret;
  144. #else
  145. dest_len = uncomp_chunksize;
  146. ret = LZ4_decompress_safe(inp, outp, chunksize, dest_len);
  147. dest_len = ret;
  148. #endif
  149. if (ret < 0) {
  150. error("Decoding failed");
  151. goto exit_2;
  152. }
  153. ret = -1;
  154. if (flush && flush(outp, dest_len) != dest_len)
  155. goto exit_2;
  156. if (output)
  157. outp += dest_len;
  158. if (posp)
  159. *posp += chunksize;
  160. if (!fill) {
  161. size -= chunksize;
  162. if (size == 0)
  163. break;
  164. else if (size < 0) {
  165. error("data corrupted");
  166. goto exit_2;
  167. }
  168. inp += chunksize;
  169. }
  170. }
  171. exit_3:
  172. ret = 0;
  173. exit_2:
  174. if (!input)
  175. large_free(inp_start);
  176. exit_1:
  177. if (!output)
  178. large_free(outp);
  179. exit_0:
  180. return ret;
  181. }
  182. #ifdef PREBOOT
  183. STATIC int INIT __decompress(unsigned char *buf, long in_len,
  184. long (*fill)(void*, unsigned long),
  185. long (*flush)(void*, unsigned long),
  186. unsigned char *output, long out_len,
  187. long *posp,
  188. void (*error)(char *x)
  189. )
  190. {
  191. return unlz4(buf, in_len - 4, fill, flush, output, posp, error);
  192. }
  193. #endif