1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2021 Google LLC
4  */
5 
6 #define LOG_CATEGORY	LOGC_BOOT
7 
8 #include <common.h>
9 #include <abuf.h>
10 #include <log.h>
11 #include <malloc.h>
12 #include <linux/zstd.h>
13 
zstd_decompress(struct abuf * in,struct abuf * out)14 int zstd_decompress(struct abuf *in, struct abuf *out)
15 {
16 	zstd_dctx *ctx;
17 	size_t wsize, len;
18 	void *workspace;
19 	int ret;
20 
21 	wsize = zstd_dctx_workspace_bound();
22 	workspace = malloc(wsize);
23 	if (!workspace) {
24 		debug("%s: cannot allocate workspace of size %zu\n", __func__,
25 			wsize);
26 		return -ENOMEM;
27 	}
28 
29 	ctx = zstd_init_dctx(workspace, wsize);
30 	if (!ctx) {
31 		log_err("%s: zstd_init_dctx() failed\n", __func__);
32 		ret = -EPERM;
33 		goto do_free;
34 	}
35 
36 	/*
37 	 * Find out how large the frame actually is, there may be junk at
38 	 * the end of the frame that zstd_decompress_dctx() can't handle.
39 	 */
40 	len = zstd_find_frame_compressed_size(abuf_data(in), abuf_size(in));
41 	if (zstd_is_error(len)) {
42 		log_err("%s: failed to detect compressed size: %d\n", __func__,
43 			zstd_get_error_code(len));
44 		ret = -EINVAL;
45 		goto do_free;
46 	}
47 
48 	len = zstd_decompress_dctx(ctx, abuf_data(out), abuf_size(out),
49 				   abuf_data(in), len);
50 	if (zstd_is_error(len)) {
51 		log_err("%s: failed to decompress: %d\n", __func__,
52 			zstd_get_error_code(len));
53 		ret = -EINVAL;
54 		goto do_free;
55 	}
56 
57 	ret = len;
58 do_free:
59 	free(workspace);
60 	return ret;
61 }
62