commonlib: Add commonlib/bsd
This patch creates a new commonlib/bsd subdirectory with a similar purpose to the existing commonlib, with the difference that all files under this subdirectory shall be licensed under the BSD-3-Clause license (or compatible permissive license). The goal is to allow more code to be shared with libpayload in the future. Initially, I'm going to move a few files there that have already been BSD-licensed in the existing commonlib. I am also exracting most contents of the often-needed <commonlib/helpers.h> as long as they have either been written by me (and are hereby relicensed) or have an existing equivalent in BSD-licensed libpayload code. I am also relicensing <commonlib/compression.h> (written by me) and <commonlib/compiler.h> (same stuff exists in libpayload). Finally, I am extracting the cb_err error code definitions from <types.h> into a new BSD-licensed header so that future commonlib/bsd code can build upon a common set of error values. I am making the assumption here that the enum constants and the half-sentence fragments of documentation next to them by themselves do not meet the threshold of copyrightability. Change-Id: I316cea70930f131e8e93d4218542ddb5ae4b63a2 Signed-off-by: Julius Werner <jwerner@chromium.org> Reviewed-on: https://review.coreboot.org/c/coreboot/+/38420 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Patrick Rudolph <siro@das-labor.org>
This commit is contained in:
42
src/commonlib/bsd/include/commonlib/bsd/cb_err.h
Normal file
42
src/commonlib/bsd/include/commonlib/bsd/cb_err.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later */
|
||||
|
||||
#ifndef _COMMONLIB_BSD_CB_ERR_H_
|
||||
#define _COMMONLIB_BSD_CB_ERR_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* coreboot error codes
|
||||
*
|
||||
* Common error definitions that can be used for any function. All error values
|
||||
* should be negative -- when useful, positive values can also be used to denote
|
||||
* success. Allocate a new group or errors every 100 values.
|
||||
*/
|
||||
enum cb_err {
|
||||
CB_SUCCESS = 0, /**< Call completed successfully */
|
||||
CB_ERR = -1, /**< Generic error code */
|
||||
CB_ERR_ARG = -2, /**< Invalid argument */
|
||||
|
||||
/* NVRAM/CMOS errors */
|
||||
CB_CMOS_OTABLE_DISABLED = -100, /**< Option table disabled */
|
||||
CB_CMOS_LAYOUT_NOT_FOUND = -101, /**< Layout file not found */
|
||||
CB_CMOS_OPTION_NOT_FOUND = -102, /**< Option string not found */
|
||||
CB_CMOS_ACCESS_ERROR = -103, /**< CMOS access error */
|
||||
CB_CMOS_CHECKSUM_INVALID = -104, /**< CMOS checksum is invalid */
|
||||
|
||||
/* Keyboard test failures */
|
||||
CB_KBD_CONTROLLER_FAILURE = -200,
|
||||
CB_KBD_INTERFACE_FAILURE = -201,
|
||||
|
||||
/* I2C controller failures */
|
||||
CB_I2C_NO_DEVICE = -300, /**< Device is not responding */
|
||||
CB_I2C_BUSY = -301, /**< Device tells it's busy */
|
||||
CB_I2C_PROTOCOL_ERROR = -302, /**< Data lost or spurious slave
|
||||
device response, try again? */
|
||||
CB_I2C_TIMEOUT = -303, /**< Transmission timed out */
|
||||
};
|
||||
|
||||
/* Don't typedef the enum directly, so the size is unambiguous for serialization. */
|
||||
typedef int32_t cb_err_t;
|
||||
|
||||
#endif /* _COMMONLIB_BSD_CB_ERR_H_ */
|
190
src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h
Normal file
190
src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h
Normal file
@ -0,0 +1,190 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-only */
|
||||
|
||||
#ifndef _CBFS_SERIALIZED_H_
|
||||
#define _CBFS_SERIALIZED_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** These are standard values for the known compression
|
||||
algorithms that coreboot knows about for stages and
|
||||
payloads. Of course, other CBFS users can use whatever
|
||||
values they want, as long as they understand them. */
|
||||
|
||||
#define CBFS_COMPRESS_NONE 0
|
||||
#define CBFS_COMPRESS_LZMA 1
|
||||
#define CBFS_COMPRESS_LZ4 2
|
||||
|
||||
/** These are standard component types for well known
|
||||
components (i.e - those that coreboot needs to consume.
|
||||
Users are welcome to use any other value for their
|
||||
components */
|
||||
|
||||
#define CBFS_TYPE_DELETED 0x00000000
|
||||
#define CBFS_TYPE_DELETED2 0xffffffff
|
||||
#define CBFS_TYPE_STAGE 0x10
|
||||
#define CBFS_TYPE_SELF 0x20
|
||||
#define CBFS_TYPE_FIT 0x21
|
||||
#define CBFS_TYPE_OPTIONROM 0x30
|
||||
#define CBFS_TYPE_BOOTSPLASH 0x40
|
||||
#define CBFS_TYPE_RAW 0x50
|
||||
#define CBFS_TYPE_VSA 0x51
|
||||
#define CBFS_TYPE_MBI 0x52
|
||||
#define CBFS_TYPE_MICROCODE 0x53
|
||||
#define CBFS_TYPE_FSP 0x60
|
||||
#define CBFS_TYPE_MRC 0x61
|
||||
#define CBFS_TYPE_MMA 0x62
|
||||
#define CBFS_TYPE_EFI 0x63
|
||||
#define CBFS_TYPE_STRUCT 0x70
|
||||
#define CBFS_COMPONENT_CMOS_DEFAULT 0xaa
|
||||
#define CBFS_TYPE_SPD 0xab
|
||||
#define CBFS_TYPE_MRC_CACHE 0xac
|
||||
#define CBFS_COMPONENT_CMOS_LAYOUT 0x01aa
|
||||
|
||||
#define CBFS_HEADER_MAGIC 0x4F524243
|
||||
#define CBFS_HEADER_VERSION1 0x31313131
|
||||
#define CBFS_HEADER_VERSION2 0x31313132
|
||||
#define CBFS_HEADER_VERSION CBFS_HEADER_VERSION2
|
||||
|
||||
/* this is the master cbfs header - it must be located somewhere available
|
||||
* to bootblock (to load romstage). The last 4 bytes in the image contain its
|
||||
* relative offset from the end of the image (as a 32-bit signed integer). */
|
||||
|
||||
struct cbfs_header {
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
uint32_t romsize;
|
||||
uint32_t bootblocksize;
|
||||
uint32_t align; /* fixed to 64 bytes */
|
||||
uint32_t offset;
|
||||
uint32_t architecture;
|
||||
uint32_t pad[1];
|
||||
} __packed;
|
||||
|
||||
/* this used to be flexible, but wasn't ever set to something different. */
|
||||
#define CBFS_ALIGNMENT 64
|
||||
|
||||
/* "Unknown" refers to CBFS headers version 1,
|
||||
* before the architecture was defined (i.e., x86 only).
|
||||
*/
|
||||
#define CBFS_ARCHITECTURE_UNKNOWN 0xFFFFFFFF
|
||||
#define CBFS_ARCHITECTURE_X86 0x00000001
|
||||
#define CBFS_ARCHITECTURE_ARM 0x00000010
|
||||
|
||||
/** This is a component header - every entry in the CBFS
|
||||
will have this header.
|
||||
|
||||
This is how the component is arranged in the ROM:
|
||||
|
||||
-------------- <- 0
|
||||
component header
|
||||
-------------- <- sizeof(struct component)
|
||||
component name
|
||||
-------------- <- offset
|
||||
data
|
||||
...
|
||||
-------------- <- offset + len
|
||||
*/
|
||||
|
||||
#define CBFS_FILE_MAGIC "LARCHIVE"
|
||||
|
||||
struct cbfs_file {
|
||||
char magic[8];
|
||||
uint32_t len;
|
||||
uint32_t type;
|
||||
uint32_t attributes_offset;
|
||||
uint32_t offset;
|
||||
} __packed;
|
||||
|
||||
/* The common fields of extended cbfs file attributes.
|
||||
Attributes are expected to start with tag/len, then append their
|
||||
specific fields. */
|
||||
struct cbfs_file_attribute {
|
||||
uint32_t tag;
|
||||
/* len covers the whole structure, incl. tag and len */
|
||||
uint32_t len;
|
||||
uint8_t data[0];
|
||||
} __packed;
|
||||
|
||||
/* Depending on how the header was initialized, it may be backed with 0x00 or
|
||||
* 0xff. Support both. */
|
||||
#define CBFS_FILE_ATTR_TAG_UNUSED 0
|
||||
#define CBFS_FILE_ATTR_TAG_UNUSED2 0xffffffff
|
||||
#define CBFS_FILE_ATTR_TAG_COMPRESSION 0x42435a4c
|
||||
#define CBFS_FILE_ATTR_TAG_HASH 0x68736148
|
||||
#define CBFS_FILE_ATTR_TAG_POSITION 0x42435350 /* PSCB */
|
||||
#define CBFS_FILE_ATTR_TAG_ALIGNMENT 0x42434c41 /* ALCB */
|
||||
#define CBFS_FILE_ATTR_TAG_IBB 0x32494242 /* Initial BootBlock */
|
||||
|
||||
struct cbfs_file_attr_compression {
|
||||
uint32_t tag;
|
||||
uint32_t len;
|
||||
/* whole file compression format. 0 if no compression. */
|
||||
uint32_t compression;
|
||||
uint32_t decompressed_size;
|
||||
} __packed;
|
||||
|
||||
struct cbfs_file_attr_hash {
|
||||
uint32_t tag;
|
||||
uint32_t len;
|
||||
uint32_t hash_type;
|
||||
/* hash_data is len - sizeof(struct) bytes */
|
||||
uint8_t hash_data[];
|
||||
} __packed;
|
||||
|
||||
struct cbfs_file_attr_position {
|
||||
uint32_t tag;
|
||||
uint32_t len;
|
||||
uint32_t position;
|
||||
} __packed;
|
||||
|
||||
struct cbfs_file_attr_align {
|
||||
uint32_t tag;
|
||||
uint32_t len;
|
||||
uint32_t alignment;
|
||||
} __packed;
|
||||
|
||||
|
||||
/*** Component sub-headers ***/
|
||||
|
||||
/* Following are component sub-headers for the "standard"
|
||||
component types */
|
||||
|
||||
/** This is the sub-header for stage components. Stages are
|
||||
loaded by coreboot during the normal boot process */
|
||||
|
||||
struct cbfs_stage {
|
||||
uint32_t compression; /** Compression type */
|
||||
uint64_t entry; /** entry point */
|
||||
uint64_t load; /** Where to load in memory */
|
||||
uint32_t len; /** length of data to load */
|
||||
uint32_t memlen; /** total length of object in memory */
|
||||
} __packed;
|
||||
|
||||
/** this is the sub-header for payload components. Payloads
|
||||
are loaded by coreboot at the end of the boot process */
|
||||
|
||||
struct cbfs_payload_segment {
|
||||
uint32_t type;
|
||||
uint32_t compression;
|
||||
uint32_t offset;
|
||||
uint64_t load_addr;
|
||||
uint32_t len;
|
||||
uint32_t mem_len;
|
||||
} __packed;
|
||||
|
||||
struct cbfs_payload {
|
||||
struct cbfs_payload_segment segments;
|
||||
};
|
||||
|
||||
#define PAYLOAD_SEGMENT_CODE 0x434F4445
|
||||
#define PAYLOAD_SEGMENT_DATA 0x44415441
|
||||
#define PAYLOAD_SEGMENT_BSS 0x42535320
|
||||
#define PAYLOAD_SEGMENT_PARAMS 0x50415241
|
||||
#define PAYLOAD_SEGMENT_ENTRY 0x454E5452
|
||||
|
||||
struct cbfs_optionrom {
|
||||
uint32_t compression;
|
||||
uint32_t len;
|
||||
} __packed;
|
||||
|
||||
#endif /* _CBFS_SERIALIZED_H_ */
|
53
src/commonlib/bsd/include/commonlib/bsd/compiler.h
Normal file
53
src/commonlib/bsd/include/commonlib/bsd/compiler.h
Normal file
@ -0,0 +1,53 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-only */
|
||||
|
||||
#ifndef _COMMONLIB_BSD_COMPILER_H_
|
||||
#define _COMMONLIB_BSD_COMPILER_H_
|
||||
|
||||
#ifndef __packed
|
||||
#if defined(__WIN32) || defined(__WIN64)
|
||||
#define __packed __attribute__((gcc_struct, packed))
|
||||
#else
|
||||
#define __packed __attribute__((packed))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef __aligned
|
||||
#define __aligned(x) __attribute__((aligned(x)))
|
||||
#endif
|
||||
|
||||
#ifndef __always_unused
|
||||
#define __always_unused __attribute__((unused))
|
||||
#endif
|
||||
|
||||
#ifndef __must_check
|
||||
#define __must_check __attribute__((warn_unused_result))
|
||||
#endif
|
||||
|
||||
#ifndef __weak
|
||||
#define __weak __attribute__((weak))
|
||||
#endif
|
||||
|
||||
#ifndef __noreturn
|
||||
#define __noreturn __attribute__((noreturn))
|
||||
#endif
|
||||
|
||||
#ifndef __always_inline
|
||||
#define __always_inline inline __attribute__((always_inline))
|
||||
#endif
|
||||
|
||||
/* This evaluates to the type of the first expression, unless that is constant
|
||||
in which case it evalutates to the type of the second. This is useful when
|
||||
assigning macro parameters to temporary variables, because that would
|
||||
normally circumvent the special loosened type promotion rules for integer
|
||||
literals. By using this macro, the promotion can happen at the time the
|
||||
literal is assigned to the temporary variable. If the literal doesn't fit in
|
||||
the chosen type, -Werror=overflow will catch it, so this should be safe. */
|
||||
#define __TYPEOF_UNLESS_CONST(expr, fallback_expr) __typeof__( \
|
||||
__builtin_choose_expr(__builtin_constant_p(expr), fallback_expr, expr))
|
||||
|
||||
/* This creates a unique local variable name for use in macros. */
|
||||
#define __TMPNAME_3(i) __tmpname_##i
|
||||
#define __TMPNAME_2(i) __TMPNAME_3(i)
|
||||
#define __TMPNAME __TMPNAME_2(__COUNTER__)
|
||||
|
||||
#endif
|
21
src/commonlib/bsd/include/commonlib/bsd/compression.h
Normal file
21
src/commonlib/bsd/include/commonlib/bsd/compression.h
Normal file
@ -0,0 +1,21 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-only */
|
||||
|
||||
#ifndef _COMMONLIB_COMPRESSION_H_
|
||||
#define _COMMONLIB_COMPRESSION_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* Decompresses an LZ4F image (multiple LZ4 blocks with frame header) from src
|
||||
* to dst, ensuring that it doesn't read more than srcn bytes and doesn't write
|
||||
* more than dstn. Buffer sizes must stay below 2GB. Can decompress files loaded
|
||||
* to the end of a buffer in-place, as long as buffer is larger than the final
|
||||
* output size. (Usually just a few bytes, but may be up to (8 + dstn/255) in
|
||||
* worst case. Will reliably return an error if buffer was too small.)
|
||||
* Returns amount of decompressed bytes, or 0 on error.
|
||||
*/
|
||||
size_t ulz4fn(const void *src, size_t srcn, void *dst, size_t dstn);
|
||||
|
||||
/* Same as ulz4fn() but does not perform any bounds checks. */
|
||||
size_t ulz4f(const void *src, void *dst);
|
||||
|
||||
#endif /* _COMMONLIB_COMPRESSION_H_ */
|
41
src/commonlib/bsd/include/commonlib/bsd/fmap_serialized.h
Normal file
41
src/commonlib/bsd/include/commonlib/bsd/fmap_serialized.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-only */
|
||||
|
||||
#ifndef FLASHMAP_SERIALIZED_H__
|
||||
#define FLASHMAP_SERIALIZED_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define FMAP_SIGNATURE "__FMAP__"
|
||||
#define FMAP_VER_MAJOR 1 /* this header's FMAP minor version */
|
||||
#define FMAP_VER_MINOR 1 /* this header's FMAP minor version */
|
||||
#define FMAP_STRLEN 32 /* maximum length for strings, */
|
||||
/* including null-terminator */
|
||||
|
||||
enum fmap_flags {
|
||||
FMAP_AREA_STATIC = 1 << 0,
|
||||
FMAP_AREA_COMPRESSED = 1 << 1,
|
||||
FMAP_AREA_RO = 1 << 2,
|
||||
FMAP_AREA_PRESERVE = 1 << 3,
|
||||
};
|
||||
|
||||
/* Mapping of volatile and static regions in firmware binary */
|
||||
struct fmap_area {
|
||||
uint32_t offset; /* offset relative to base */
|
||||
uint32_t size; /* size in bytes */
|
||||
uint8_t name[FMAP_STRLEN]; /* descriptive name */
|
||||
uint16_t flags; /* flags for this area */
|
||||
} __packed;
|
||||
|
||||
struct fmap {
|
||||
uint8_t signature[8]; /* "__FMAP__" (0x5F5F464D41505F5F) */
|
||||
uint8_t ver_major; /* major version */
|
||||
uint8_t ver_minor; /* minor version */
|
||||
uint64_t base; /* address of the firmware binary */
|
||||
uint32_t size; /* size of firmware binary in bytes */
|
||||
uint8_t name[FMAP_STRLEN]; /* name of this firmware binary */
|
||||
uint16_t nareas; /* number of areas described by
|
||||
fmap_areas[] below */
|
||||
struct fmap_area areas[];
|
||||
} __packed;
|
||||
|
||||
#endif /* FLASHMAP_SERIALIZED_H__ */
|
89
src/commonlib/bsd/include/commonlib/bsd/helpers.h
Normal file
89
src/commonlib/bsd/include/commonlib/bsd/helpers.h
Normal file
@ -0,0 +1,89 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-only */
|
||||
|
||||
#ifndef COMMONLIB_BSD_HELPERS_H
|
||||
#define COMMONLIB_BSD_HELPERS_H
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
#include <commonlib/bsd/compiler.h>
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
#endif
|
||||
|
||||
#define ALIGN(x, a) __ALIGN_MASK(x, (__typeof__(x))(a)-1UL)
|
||||
#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
|
||||
#define ALIGN_UP(x, a) ALIGN((x), (a))
|
||||
#define ALIGN_DOWN(x, a) ((x) & ~((__typeof__(x))(a)-1UL))
|
||||
#define IS_ALIGNED(x, a) (((x) & ((__typeof__(x))(a)-1UL)) == 0)
|
||||
|
||||
/* Double-evaluation unsafe min/max, for bitfields and outside of functions */
|
||||
#define __CMP_UNSAFE(a, b, op) ((a) op (b) ? (a) : (b))
|
||||
#define MIN_UNSAFE(a, b) __CMP_UNSAFE(a, b, <)
|
||||
#define MAX_UNSAFE(a, b) __CMP_UNSAFE(a, b, >)
|
||||
|
||||
#define __CMP_SAFE(a, b, op, var_a, var_b) ({ \
|
||||
__TYPEOF_UNLESS_CONST(a, b) var_a = (a); \
|
||||
__TYPEOF_UNLESS_CONST(b, a) var_b = (b); \
|
||||
var_a op var_b ? var_a : var_b; \
|
||||
})
|
||||
|
||||
#define __CMP(a, b, op) __builtin_choose_expr( \
|
||||
__builtin_constant_p(a) && __builtin_constant_p(b), \
|
||||
__CMP_UNSAFE(a, b, op), __CMP_SAFE(a, b, op, __TMPNAME, __TMPNAME))
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) __CMP(a, b, <)
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) __CMP(a, b, >)
|
||||
#endif
|
||||
|
||||
#ifndef ABS
|
||||
#define ABS(a) ({ \
|
||||
__typeof__(a) _abs_local_a = (a); \
|
||||
(_abs_local_a < 0) ? (-_abs_local_a) : _abs_local_a; \
|
||||
})
|
||||
#endif
|
||||
|
||||
#define IS_POWER_OF_2(x) ({ \
|
||||
__typeof__(x) _power_local_x = (x); \
|
||||
(_power_local_x & (_power_local_x - 1)) == 0; \
|
||||
})
|
||||
|
||||
#define DIV_ROUND_UP(x, y) ({ \
|
||||
__typeof__(x) _div_local_x = (x); \
|
||||
__typeof__(y) _div_local_y = (y); \
|
||||
(_div_local_x + _div_local_y - 1) / _div_local_y; \
|
||||
})
|
||||
|
||||
#define SWAP(a, b) do { \
|
||||
__typeof__(&(a)) _swap_local_a = &(a); \
|
||||
__typeof__(&(b)) _swap_local_b = &(b); \
|
||||
__typeof__(a) _swap_local_tmp = *_swap_local_a; \
|
||||
*_swap_local_a = *_swap_local_b; \
|
||||
*_swap_local_b = _swap_local_tmp; \
|
||||
} while (0)
|
||||
|
||||
/* Standard units. */
|
||||
#define KiB (1<<10)
|
||||
#define MiB (1<<20)
|
||||
#define GiB (1<<30)
|
||||
|
||||
#define KHz (1000)
|
||||
#define MHz (1000 * KHz)
|
||||
#define GHz (1000 * MHz)
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER)
|
||||
#endif
|
||||
|
||||
#define check_member(structure, member, offset) _Static_assert( \
|
||||
offsetof(struct structure, member) == offset, \
|
||||
"`struct " #structure "` offset for `" #member "` is not " #offset)
|
||||
|
||||
/* Calculate size of structure member. */
|
||||
#define member_size(type, member) (sizeof(((type *)0)->member))
|
||||
|
||||
#endif /* COMMONLIB_BSD_HELPERS_H */
|
280
src/commonlib/bsd/lz4.c.inc
Normal file
280
src/commonlib/bsd/lz4.c.inc
Normal file
@ -0,0 +1,280 @@
|
||||
/*
|
||||
LZ4 - Fast LZ compression algorithm
|
||||
Copyright (C) 2011-2015, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : https://github.com/Cyan4973/lz4
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
|
||||
|
||||
/**************************************
|
||||
* Reading and writing into memory
|
||||
**************************************/
|
||||
|
||||
/* customized variant of memcpy, which can overwrite up to 7 bytes beyond dstEnd */
|
||||
static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd)
|
||||
{
|
||||
BYTE* d = (BYTE*)dstPtr;
|
||||
const BYTE* s = (const BYTE*)srcPtr;
|
||||
BYTE* const e = (BYTE*)dstEnd;
|
||||
|
||||
#if 0
|
||||
const size_t l2 = 8 - (((size_t)d) & (sizeof(void*)-1));
|
||||
LZ4_copy8(d,s); if (d>e-9) return;
|
||||
d+=l2; s+=l2;
|
||||
#endif /* join to align */
|
||||
|
||||
do { LZ4_copy8(d,s); d+=8; s+=8; } while (d<e);
|
||||
}
|
||||
|
||||
|
||||
/**************************************
|
||||
* Common Constants
|
||||
**************************************/
|
||||
#define MINMATCH 4
|
||||
|
||||
#define WILDCOPYLENGTH 8
|
||||
#define LASTLITERALS 5
|
||||
#define MFLIMIT (WILDCOPYLENGTH+MINMATCH)
|
||||
static const int LZ4_minLength = (MFLIMIT+1);
|
||||
|
||||
#define KB *(1 <<10)
|
||||
#define MB *(1 <<20)
|
||||
#define GB *(1U<<30)
|
||||
|
||||
#define MAXD_LOG 16
|
||||
#define MAX_DISTANCE ((1 << MAXD_LOG) - 1)
|
||||
|
||||
#define ML_BITS 4
|
||||
#define ML_MASK ((1U<<ML_BITS)-1)
|
||||
#define RUN_BITS (8-ML_BITS)
|
||||
#define RUN_MASK ((1U<<RUN_BITS)-1)
|
||||
|
||||
|
||||
/**************************************
|
||||
* Local Structures and types
|
||||
**************************************/
|
||||
typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive;
|
||||
typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive;
|
||||
typedef enum { full = 0, partial = 1 } earlyEnd_directive;
|
||||
|
||||
|
||||
|
||||
/*******************************
|
||||
* Decompression functions
|
||||
*******************************/
|
||||
/*
|
||||
* This generic decompression function cover all use cases.
|
||||
* It shall be instantiated several times, using different sets of directives
|
||||
* Note that it is essential this generic function is really inlined,
|
||||
* in order to remove useless branches during compilation optimization.
|
||||
*/
|
||||
FORCE_INLINE int LZ4_decompress_generic(
|
||||
const char* const source,
|
||||
char* const dest,
|
||||
int inputSize,
|
||||
int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */
|
||||
|
||||
int endOnInput, /* endOnOutputSize, endOnInputSize */
|
||||
int partialDecoding, /* full, partial */
|
||||
int targetOutputSize, /* only used if partialDecoding==partial */
|
||||
int dict, /* noDict, withPrefix64k, usingExtDict */
|
||||
const BYTE* const lowPrefix, /* == dest if dict == noDict */
|
||||
const BYTE* const dictStart, /* only if dict==usingExtDict */
|
||||
const size_t dictSize /* note : = 0 if noDict */
|
||||
)
|
||||
{
|
||||
/* Local Variables */
|
||||
const BYTE* ip = (const BYTE*) source;
|
||||
const BYTE* const iend = ip + inputSize;
|
||||
|
||||
BYTE* op = (BYTE*) dest;
|
||||
BYTE* const oend = op + outputSize;
|
||||
BYTE* cpy;
|
||||
BYTE* oexit = op + targetOutputSize;
|
||||
const BYTE* const lowLimit = lowPrefix - dictSize;
|
||||
|
||||
const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize;
|
||||
const unsigned dec32table[] = {4, 1, 2, 1, 4, 4, 4, 4};
|
||||
const int dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3};
|
||||
|
||||
const int safeDecode = (endOnInput==endOnInputSize);
|
||||
const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB)));
|
||||
const int inPlaceDecode = ((ip >= op) && (ip < oend));
|
||||
|
||||
|
||||
/* Special cases */
|
||||
if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */
|
||||
if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */
|
||||
if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1);
|
||||
|
||||
|
||||
/* Main Loop */
|
||||
while (1)
|
||||
{
|
||||
unsigned token;
|
||||
size_t length;
|
||||
const BYTE* match;
|
||||
size_t offset;
|
||||
|
||||
if (unlikely((inPlaceDecode) && (op + WILDCOPYLENGTH > ip))) goto _output_error; /* output stream ran over input stream */
|
||||
|
||||
/* get literal length */
|
||||
token = *ip++;
|
||||
if ((length=(token>>ML_BITS)) == RUN_MASK)
|
||||
{
|
||||
unsigned s;
|
||||
do
|
||||
{
|
||||
s = *ip++;
|
||||
length += s;
|
||||
}
|
||||
while ( likely(endOnInput ? ip<iend-RUN_MASK : 1) && (s==255) );
|
||||
if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)(op))) goto _output_error; /* overflow detection */
|
||||
if ((safeDecode) && unlikely((size_t)(ip+length)<(size_t)(ip))) goto _output_error; /* overflow detection */
|
||||
}
|
||||
|
||||
/* copy literals */
|
||||
cpy = op+length;
|
||||
if (((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) )
|
||||
|| ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)))
|
||||
{
|
||||
if (partialDecoding)
|
||||
{
|
||||
if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */
|
||||
if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */
|
||||
if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */
|
||||
}
|
||||
memmove(op, ip, length);
|
||||
ip += length;
|
||||
op += length;
|
||||
break; /* Necessarily EOF, due to parsing restrictions */
|
||||
}
|
||||
LZ4_wildCopy(op, ip, cpy);
|
||||
ip += length; op = cpy;
|
||||
|
||||
/* get offset */
|
||||
offset = LZ4_readLE16(ip); ip+=2;
|
||||
match = op - offset;
|
||||
if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside buffers */
|
||||
|
||||
/* get matchlength */
|
||||
length = token & ML_MASK;
|
||||
if (length == ML_MASK)
|
||||
{
|
||||
unsigned s;
|
||||
do
|
||||
{
|
||||
if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error;
|
||||
s = *ip++;
|
||||
length += s;
|
||||
} while (s==255);
|
||||
if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)op)) goto _output_error; /* overflow detection */
|
||||
}
|
||||
length += MINMATCH;
|
||||
|
||||
/* check external dictionary */
|
||||
if ((dict==usingExtDict) && (match < lowPrefix))
|
||||
{
|
||||
if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */
|
||||
|
||||
if (length <= (size_t)(lowPrefix-match))
|
||||
{
|
||||
/* match can be copied as a single segment from external dictionary */
|
||||
match = dictEnd - (lowPrefix-match);
|
||||
memmove(op, match, length); op += length;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* match encompass external dictionary and current block */
|
||||
size_t copySize = (size_t)(lowPrefix-match);
|
||||
memcpy(op, dictEnd - copySize, copySize);
|
||||
op += copySize;
|
||||
copySize = length - copySize;
|
||||
if (copySize > (size_t)(op-lowPrefix)) /* overlap copy */
|
||||
{
|
||||
BYTE* const endOfMatch = op + copySize;
|
||||
const BYTE* copyFrom = lowPrefix;
|
||||
while (op < endOfMatch) *op++ = *copyFrom++;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(op, lowPrefix, copySize);
|
||||
op += copySize;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* copy match within block */
|
||||
cpy = op + length;
|
||||
if (unlikely(offset<8))
|
||||
{
|
||||
const int dec64 = dec64table[offset];
|
||||
op[0] = match[0];
|
||||
op[1] = match[1];
|
||||
op[2] = match[2];
|
||||
op[3] = match[3];
|
||||
match += dec32table[offset];
|
||||
memcpy(op+4, match, 4);
|
||||
match -= dec64;
|
||||
} else { LZ4_copy8(op, match); match+=8; }
|
||||
op += 8;
|
||||
|
||||
if (unlikely(cpy>oend-12))
|
||||
{
|
||||
BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1);
|
||||
if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */
|
||||
if (op < oCopyLimit)
|
||||
{
|
||||
LZ4_wildCopy(op, match, oCopyLimit);
|
||||
match += oCopyLimit - op;
|
||||
op = oCopyLimit;
|
||||
}
|
||||
while (op<cpy) *op++ = *match++;
|
||||
}
|
||||
else
|
||||
LZ4_wildCopy(op, match, cpy);
|
||||
op=cpy; /* correction */
|
||||
}
|
||||
|
||||
/* end of decoding */
|
||||
if (endOnInput)
|
||||
return (int) (((char*)op)-dest); /* Nb of output bytes decoded */
|
||||
else
|
||||
return (int) (((const char*)ip)-source); /* Nb of input bytes read */
|
||||
|
||||
/* Overflow error detected */
|
||||
_output_error:
|
||||
return (int) (-(((const char*)ip)-source))-1;
|
||||
}
|
174
src/commonlib/bsd/lz4_wrapper.c
Normal file
174
src/commonlib/bsd/lz4_wrapper.c
Normal file
@ -0,0 +1,174 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-only */
|
||||
|
||||
#include <commonlib/bsd/compression.h>
|
||||
#include <commonlib/bsd/helpers.h>
|
||||
#include <endian.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/* LZ4 comes with its own supposedly portable memory access functions, but they
|
||||
* seem to be very inefficient in practice (at least on ARM64). Since coreboot
|
||||
* knows about endinaness and allows some basic assumptions (such as unaligned
|
||||
* access support), we can easily write the ones we need ourselves. */
|
||||
static uint16_t LZ4_readLE16(const void *src)
|
||||
{
|
||||
return le16toh(*(const uint16_t *)src);
|
||||
}
|
||||
static void LZ4_copy8(void *dst, const void *src)
|
||||
{
|
||||
/* ARM32 needs to be a special snowflake to prevent GCC from coalescing the
|
||||
* access into LDRD/STRD (which don't support unaligned accesses). */
|
||||
#ifdef __arm__ /* ARMv < 6 doesn't support unaligned accesses at all. */
|
||||
#if defined(__COREBOOT_ARM_ARCH__) && __COREBOOT_ARM_ARCH__ < 6
|
||||
int i;
|
||||
for (i = 0; i < 8; i++)
|
||||
((uint8_t *)dst)[i] = ((uint8_t *)src)[i];
|
||||
#else
|
||||
uint32_t x0, x1;
|
||||
__asm__ ("ldr %[x0], [%[src]]"
|
||||
: [x0]"=r"(x0)
|
||||
: [src]"r"(src), "m"(*(const uint32_t *)src));
|
||||
__asm__ ("ldr %[x1], [%[src], #4]"
|
||||
: [x1]"=r"(x1)
|
||||
: [src]"r"(src), "m"(*(const uint32_t *)(src + 4)));
|
||||
__asm__ ("str %[x0], [%[dst]]"
|
||||
: "=m"(*(uint32_t *)dst)
|
||||
: [x0]"r"(x0), [dst]"r"(dst));
|
||||
__asm__ ("str %[x1], [%[dst], #4]"
|
||||
: "=m"(*(uint32_t *)(dst + 4))
|
||||
: [x1]"r"(x1), [dst]"r"(dst));
|
||||
#endif
|
||||
#elif defined(__riscv)
|
||||
/* RISC-V implementations may trap on any unaligned access. */
|
||||
int i;
|
||||
for (i = 0; i < 8; i++)
|
||||
((uint8_t *)dst)[i] = ((uint8_t *)src)[i];
|
||||
#else
|
||||
*(uint64_t *)dst = *(const uint64_t *)src;
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef uint8_t BYTE;
|
||||
typedef uint16_t U16;
|
||||
typedef uint32_t U32;
|
||||
typedef int32_t S32;
|
||||
typedef uint64_t U64;
|
||||
|
||||
#define FORCE_INLINE static __always_inline
|
||||
#define likely(expr) __builtin_expect((expr) != 0, 1)
|
||||
#define unlikely(expr) __builtin_expect((expr) != 0, 0)
|
||||
|
||||
/* Unaltered (just removed unrelated code) from github.com/Cyan4973/lz4/dev. */
|
||||
#include "lz4.c.inc" /* #include for inlining, do not link! */
|
||||
|
||||
#define LZ4F_MAGICNUMBER 0x184D2204
|
||||
|
||||
struct lz4_frame_header {
|
||||
uint32_t magic;
|
||||
union {
|
||||
uint8_t flags;
|
||||
struct {
|
||||
uint8_t reserved0 : 2;
|
||||
uint8_t has_content_checksum : 1;
|
||||
uint8_t has_content_size : 1;
|
||||
uint8_t has_block_checksum : 1;
|
||||
uint8_t independent_blocks : 1;
|
||||
uint8_t version : 2;
|
||||
};
|
||||
};
|
||||
union {
|
||||
uint8_t block_descriptor;
|
||||
struct {
|
||||
uint8_t reserved1 : 4;
|
||||
uint8_t max_block_size : 3;
|
||||
uint8_t reserved2 : 1;
|
||||
};
|
||||
};
|
||||
/* + uint64_t content_size iff has_content_size is set */
|
||||
/* + uint8_t header_checksum */
|
||||
} __packed;
|
||||
|
||||
struct lz4_block_header {
|
||||
union {
|
||||
uint32_t raw;
|
||||
struct {
|
||||
uint32_t size : 31;
|
||||
uint32_t not_compressed : 1;
|
||||
};
|
||||
};
|
||||
/* + size bytes of data */
|
||||
/* + uint32_t block_checksum iff has_block_checksum is set */
|
||||
} __packed;
|
||||
|
||||
size_t ulz4fn(const void *src, size_t srcn, void *dst, size_t dstn)
|
||||
{
|
||||
const void *in = src;
|
||||
void *out = dst;
|
||||
size_t out_size = 0;
|
||||
int has_block_checksum;
|
||||
|
||||
{ /* With in-place decompression the header may become invalid later. */
|
||||
const struct lz4_frame_header *h = in;
|
||||
|
||||
if (srcn < sizeof(*h) + sizeof(uint64_t) + sizeof(uint8_t))
|
||||
return 0; /* input overrun */
|
||||
|
||||
/* We assume there's always only a single, standard frame. */
|
||||
if (le32toh(h->magic) != LZ4F_MAGICNUMBER || h->version != 1)
|
||||
return 0; /* unknown format */
|
||||
if (h->reserved0 || h->reserved1 || h->reserved2)
|
||||
return 0; /* reserved must be zero */
|
||||
if (!h->independent_blocks)
|
||||
return 0; /* we don't support block dependency */
|
||||
has_block_checksum = h->has_block_checksum;
|
||||
|
||||
in += sizeof(*h);
|
||||
if (h->has_content_size)
|
||||
in += sizeof(uint64_t);
|
||||
in += sizeof(uint8_t);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
struct lz4_block_header b = {
|
||||
{ .raw = le32toh(*(const uint32_t *)in) }
|
||||
};
|
||||
in += sizeof(struct lz4_block_header);
|
||||
|
||||
if ((size_t)(in - src) + b.size > srcn)
|
||||
break; /* input overrun */
|
||||
|
||||
if (!b.size) {
|
||||
out_size = out - dst;
|
||||
break; /* decompression successful */
|
||||
}
|
||||
|
||||
if (b.not_compressed) {
|
||||
size_t size = MIN((uintptr_t)b.size, (uintptr_t)dst
|
||||
+ dstn - (uintptr_t)out);
|
||||
memcpy(out, in, size);
|
||||
if (size < b.size)
|
||||
break; /* output overrun */
|
||||
out += size;
|
||||
} else {
|
||||
/* constant folding essential, do not touch params! */
|
||||
int ret = LZ4_decompress_generic(in, out, b.size,
|
||||
dst + dstn - out, endOnInputSize,
|
||||
full, 0, noDict, out, NULL, 0);
|
||||
if (ret < 0)
|
||||
break; /* decompression error */
|
||||
out += ret;
|
||||
}
|
||||
|
||||
in += b.size;
|
||||
if (has_block_checksum)
|
||||
in += sizeof(uint32_t);
|
||||
}
|
||||
|
||||
return out_size;
|
||||
}
|
||||
|
||||
size_t ulz4f(const void *src, void *dst)
|
||||
{
|
||||
/* LZ4 uses signed size parameters, so can't just use ((u32)-1) here. */
|
||||
return ulz4fn(src, 1*GiB, dst, 1*GiB);
|
||||
}
|
Reference in New Issue
Block a user