Skip to content

Commit 79ffdef

Browse files
committed
fix lz4 HC unpack repack
1 parent 2cbf613 commit 79ffdef

2 files changed

Lines changed: 167 additions & 47 deletions

File tree

tools/bootimg.c

Lines changed: 162 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "common.h"
1010
#include "lib/lz4/lz4.h"
1111
#include "lib/lz4/lz4frame.h"
12+
#include "lib/lz4/lz4hc.h"
1213
#include "lib/bz2/bzlib.h"
1314
#include "lib/xz/xz.h"
1415
#include "lib/sha/sha256.h"
@@ -185,37 +186,76 @@ int compress_lz4(const uint8_t *in_data, size_t in_size, uint8_t **out_data, uin
185186
*out_size = (uint32_t)compressed_size;
186187
return 0;
187188
}
188-
int compress_lz4_le(const uint8_t *in_data, size_t in_size, uint8_t **out_data, uint32_t *out_size, compress_head data) {
189-
int max_block_size = LZ4_compressBound((int)in_size);
190-
191-
uint32_t total_max_size = 8 + max_block_size;
192-
*out_data = (uint8_t *)malloc(total_max_size);
193-
if (!*out_data) {
194-
return -1;
189+
int compress_lz4_le(
190+
const uint8_t *in_data,
191+
size_t in_size,
192+
uint8_t **out_data,
193+
uint32_t *out_size,
194+
compress_head k_head
195+
) {
196+
197+
size_t max_blocks =
198+
(in_size + LZ4_BLOCK_SIZE - 1) / LZ4_BLOCK_SIZE;
199+
// uint32_t max_blocks_1 =
200+
// ((uint32_t)k_head.magic[4])
201+
// | ((uint32_t)k_head.magic[5] << 8)
202+
// | ((uint32_t)k_head.magic[6] << 16)
203+
// | ((uint32_t)k_head.magic[7] << 24);
204+
tools_logi("Calculated max blocks: %zu\n", max_blocks);
205+
size_t max_out =
206+
sizeof(uint32_t) + // MAGIC
207+
max_blocks * (sizeof(uint32_t) + // block header
208+
LZ4_compressBound(LZ4_BLOCK_SIZE));
209+
210+
uint8_t *out = malloc(max_out);
211+
if (!out) {
212+
tools_loge("Failed to allocate memory for LZ4 compression,size: %zu\n",max_out);
213+
return -2;
195214
}
196215

197-
(*out_data)[0] = data.magic[0];
198-
(*out_data)[1] = data.magic[1];
199-
(*out_data)[2] = data.magic[2];
200-
(*out_data)[3] = data.magic[3];
201-
(*out_data)[4] = data.magic[4];
202-
(*out_data)[5] = data.magic[5];
203-
(*out_data)[6] = data.magic[6];
204-
(*out_data)[7] = data.magic[7];
205-
206-
int compressed_bytes = LZ4_compress_default(
207-
(const char*)in_data,
208-
(char*)(*out_data + 8),
209-
(int)in_size,
210-
max_block_size
211-
);
212-
if (compressed_bytes <= 0) {
213-
free(*out_data);
214-
*out_data = NULL;
215-
return -2;
216+
size_t out_off = 0;
217+
218+
/* write MAGIC */
219+
uint32_t magic = LZ4_MAGIC;
220+
memcpy(out + out_off, &magic, sizeof(magic));
221+
out_off += sizeof(magic);
222+
223+
size_t in_off = 0;
224+
225+
while (in_off < in_size) {
226+
size_t chunk_size = in_size - in_off;
227+
if (chunk_size > LZ4_BLOCK_SIZE)
228+
chunk_size = LZ4_BLOCK_SIZE;
229+
230+
int max_dst = LZ4_compressBound((int)chunk_size);
231+
232+
int compressed = LZ4_compress_HC(
233+
(const char *)(in_data + in_off),
234+
(char *)(out + out_off + sizeof(uint32_t)),
235+
(int)chunk_size,
236+
max_dst,
237+
LZ4HC_CLEVEL
238+
);
239+
240+
if (compressed <= 0) {
241+
tools_loge("LZ4 compression failed for block at offset %zu\n", in_off);
242+
free(out);
243+
return -3;
244+
}
245+
246+
/* write compressed block size */
247+
uint32_t csz = (uint32_t)compressed;
248+
memcpy(out + out_off, &csz, sizeof(csz));
249+
out_off += sizeof(uint32_t);
250+
251+
/* advance over compressed data */
252+
out_off += compressed;
253+
in_off += chunk_size;
216254
}
217-
*out_size = 8 + (uint32_t)compressed_bytes;
218-
return 0;
255+
256+
*out_data = out;
257+
*out_size = (uint32_t)out_off;
258+
return 0;
219259
}
220260

221261
// int compress_zstd(const uint8_t *in_data, size_t in_size, uint8_t **out_data, uint32_t *out_size) {
@@ -326,7 +366,7 @@ int auto_depress(const uint8_t *data, size_t size, const char *out_path) {
326366
compress_head k_head;
327367
memcpy(&k_head, data, sizeof(k_head));
328368
int method = detect_compress_method(k_head);
329-
369+
tools_logi("Auto-detect compression method: %d\n", method);
330370

331371
if (method == 1) { //Gzip
332372
tools_logi("Detected GZIP compressed kernel.\n");
@@ -367,29 +407,104 @@ int auto_depress(const uint8_t *data, size_t size, const char *out_path) {
367407
return 0;
368408
}
369409
}
410+
411+
if (method == 3) {
412+
tools_logi("Probing LZ4 Legacy (block-based)...\n");
370413

371-
if (method == 3) {
372-
tools_logi("Detected LZ4 Legacy. Decompressing with LZ4 Block API...\n");
414+
const uint8_t *p = (const uint8_t *)data;
415+
const uint8_t *end = p + size;
373416

374-
const char* compressed_ptr = (const char*)data + 8;
375-
int compressed_size = (int)size - 8;
376417

377-
size_t dstCapacity = 64 * 1024 * 1024;
378-
void* dst = malloc(dstCapacity);
379-
if (!dst) return -1;
418+
if (size < 4)
419+
goto not_lz4;
380420

381-
int ret = LZ4_decompress_safe(compressed_ptr, (char*)dst, compressed_size, (int)dstCapacity);
382421

383-
if (ret < 0) {
384-
tools_loge("LZ4 Legacy decompression failed.\n");
385-
free(dst);
386-
return -1;
387-
} else {
388-
tools_logi("Decompressed: %d bytes\n", ret);
389-
write_data_to_file(out_path, (uint8_t*)dst, (uint32_t)ret);
390-
free(dst);
391-
return 0;
422+
if (*(uint32_t *)p != LZ4_MAGIC)
423+
goto not_lz4;
424+
425+
p += 4;
426+
427+
size_t out_cap = 64 * 1024 * 1024;
428+
uint8_t *out = malloc(out_cap);
429+
if (!out)
430+
goto not_lz4;
431+
432+
size_t out_off = 0;
433+
434+
uint8_t *block_out = malloc(LZ4_BLOCK_SIZE);
435+
if (!block_out) {
436+
free(out);
437+
goto not_lz4;
438+
}
439+
440+
int decoded_any = 0;
441+
while (1) {
442+
uint32_t block_size;
443+
444+
if (p + 4 > end)
445+
break;
446+
447+
memcpy(&block_size, p, 4);
448+
p += 4;
449+
450+
if (block_size == 0)
451+
break;
452+
453+
if (block_size > LZ4_compressBound(LZ4_BLOCK_SIZE))
454+
goto fail;
455+
456+
if (p + block_size > end)
457+
goto fail;
458+
459+
int decoded = LZ4_decompress_safe(
460+
(const char *)p,
461+
(char *)block_out,
462+
(int)block_size,
463+
LZ4_BLOCK_SIZE
464+
);
465+
466+
if (decoded < 0)
467+
goto fail;
468+
469+
decoded_any = 1;
470+
471+
if (out_off + (size_t)decoded > out_cap) {
472+
size_t new_cap = out_cap * 2;
473+
while (new_cap < out_off + (size_t)decoded)
474+
new_cap *= 2;
475+
476+
uint8_t *tmp = realloc(out, new_cap);
477+
if (!tmp)
478+
goto fail;
479+
480+
out = tmp;
481+
out_cap = new_cap;
482+
}
483+
484+
memcpy(out + out_off, block_out, (size_t)decoded);
485+
out_off += (size_t)decoded;
486+
487+
p += block_size;
392488
}
489+
490+
491+
if (!decoded_any)
492+
goto fail;
493+
494+
tools_logi("LZ4 block decompressed: %zu bytes\n", out_off);
495+
write_data_to_file(out_path, out, (uint32_t)out_off);
496+
497+
free(block_out);
498+
free(out);
499+
return 0;
500+
501+
fail:
502+
free(block_out);
503+
free(out);
504+
505+
not_lz4:
506+
507+
tools_logi("Not LZ4 block format, fallback.\n");
393508
}
394509

395510
// till now no kernel use this
@@ -691,7 +806,7 @@ int repack_bootimg(const char *orig_boot_path,
691806
return -1;
692807
}
693808
}
694-
809+
tools_logi("Final kernel size after compression (if applied): %u bytes\n", final_k_size);
695810
uint32_t old_k_aligned = ALIGN(hdr.kernel_size, page_size);
696811
uint32_t rest_data_offset = page_size + old_k_aligned;
697812
uint32_t rest_data_size = (total_size > rest_data_offset) ? (total_size - rest_data_offset) : 0;

tools/bootimg.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11

22
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
33
#define PAGE_SIZE_DEFAULT 4096
4+
5+
#define LZ4_MAGIC 0x184c2102
6+
#define LZ4_BLOCK_SIZE 0x800000
7+
#define LZ4HC_CLEVEL 12
8+
49
struct boot_img_hdr {
510
uint8_t magic[8]; // "ANDROID!"
611
uint32_t kernel_size;

0 commit comments

Comments
 (0)