1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <linux/efi.h>
4 #include <linux/zlib.h>
5 
6 #include <asm/efi.h>
7 
8 #include "efistub.h"
9 
10 #include "inftrees.c"
11 #include "inffast.c"
12 #include "inflate.c"
13 
14 extern unsigned char _gzdata_start[], _gzdata_end[];
15 extern u32 __aligned(1) payload_size;
16 
17 static struct z_stream_s stream;
18 
efi_zboot_decompress_init(unsigned long * alloc_size)19 efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size)
20 {
21 	efi_status_t status;
22 	int rc;
23 
24 	/* skip the 10 byte header, assume no recorded filename */
25 	stream.next_in = _gzdata_start + 10;
26 	stream.avail_in = _gzdata_end - stream.next_in;
27 
28 	status = efi_allocate_pages(zlib_inflate_workspacesize(),
29 				    (unsigned long *)&stream.workspace,
30 				    ULONG_MAX);
31 	if (status != EFI_SUCCESS)
32 		return status;
33 
34 	rc = zlib_inflateInit2(&stream, -MAX_WBITS);
35 	if (rc != Z_OK) {
36 		efi_err("failed to initialize GZIP decompressor: %d\n", rc);
37 		status = EFI_LOAD_ERROR;
38 		goto out;
39 	}
40 
41 	*alloc_size = payload_size;
42 	return EFI_SUCCESS;
43 out:
44 	efi_free(zlib_inflate_workspacesize(), (unsigned long)stream.workspace);
45 	return status;
46 }
47 
efi_zboot_decompress(u8 * out,unsigned long outlen)48 efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen)
49 {
50 	int rc;
51 
52 	stream.next_out = out;
53 	stream.avail_out = outlen;
54 
55 	rc = zlib_inflate(&stream, 0);
56 	zlib_inflateEnd(&stream);
57 
58 	efi_free(zlib_inflate_workspacesize(), (unsigned long)stream.workspace);
59 
60 	if (rc != Z_STREAM_END) {
61 		efi_err("GZIP decompression failed with status %d\n", rc);
62 		return EFI_LOAD_ERROR;
63 	}
64 
65 	efi_cache_sync_image((unsigned long)out, outlen);
66 
67 	return EFI_SUCCESS;
68 }
69