1afee7815SWarner Losh /*
2afee7815SWarner Losh * Copyright (c) 2026 Netflix, Inc. Written by Warner Losh
3afee7815SWarner Losh *
4afee7815SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
5afee7815SWarner Losh */
6afee7815SWarner Losh
7afee7815SWarner Losh #include "stand.h"
8afee7815SWarner Losh #include "loader_efi.h"
9afee7815SWarner Losh #include <efilib.h>
10afee7815SWarner Losh #include "decompress.h"
11afee7815SWarner Losh
12afee7815SWarner Losh #include <zlib.h>
13afee7815SWarner Losh #include <bzlib.h>
14afee7815SWarner Losh #ifdef LOADER_ZFS_SUPPORT /* ZSTD only available with ZFS */
15afee7815SWarner Losh #include <zstd.h>
16afee7815SWarner Losh #endif
17afee7815SWarner Losh #include <sys/_param.h>
18afee7815SWarner Losh
19afee7815SWarner Losh #define ULL(x) ((unsigned long long)(x))
20afee7815SWarner Losh
21afee7815SWarner Losh static EFI_MEMORY_TYPE mem_type = EfiReservedMemoryType;
22afee7815SWarner Losh
23afee7815SWarner Losh struct decomp_state
24afee7815SWarner Losh {
25afee7815SWarner Losh enum compression type;
26afee7815SWarner Losh size_t size; /* Best guess at final size */
27afee7815SWarner Losh size_t alloc_size; /* Current size of `buf` */
28afee7815SWarner Losh size_t pages; /* Alloc_size in pages */
29afee7815SWarner Losh uint8_t *buf_cur; /* Current output buffer */
30afee7815SWarner Losh uint8_t *buf_end; /* Current end of allocated buffer */
31afee7815SWarner Losh EFI_PHYSICAL_ADDRESS buf; /* Decompression buffer */
32afee7815SWarner Losh union {
33afee7815SWarner Losh z_stream zstrm;
34afee7815SWarner Losh bz_stream bzstrm;
35afee7815SWarner Losh #ifdef LOADER_ZFS_SUPPORT
36afee7815SWarner Losh ZSTD_DStream *zstdstrm;
37afee7815SWarner Losh #endif
38afee7815SWarner Losh };
39afee7815SWarner Losh EFI_STATUS (*init)(decomp_state *dctx, uint8_t *first_buf, size_t buflen,
40afee7815SWarner Losh size_t size_hint);
41afee7815SWarner Losh enum step_return (*step)(decomp_state *dctx, uint8_t *buf, size_t len, size_t offset);
42afee7815SWarner Losh void (*fini)(decomp_state *dctx, bool flush);
43afee7815SWarner Losh };
44afee7815SWarner Losh
45afee7815SWarner Losh static enum compression
what_compressed(uint8_t * buf,size_t len)46afee7815SWarner Losh what_compressed(uint8_t *buf, size_t len)
47afee7815SWarner Losh {
48afee7815SWarner Losh /*
49afee7815SWarner Losh * Failsafe
50afee7815SWarner Losh */
51afee7815SWarner Losh if (len < 32)
52afee7815SWarner Losh return (none);
53afee7815SWarner Losh if (memcmp(buf, "\x1f\x8b", 2) == 0) {
54afee7815SWarner Losh printf("GZIP\n");
55afee7815SWarner Losh return (zlib);
56afee7815SWarner Losh }
57afee7815SWarner Losh if (memcmp(buf, "BZh", 3) == 0) {
58afee7815SWarner Losh printf("BZIP2\n");
59afee7815SWarner Losh return (bzip2);
60afee7815SWarner Losh }
61afee7815SWarner Losh if (memcmp(buf, "\x28\xb5\x2f\xfd", 4) == 0) {
62afee7815SWarner Losh printf("zstd\n");
63afee7815SWarner Losh return (zstd);
64afee7815SWarner Losh }
65afee7815SWarner Losh if (memcmp(buf, "\xfd""7zXZ\x00", 6) == 0) {
66afee7815SWarner Losh printf("xz -- unsupproted\n");
67afee7815SWarner Losh } else {
68afee7815SWarner Losh printf("Not compressed\n");
69afee7815SWarner Losh }
70afee7815SWarner Losh return (none);
71afee7815SWarner Losh }
72afee7815SWarner Losh
73afee7815SWarner Losh static EFI_STATUS
alloc_buffer(decomp_state * dctx,size_t size)74afee7815SWarner Losh alloc_buffer(decomp_state *dctx, size_t size)
75afee7815SWarner Losh {
76afee7815SWarner Losh dctx->alloc_size = roundup2(size, EFI_PAGE_SIZE);
77afee7815SWarner Losh dctx->pages = dctx->alloc_size / EFI_PAGE_SIZE;
78afee7815SWarner Losh EFI_STATUS status = BS->AllocatePages(AllocateAnyPages, mem_type, dctx->pages, &dctx->buf);
79afee7815SWarner Losh if (EFI_ERROR(status)) {
80afee7815SWarner Losh printf("Failed to allocate memory for %llu bytes\n", ULL(dctx->alloc_size));
81afee7815SWarner Losh return (status);
82afee7815SWarner Losh }
83*9cb14596SWarner Losh BS->SetMem((void *)(uintptr_t)dctx->buf, dctx->alloc_size, 0);
84*9cb14596SWarner Losh dctx->buf_cur = (uint8_t *)(uintptr_t)dctx->buf;
85*9cb14596SWarner Losh dctx->buf_end = (uint8_t *)(uintptr_t)dctx->buf + dctx->alloc_size;
86afee7815SWarner Losh return (EFI_SUCCESS);
87afee7815SWarner Losh }
88afee7815SWarner Losh
89afee7815SWarner Losh static EFI_STATUS
grow_buffer(decomp_state * dctx)90afee7815SWarner Losh grow_buffer(decomp_state *dctx)
91afee7815SWarner Losh {
92afee7815SWarner Losh /*
93afee7815SWarner Losh * a 1.5 exp growth trades a few more copies for a little less waste.
94afee7815SWarner Losh */
95afee7815SWarner Losh size_t newsz = roundup2(dctx->alloc_size * 3 / 2, EFI_PAGE_SIZE);
96afee7815SWarner Losh size_t newpages = newsz / EFI_PAGE_SIZE;
97afee7815SWarner Losh EFI_PHYSICAL_ADDRESS newbuf;
98afee7815SWarner Losh EFI_STATUS status = BS->AllocatePages(AllocateAnyPages, mem_type, newpages, &newbuf);
99afee7815SWarner Losh if (EFI_ERROR(status)) {
100afee7815SWarner Losh printf("Failed to allocate memory for %llu bytes\n", ULL(newsz));
101afee7815SWarner Losh return (status);
102afee7815SWarner Losh }
103*9cb14596SWarner Losh memcpy((void *)(uintptr_t)newbuf, (void *)(uintptr_t)dctx->buf, dctx->alloc_size);
104afee7815SWarner Losh BS->FreePages(dctx->buf, dctx->pages);
105afee7815SWarner Losh dctx->buf = newbuf;
106afee7815SWarner Losh dctx->pages = newpages;
107*9cb14596SWarner Losh dctx->buf_cur = (uint8_t *)(uintptr_t)dctx->buf + dctx->alloc_size;
108*9cb14596SWarner Losh dctx->buf_end = (uint8_t *)(uintptr_t)dctx->buf + newsz;
109afee7815SWarner Losh BS->SetMem(dctx->buf_cur, newsz - dctx->alloc_size, 0);
110afee7815SWarner Losh dctx->alloc_size = newsz;
111afee7815SWarner Losh return (EFI_SUCCESS);
112afee7815SWarner Losh }
113afee7815SWarner Losh
114afee7815SWarner Losh static void
free_buffer(decomp_state * dctx)115afee7815SWarner Losh free_buffer(decomp_state *dctx)
116afee7815SWarner Losh {
117afee7815SWarner Losh if (dctx->buf)
118afee7815SWarner Losh BS->FreePages(dctx->buf, dctx->pages);
119afee7815SWarner Losh dctx->buf = 0;
120afee7815SWarner Losh }
121afee7815SWarner Losh
122afee7815SWarner Losh /*
123afee7815SWarner Losh * zlib supprot
124afee7815SWarner Losh */
125afee7815SWarner Losh static EFI_STATUS
zlib_init(decomp_state * dctx,uint8_t * first_buf,size_t buflen,size_t size_hint)126afee7815SWarner Losh zlib_init(decomp_state *dctx, uint8_t *first_buf, size_t buflen, size_t size_hint)
127afee7815SWarner Losh {
128afee7815SWarner Losh z_stream *strm = &dctx->zstrm;
129afee7815SWarner Losh
130afee7815SWarner Losh /*
131afee7815SWarner Losh * Assume 4x compression, but start at 64MB
132afee7815SWarner Losh */
133afee7815SWarner Losh dctx->size = max(size_hint * 4, M(64));
134afee7815SWarner Losh EFI_STATUS status = alloc_buffer(dctx, dctx->size);
135afee7815SWarner Losh if (EFI_ERROR(status))
136afee7815SWarner Losh return (status);
137afee7815SWarner Losh memset(strm, 0, sizeof(*strm));
138afee7815SWarner Losh strm->next_in = first_buf;
139afee7815SWarner Losh strm->avail_in = buflen;
140afee7815SWarner Losh return (inflateInit2(strm, 15 + 16) == Z_OK ? EFI_SUCCESS : EFI_VOLUME_CORRUPTED);
141afee7815SWarner Losh }
142afee7815SWarner Losh
143afee7815SWarner Losh static enum step_return
zlib_step(decomp_state * dctx,uint8_t * buf,size_t len,size_t offset)144afee7815SWarner Losh zlib_step(decomp_state *dctx, uint8_t *buf, size_t len, size_t offset)
145afee7815SWarner Losh {
146afee7815SWarner Losh z_stream *strm = &dctx->zstrm;
147afee7815SWarner Losh size_t outlen = dctx->buf_end - dctx->buf_cur;
148afee7815SWarner Losh
149afee7815SWarner Losh strm->next_in = buf;
150afee7815SWarner Losh strm->avail_in = len;
151afee7815SWarner Losh strm->next_out = dctx->buf_cur;
152afee7815SWarner Losh strm->avail_out = outlen;
153afee7815SWarner Losh
154afee7815SWarner Losh int ret = inflate(strm, Z_NO_FLUSH);
155afee7815SWarner Losh dctx->buf_cur += outlen - strm->avail_out;
156afee7815SWarner Losh
157afee7815SWarner Losh if (ret == Z_STREAM_END)
158afee7815SWarner Losh return (done);
159afee7815SWarner Losh if (ret != Z_OK)
160afee7815SWarner Losh return (err);
161afee7815SWarner Losh if (dctx->buf_cur < dctx->buf_end) /* Have output space */
162afee7815SWarner Losh return (ok);
163afee7815SWarner Losh
164afee7815SWarner Losh /*
165afee7815SWarner Losh * We're out of space, grow the buffer and try again if there's buffer
166afee7815SWarner Losh * space. We try again recursively since we know that will usually go
167afee7815SWarner Losh * only 1 deep.
168afee7815SWarner Losh */
169afee7815SWarner Losh if (EFI_ERROR(grow_buffer(dctx)))
170afee7815SWarner Losh return (err);
171afee7815SWarner Losh if (strm->avail_in == 0)
172afee7815SWarner Losh return (ok);
173afee7815SWarner Losh size_t consumed = len - strm->avail_in;
174afee7815SWarner Losh return (zlib_step(dctx, buf + consumed, strm->avail_in, offset + consumed));
175afee7815SWarner Losh }
176afee7815SWarner Losh
177afee7815SWarner Losh static void
zlib_fini(decomp_state * dctx,bool flush)178afee7815SWarner Losh zlib_fini(decomp_state *dctx, bool flush)
179afee7815SWarner Losh {
180afee7815SWarner Losh inflateEnd(&dctx->zstrm);
181afee7815SWarner Losh if (!flush)
182afee7815SWarner Losh return;
183afee7815SWarner Losh free_buffer(dctx);
184afee7815SWarner Losh }
185afee7815SWarner Losh
186afee7815SWarner Losh /*
187afee7815SWarner Losh * Bzip2 supprot
188afee7815SWarner Losh */
189afee7815SWarner Losh static EFI_STATUS
bzip2_init(decomp_state * dctx,uint8_t * first_buf,size_t buflen,size_t size_hint)190afee7815SWarner Losh bzip2_init(decomp_state *dctx, uint8_t *first_buf, size_t buflen, size_t size_hint)
191afee7815SWarner Losh {
192afee7815SWarner Losh bz_stream *strm = &dctx->bzstrm;
193afee7815SWarner Losh
194afee7815SWarner Losh /*
195afee7815SWarner Losh * Assume 4x compression, but start at 64MB
196afee7815SWarner Losh */
197afee7815SWarner Losh dctx->size = max(size_hint * 4, M(64));
198afee7815SWarner Losh EFI_STATUS status = alloc_buffer(dctx, dctx->size);
199afee7815SWarner Losh if (EFI_ERROR(status))
200afee7815SWarner Losh return (status);
201afee7815SWarner Losh memset(strm, 0, sizeof(*strm));
202afee7815SWarner Losh strm->next_in = first_buf;
203afee7815SWarner Losh strm->avail_in = buflen;
204afee7815SWarner Losh return (BZ2_bzDecompressInit(strm, 0, 0) == BZ_OK ? EFI_SUCCESS : EFI_VOLUME_CORRUPTED);
205afee7815SWarner Losh }
206afee7815SWarner Losh
207afee7815SWarner Losh static enum step_return
bzip2_step(decomp_state * dctx,uint8_t * buf,size_t len,size_t offset)208afee7815SWarner Losh bzip2_step(decomp_state *dctx, uint8_t *buf, size_t len, size_t offset)
209afee7815SWarner Losh {
210afee7815SWarner Losh bz_stream *strm = &dctx->bzstrm;
211afee7815SWarner Losh size_t outlen = dctx->buf_end - dctx->buf_cur;
212afee7815SWarner Losh
213afee7815SWarner Losh strm->next_in = buf;
214afee7815SWarner Losh strm->avail_in = len;
215afee7815SWarner Losh strm->next_out = dctx->buf_cur;
216afee7815SWarner Losh strm->avail_out = outlen;
217afee7815SWarner Losh
218afee7815SWarner Losh int ret = BZ2_bzDecompress(strm);
219afee7815SWarner Losh dctx->buf_cur += outlen - strm->avail_out;
220afee7815SWarner Losh
221afee7815SWarner Losh if (ret == BZ_STREAM_END)
222afee7815SWarner Losh return (done);
223afee7815SWarner Losh if (ret != Z_OK)
224afee7815SWarner Losh return (err);
225afee7815SWarner Losh if (dctx->buf_cur < dctx->buf_end) /* Have output space */
226afee7815SWarner Losh return (ok);
227afee7815SWarner Losh
228afee7815SWarner Losh /*
229afee7815SWarner Losh * We're out of space, grow the buffer and try again if there's buffer
230afee7815SWarner Losh * space. We try again recursively since we know that will usually go
231afee7815SWarner Losh * only 1 deep.
232afee7815SWarner Losh */
233afee7815SWarner Losh if (EFI_ERROR(grow_buffer(dctx)))
234afee7815SWarner Losh return (err);
235afee7815SWarner Losh if (strm->avail_in == 0)
236afee7815SWarner Losh return (ok);
237afee7815SWarner Losh size_t consumed = len - strm->avail_in;
238afee7815SWarner Losh return (bzip2_step(dctx, buf + consumed, strm->avail_in, offset + consumed));
239afee7815SWarner Losh }
240afee7815SWarner Losh
241afee7815SWarner Losh static void
bzip2_fini(decomp_state * dctx,bool flush)242afee7815SWarner Losh bzip2_fini(decomp_state *dctx, bool flush)
243afee7815SWarner Losh {
244afee7815SWarner Losh BZ2_bzDecompressEnd(&dctx->bzstrm);
245afee7815SWarner Losh if (!flush)
246afee7815SWarner Losh return;
247afee7815SWarner Losh free_buffer(dctx);
248afee7815SWarner Losh }
249afee7815SWarner Losh
250afee7815SWarner Losh /*
251afee7815SWarner Losh * ZSTD supprot
252afee7815SWarner Losh */
253afee7815SWarner Losh #ifdef LOADER_ZFS_SUPPORT
254afee7815SWarner Losh static EFI_STATUS
zstd_init(decomp_state * dctx,uint8_t * first_buf,size_t buflen,size_t size_hint)255afee7815SWarner Losh zstd_init(decomp_state *dctx, uint8_t *first_buf, size_t buflen, size_t size_hint)
256afee7815SWarner Losh {
257afee7815SWarner Losh unsigned long long size = ZSTD_getFrameContentSize(first_buf, buflen);
258afee7815SWarner Losh if (size == ZSTD_CONTENTSIZE_ERROR)
259afee7815SWarner Losh return (EFI_VOLUME_CORRUPTED);
260afee7815SWarner Losh if (size == ZSTD_CONTENTSIZE_UNKNOWN)
261afee7815SWarner Losh dctx->size = max(size_hint * 4, M(64)); /* Guess 4x compression or 64M */
262afee7815SWarner Losh else
263afee7815SWarner Losh dctx->size = size; /* We know the size */
264afee7815SWarner Losh EFI_STATUS status = alloc_buffer(dctx, dctx->size);
265afee7815SWarner Losh if (EFI_ERROR(status))
266afee7815SWarner Losh return (status);
267afee7815SWarner Losh
268afee7815SWarner Losh dctx->zstdstrm = ZSTD_createDStream();
269afee7815SWarner Losh if (dctx->zstdstrm == NULL)
270afee7815SWarner Losh return (EFI_OUT_OF_RESOURCES);
271afee7815SWarner Losh if (ZSTD_isError(ZSTD_initDStream(dctx->zstdstrm))) {
272afee7815SWarner Losh ZSTD_freeDStream(dctx->zstdstrm);
273afee7815SWarner Losh dctx->zstdstrm = NULL;
274afee7815SWarner Losh return (EFI_OUT_OF_RESOURCES);
275afee7815SWarner Losh }
276afee7815SWarner Losh return (EFI_SUCCESS);
277afee7815SWarner Losh }
278afee7815SWarner Losh
279afee7815SWarner Losh static enum step_return
zstd_step(decomp_state * dctx,uint8_t * buf,size_t len,size_t offset)280afee7815SWarner Losh zstd_step(decomp_state *dctx, uint8_t *buf, size_t len, size_t offset)
281afee7815SWarner Losh {
282afee7815SWarner Losh size_t outlen = dctx->buf_end - dctx->buf_cur;
283afee7815SWarner Losh ZSTD_inBuffer inbuf = { buf, len, 0 };
284afee7815SWarner Losh ZSTD_outBuffer outbuf = { dctx->buf_cur, outlen, 0 };
285afee7815SWarner Losh size_t ret;
286afee7815SWarner Losh
287afee7815SWarner Losh ret = ZSTD_decompressStream(dctx->zstdstrm, &outbuf, &inbuf);
288afee7815SWarner Losh dctx->buf_cur += outbuf.pos;
289afee7815SWarner Losh
290afee7815SWarner Losh if (ZSTD_isError(ret))
291afee7815SWarner Losh return (err);
292afee7815SWarner Losh if (ret == 0)
293afee7815SWarner Losh return (done);
294afee7815SWarner Losh if (dctx->buf_cur < dctx->buf_end) /* Have output space */
295afee7815SWarner Losh return (ok);
296afee7815SWarner Losh
297afee7815SWarner Losh /*
298afee7815SWarner Losh * We're out of space, grow the buffer and try again if there's buffer
299afee7815SWarner Losh * space. We try again recursively since we know that will usually go
300afee7815SWarner Losh * only 1 deep.
301afee7815SWarner Losh */
302afee7815SWarner Losh if (EFI_ERROR(grow_buffer(dctx)))
303afee7815SWarner Losh return (err);
304afee7815SWarner Losh if (inbuf.size == inbuf.pos)
305afee7815SWarner Losh return (ok);
306afee7815SWarner Losh return (zstd_step(dctx, buf + inbuf.pos, inbuf.size - inbuf.pos, offset + inbuf.pos));
307afee7815SWarner Losh }
308afee7815SWarner Losh
309afee7815SWarner Losh static void
zstd_fini(decomp_state * dctx,bool flush)310afee7815SWarner Losh zstd_fini(decomp_state *dctx, bool flush)
311afee7815SWarner Losh {
312afee7815SWarner Losh ZSTD_freeDStream(dctx->zstdstrm);
313afee7815SWarner Losh if (!flush)
314afee7815SWarner Losh return;
315afee7815SWarner Losh free_buffer(dctx);
316afee7815SWarner Losh }
317afee7815SWarner Losh #endif
318afee7815SWarner Losh
319afee7815SWarner Losh /*
320afee7815SWarner Losh * No / Unknown decompression fallback
321afee7815SWarner Losh */
322afee7815SWarner Losh static EFI_STATUS
null_init(decomp_state * dctx,uint8_t * first_buf,size_t buflen,size_t size_hint)323afee7815SWarner Losh null_init(decomp_state *dctx, uint8_t *first_buf, size_t buflen, size_t size_hint)
324afee7815SWarner Losh {
325afee7815SWarner Losh dctx->size = size_hint;
326afee7815SWarner Losh return (alloc_buffer(dctx, size_hint));
327afee7815SWarner Losh }
328afee7815SWarner Losh
329afee7815SWarner Losh static enum step_return
null_step(decomp_state * dctx,uint8_t * buf,size_t len,size_t offset)330afee7815SWarner Losh null_step(decomp_state *dctx, uint8_t *buf, size_t len, size_t offset)
331afee7815SWarner Losh {
332afee7815SWarner Losh size_t end = offset + len;
333afee7815SWarner Losh
334afee7815SWarner Losh if (end > dctx->size) {
335afee7815SWarner Losh printf("Too much data recieved!");
336afee7815SWarner Losh return (err);
337afee7815SWarner Losh }
338afee7815SWarner Losh
339afee7815SWarner Losh CHAR8 *src = buf;
340*9cb14596SWarner Losh CHAR8 *dst = (void*)(uintptr_t)(dctx->buf + offset);
341afee7815SWarner Losh BS->CopyMem(dst, src, len);
342afee7815SWarner Losh return (end == dctx->size ? done : ok);
343afee7815SWarner Losh }
344afee7815SWarner Losh
345afee7815SWarner Losh static void
null_fini(decomp_state * dctx,bool flush)346afee7815SWarner Losh null_fini(decomp_state *dctx, bool flush)
347afee7815SWarner Losh {
348afee7815SWarner Losh if (!flush)
349afee7815SWarner Losh return;
350afee7815SWarner Losh free_buffer(dctx);
351afee7815SWarner Losh }
352afee7815SWarner Losh
353afee7815SWarner Losh decomp_state *
decomp_init(uint8_t * buf,size_t buflen,size_t size_hint)354afee7815SWarner Losh decomp_init(uint8_t *buf, size_t buflen, size_t size_hint)
355afee7815SWarner Losh {
356afee7815SWarner Losh decomp_state *dctx;
357afee7815SWarner Losh
358afee7815SWarner Losh dctx = malloc(sizeof(*dctx));
359afee7815SWarner Losh memset(dctx, 0, sizeof(*dctx));
360afee7815SWarner Losh dctx->type = what_compressed(buf, buflen);
361afee7815SWarner Losh switch (dctx->type) {
362afee7815SWarner Losh case zlib:
363afee7815SWarner Losh dctx->init = zlib_init;
364afee7815SWarner Losh dctx->step = zlib_step;
365afee7815SWarner Losh dctx->fini = zlib_fini;
366afee7815SWarner Losh break;
367afee7815SWarner Losh case bzip2:
368afee7815SWarner Losh dctx->init = bzip2_init;
369afee7815SWarner Losh dctx->step = bzip2_step;
370afee7815SWarner Losh dctx->fini = bzip2_fini;
371afee7815SWarner Losh break;
372afee7815SWarner Losh #ifdef LOADER_ZFS_SUPPORT
373afee7815SWarner Losh case zstd:
374afee7815SWarner Losh dctx->init = zstd_init;
375afee7815SWarner Losh dctx->step = zstd_step;
376afee7815SWarner Losh dctx->fini = zstd_fini;
377afee7815SWarner Losh break;
378afee7815SWarner Losh #endif
379afee7815SWarner Losh case none:
380afee7815SWarner Losh dctx->init = null_init;
381afee7815SWarner Losh dctx->step = null_step;
382afee7815SWarner Losh dctx->fini = null_fini;
383afee7815SWarner Losh break;
384afee7815SWarner Losh default:
385afee7815SWarner Losh return (NULL);
386afee7815SWarner Losh }
387afee7815SWarner Losh
388afee7815SWarner Losh if (EFI_ERROR(dctx->init(dctx, buf, buflen, size_hint))) {
389afee7815SWarner Losh free(dctx);
390afee7815SWarner Losh dctx = NULL;
391afee7815SWarner Losh }
392afee7815SWarner Losh return (dctx);
393afee7815SWarner Losh }
394afee7815SWarner Losh
395afee7815SWarner Losh enum step_return
decomp_step(decomp_state * dctx,uint8_t * buf,size_t len,size_t offset)396afee7815SWarner Losh decomp_step(decomp_state *dctx, uint8_t *buf, size_t len, size_t offset)
397afee7815SWarner Losh {
398afee7815SWarner Losh return (dctx->step(dctx, buf, len, offset));
399afee7815SWarner Losh }
400afee7815SWarner Losh
401afee7815SWarner Losh void
decomp_fini(decomp_state * dctx,bool flush)402afee7815SWarner Losh decomp_fini(decomp_state *dctx, bool flush)
403afee7815SWarner Losh {
404afee7815SWarner Losh return (dctx->fini(dctx, flush));
405afee7815SWarner Losh }
406afee7815SWarner Losh
407afee7815SWarner Losh EFI_PHYSICAL_ADDRESS
decomp_buffer(decomp_state * dctx)408afee7815SWarner Losh decomp_buffer(decomp_state *dctx)
409afee7815SWarner Losh {
410afee7815SWarner Losh if (dctx == NULL)
411afee7815SWarner Losh return (0);
412afee7815SWarner Losh return (dctx->buf);
413afee7815SWarner Losh }
414afee7815SWarner Losh
415afee7815SWarner Losh size_t
decomp_buffer_length(decomp_state * dctx)416afee7815SWarner Losh decomp_buffer_length(decomp_state *dctx)
417afee7815SWarner Losh {
418afee7815SWarner Losh if (dctx == NULL)
419afee7815SWarner Losh return (0);
420*9cb14596SWarner Losh return ((uintptr_t)dctx->buf_cur - (uintptr_t)dctx->buf);
421afee7815SWarner Losh }
422