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_DStream *dstream;
17 	ZSTD_inBuffer in_buf;
18 	ZSTD_outBuffer out_buf;
19 	void *workspace;
20 	size_t wsize;
21 	int ret;
22 
23 	wsize = ZSTD_DStreamWorkspaceBound(abuf_size(in));
24 	workspace = malloc(wsize);
25 	if (!workspace) {
26 		debug("%s: cannot allocate workspace of size %zu\n", __func__,
27 			wsize);
28 		return -ENOMEM;
29 	}
30 
31 	dstream = ZSTD_initDStream(abuf_size(in), workspace, wsize);
32 	if (!dstream) {
33 		log_err("%s: ZSTD_initDStream failed\n", __func__);
34 		ret = -EPERM;
35 		goto do_free;
36 	}
37 
38 	in_buf.src = abuf_data(in);
39 	in_buf.pos = 0;
40 	in_buf.size = abuf_size(in);
41 
42 	out_buf.dst = abuf_data(out);
43 	out_buf.pos = 0;
44 	out_buf.size = abuf_size(out);
45 
46 	while (1) {
47 		size_t res;
48 
49 		res = ZSTD_decompressStream(dstream, &out_buf, &in_buf);
50 		if (ZSTD_isError(res)) {
51 			ret = ZSTD_getErrorCode(res);
52 			log_err("ZSTD_decompressStream error %d\n", ret);
53 			goto do_free;
54 		}
55 
56 		if (in_buf.pos >= abuf_size(in) || !res)
57 			break;
58 	}
59 
60 	ret = out_buf.pos;
61 do_free:
62 	free(workspace);
63 	return ret;
64 }
65