summaryrefslogtreecommitdiff
path: root/drivers/firmware/efi/libstub/zboot-decompress-gzip.c
blob: e97a7e9d3c980b24577393148580b78aa604b9c2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// SPDX-License-Identifier: GPL-2.0

#include <linux/efi.h>
#include <linux/zlib.h>

#include <asm/efi.h>

#include "efistub.h"

#include "inftrees.c"
#include "inffast.c"
#include "inflate.c"

extern unsigned char _gzdata_start[], _gzdata_end[];
extern u32 __aligned(1) payload_size;

static struct z_stream_s stream;

efi_status_t efi_zboot_decompress_init(unsigned long *alloc_size)
{
	efi_status_t status;
	int rc;

	/* skip the 10 byte header, assume no recorded filename */
	stream.next_in = _gzdata_start + 10;
	stream.avail_in = _gzdata_end - stream.next_in;

	status = efi_allocate_pages(zlib_inflate_workspacesize(),
				    (unsigned long *)&stream.workspace,
				    ULONG_MAX);
	if (status != EFI_SUCCESS)
		return status;

	rc = zlib_inflateInit2(&stream, -MAX_WBITS);
	if (rc != Z_OK) {
		efi_err("failed to initialize GZIP decompressor: %d\n", rc);
		status = EFI_LOAD_ERROR;
		goto out;
	}

	*alloc_size = payload_size;
	return EFI_SUCCESS;
out:
	efi_free(zlib_inflate_workspacesize(), (unsigned long)stream.workspace);
	return status;
}

efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen)
{
	int rc;

	stream.next_out = out;
	stream.avail_out = outlen;

	rc = zlib_inflate(&stream, 0);
	zlib_inflateEnd(&stream);

	efi_free(zlib_inflate_workspacesize(), (unsigned long)stream.workspace);

	if (rc != Z_STREAM_END) {
		efi_err("GZIP decompression failed with status %d\n", rc);
		return EFI_LOAD_ERROR;
	}

	efi_cache_sync_image((unsigned long)out, outlen);

	return EFI_SUCCESS;
}