From afaa25b9bd5d9e8c2e0a410eede6f30680c35d72 Mon Sep 17 00:00:00 2001 From: Richard Qin Date: Wed, 13 May 2026 15:42:22 +0800 Subject: feat: add LZ4 decompressor implementation and update linker script --- na/arch/riscv/kernel/lumeos.lds.S | 7 ++++ na/include/lume/decompress.h | 11 ++++++ na/lib/decompress_lz4.cc | 77 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 na/include/lume/decompress.h create mode 100644 na/lib/decompress_lz4.cc (limited to 'na') diff --git a/na/arch/riscv/kernel/lumeos.lds.S b/na/arch/riscv/kernel/lumeos.lds.S index f47fef2..ca5218f 100644 --- a/na/arch/riscv/kernel/lumeos.lds.S +++ b/na/arch/riscv/kernel/lumeos.lds.S @@ -69,10 +69,17 @@ SECTIONS { . = ALIGN(4096); + RELOC_SECTION + + . = ALIGN(4096); + DATA_SECTION . = ALIGN(4096); + /* End of file-backed image (BSS follows as NOBITS) */ + __lume_image_end = .; + BSS_SECTION KERNEL_END diff --git a/na/include/lume/decompress.h b/na/include/lume/decompress.h new file mode 100644 index 0000000..04082a9 --- /dev/null +++ b/na/include/lume/decompress.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (C) 2026 Richard Qin */ + +#pragma once + +#include + +/* + * LZ4 block decompressor (no frame headers). Returns bytes written or -1. + */ +int lz4_decompress(const uint8* src, uint32 src_len, uint8* dst, uint32 dst_cap); diff --git a/na/lib/decompress_lz4.cc b/na/lib/decompress_lz4.cc new file mode 100644 index 0000000..6a93936 --- /dev/null +++ b/na/lib/decompress_lz4.cc @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (C) 2026 Richard Qin */ + +#include + +int lz4_decompress(const uint8* src, uint32 src_len, uint8* dst, uint32 dst_cap) +{ + const uint8* ip = src; + const uint8* iend = src + src_len; + uint8* op = dst; + uint8* oend = dst + dst_cap; + + while (ip < iend) { + uint8 token = *ip++; + uint32 lit_len = token >> 4; + + if (lit_len == 15) { + uint8 s = 0; + do { + if (ip >= iend) { + return -1; + } + s = *ip++; + lit_len += s; + } while (s == 255); + } + + if (ip + lit_len > iend) { + return -1; + } + if (op + lit_len > oend) { + return -1; + } + + for (uint32 i = 0; i < lit_len; ++i) { + *op++ = *ip++; + } + + if (ip >= iend) { + break; + } + if (ip + 2 > iend) { + return -1; + } + + uint32 off = static_cast(ip[0]) | (static_cast(ip[1]) << 8); + ip += 2; + if (off == 0 || off > static_cast(op - dst)) { + return -1; + } + + uint32 match_len = token & 0x0F; + if (match_len == 15) { + uint8 s = 0; + do { + if (ip >= iend) { + return -1; + } + s = *ip++; + match_len += s; + } while (s == 255); + } + match_len += 4; + + if (op + match_len > oend) { + return -1; + } + + uint8* match = op - off; + for (uint32 i = 0; i < match_len; ++i) { + op[i] = match[i]; + } + op += match_len; + } + + return static_cast(op - dst); +} -- cgit v1.2.3