All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFCv2 0/7] kexec: Use BPF lskel to enable kexec to load PE format boot image
@ 2025-04-29  4:12 Pingfan Liu
  2025-04-29  4:12 ` [RFCv2 1/7] kexec_file: Make kexec_image_load_default global visible Pingfan Liu
                   ` (6 more replies)
  0 siblings, 7 replies; 13+ messages in thread
From: Pingfan Liu @ 2025-04-29  4:12 UTC (permalink / raw)
  Cc: Pingfan Liu, Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Jeremy Linton, Catalin Marinas, Will Deacon,
	Ard Biesheuvel, Simon Horman, Gerd Hoffmann, Vitaly Kuznetsov,
	Philipp Rudo, Viktor Malik, Jan Hendrik Farr, Baoquan He,
	Dave Young, Eric Biederman, Andrew Morton, kexec, bpf

*** Review the history ***

Nowadays UEFI PE bootable image is more and more popular on the distribution.
But it is still an open issue to load that kind of image by kexec with IMA enabled

There are several approaches to reslove this issue, but none of them are
accepted in upstream till now.

The summary of those approaches:
  -1. UEFI service emulator for UEFI stub
  -2. PE format parser in kernel

For the first one, I have tried a purgatory-style emulator [1]. But it
confronts the hardware scaling trouble.  For the second one, there are two
choices, one is to implement it inside the kernel, the other is inside the user
space.  Both zboot-format [2] and UKI-format [3] parsers are rejected due to
the concern that the variant format parsers will inflate the kernel code.  And
finally, we have these kinds of parsers in the user space 'kexec-tools'.


*** The approach in this series ***

This approach allows the various PE boot image to be parsed in the bpf-prog,
as a result, the kexec kernel code to remain relatively stable.

To protect against malicious attacks on the BPF loader in user space, it
employs BPF lskel to load and execute BPF programs from within the
kernel.

Each type of PE image contains a dedicated section '.bpf', which stores
the bpf-prog designed to parse the format.  This ensures that the PE's
signature also protects the integrity of the '.bpf' section.


The parsing process operates as a pipeline. The current BPF program
parser attaches to bpf_handle_pefile() and detaches at the end of the
current stage via disarm_bpf_prog(). The results parsed by the current
BPF program are buffered in the kernel through prepare_nested_pe() and
then delivered to the next stage. For each stage of the pipeline, the
BPF bytecode is stored in the '.bpf' section of the PE file. That means
a vmlinuz.efi embeded in UKI format can be handled.


Special thanks to Philipp Rudo, who spent significant time evaluating
the practicality of my solution, and to Viktor Malik, who guided me
toward using BPF light skeleton to prevent malicious attacks from user
space.


*** To do ***
For Poc, this series uses BPF fentry to call the parsing function.
Later, it should implement a dedicated BPF_PROG_TYPE and confine the use
of the newly introduced three kfuncs to the kexec_file_load context



[1]: https://lore.kernel.org/lkml/20240819145417.23367-1-piliu@redhat.com/T/
[2]: https://lore.kernel.org/kexec/20230306030305.15595-1-kernelfans@gmail.com/
[3]: https://lore.kernel.org/lkml/20230911052535.335770-1-kernel@jfarr.cc/
[4]: https://lore.kernel.org/linux-arm-kernel/20230921133703.39042-2-kernelfans@gmail.com/T/


RFCv1 -> RFCv2
  - Use bpf kfunc instead of helper
  - Use C source code to generate the light skeleton file

---
Pingfan Liu (7):
  kexec_file: Make kexec_image_load_default global visible
  kexec: Introduce kexec_pe_image to parse and load PE file
  lib/decompress: Keep decompressor when CONFIG_KEXEC_PE_IMAGE
  bpf/kexec: Introduce two bpf kfunc for kexec
  kexec: Introduce a bpf-prog lskel
  kexec: Integrate bpf light skeleton to load zboot image
  arm64/kexec: Add PE image format support

 arch/arm64/Kconfig                           |   1 +
 arch/arm64/include/asm/kexec.h               |   1 +
 arch/arm64/kernel/machine_kexec_file.c       |   3 +
 include/linux/decompress/mm.h                |   7 +
 include/linux/kexec.h                        |   2 +
 kernel/Kconfig.kexec                         |   8 +
 kernel/Makefile                              |   2 +
 kernel/kexec_bpf/Makefile                    |  65 ++
 kernel/kexec_bpf/kexec_pe_parser_bpf.c       |  66 ++
 kernel/kexec_bpf/kexec_pe_parser_bpf.lskel.h | 147 +++++
 kernel/kexec_file.c                          |   2 +-
 kernel/kexec_pe_image.c                      | 611 +++++++++++++++++++
 lib/decompress.c                             |   6 +-
 13 files changed, 917 insertions(+), 4 deletions(-)
 create mode 100644 kernel/kexec_bpf/Makefile
 create mode 100644 kernel/kexec_bpf/kexec_pe_parser_bpf.c
 create mode 100644 kernel/kexec_bpf/kexec_pe_parser_bpf.lskel.h
 create mode 100644 kernel/kexec_pe_image.c

-- 
2.49.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [RFCv2 1/7] kexec_file: Make kexec_image_load_default global visible
  2025-04-29  4:12 [RFCv2 0/7] kexec: Use BPF lskel to enable kexec to load PE format boot image Pingfan Liu
@ 2025-04-29  4:12 ` Pingfan Liu
  2025-04-29  4:12 ` [RFCv2 2/7] kexec: Introduce kexec_pe_image to parse and load PE file Pingfan Liu
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Pingfan Liu @ 2025-04-29  4:12 UTC (permalink / raw)
  To: kexec
  Cc: Pingfan Liu, Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Jeremy Linton, Catalin Marinas, Will Deacon,
	Ard Biesheuvel, Simon Horman, Gerd Hoffmann, Vitaly Kuznetsov,
	Philipp Rudo, Viktor Malik, Jan Hendrik Farr, Baoquan He,
	Dave Young, Eric Biederman, Andrew Morton, bpf

In latter patches, PE format parser will extract the linux kernel inside
and try its real format parser. So making kexec_image_load_default
global.

Signed-off-by: Pingfan Liu <piliu@redhat.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: Eric Biederman <ebiederm@xmission.com>
To: kexec@lists.infradead.org
---
 include/linux/kexec.h | 1 +
 kernel/kexec_file.c   | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index c8971861521a5..26398b269ac29 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -148,6 +148,7 @@ extern const struct kexec_file_ops * const kexec_file_loaders[];
 
 int kexec_image_probe_default(struct kimage *image, void *buf,
 			      unsigned long buf_len);
+void *kexec_image_load_default(struct kimage *image);
 int kexec_image_post_load_cleanup_default(struct kimage *image);
 
 /*
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index fba686487e3b5..6a72bdfab5f5c 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -65,7 +65,7 @@ int kexec_image_probe_default(struct kimage *image, void *buf,
 	return ret;
 }
 
-static void *kexec_image_load_default(struct kimage *image)
+void *kexec_image_load_default(struct kimage *image)
 {
 	if (!image->fops || !image->fops->load)
 		return ERR_PTR(-ENOEXEC);
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFCv2 2/7] kexec: Introduce kexec_pe_image to parse and load PE file
  2025-04-29  4:12 [RFCv2 0/7] kexec: Use BPF lskel to enable kexec to load PE format boot image Pingfan Liu
  2025-04-29  4:12 ` [RFCv2 1/7] kexec_file: Make kexec_image_load_default global visible Pingfan Liu
@ 2025-04-29  4:12 ` Pingfan Liu
  2025-04-29  4:12 ` [RFCv2 3/7] lib/decompress: Keep decompressor when CONFIG_KEXEC_PE_IMAGE Pingfan Liu
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Pingfan Liu @ 2025-04-29  4:12 UTC (permalink / raw)
  To: kexec
  Cc: Pingfan Liu, Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Jeremy Linton, Catalin Marinas, Will Deacon,
	Ard Biesheuvel, Simon Horman, Gerd Hoffmann, Vitaly Kuznetsov,
	Philipp Rudo, Viktor Malik, Jan Hendrik Farr, Baoquan He,
	Dave Young, Eric Biederman, Andrew Morton, bpf

As UEFI becomes popular, a few architectures support to boot a PE format
kernel image directly. But the internal of PE format varies, which means
each parser for each format.

This patch (with the rest in this series) introduces a common skeleton
to parse all these kinds of file, and leave the format parsing in
bpf-prog, so the kernel code can keep relative stable.

A new kexec_file_ops is implementation, named pe_image_ops.
It takes care of the file data handling process, which allows to unfold the PE
file, e.g. a vmlinuz.efi embeded in UKI's .linux section.

There are some place holder function in this patch. (They will take
effect after the introduction of kexec bpf light skeleton and bpf
helpers). Overall the parsing progress is a pipeline, the current
bpf-prog parser is attached to bpf_handle_pefile(), and detatched at the
end of the current stage 'disarm_bpf_prog()' the current parsed result
by the current bpf-prog will be buffered in kernel 'prepare_nested_pe()'
, and deliver to the next stage.  For each stage, the bpf bytecode is
stored in the '.bpf' section of the PE file.

Signed-off-by: Pingfan Liu <piliu@redhat.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: Eric Biederman <ebiederm@xmission.com>
To: kexec@lists.infradead.org
---
 include/linux/kexec.h   |   1 +
 kernel/Kconfig.kexec    |   8 +
 kernel/Makefile         |   1 +
 kernel/kexec_pe_image.c | 338 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 348 insertions(+)
 create mode 100644 kernel/kexec_pe_image.c

diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index 26398b269ac29..bca8136dcf1fd 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -392,6 +392,7 @@ static inline int machine_kexec_post_load(struct kimage *image) { return 0; }
 
 extern struct kimage *kexec_image;
 extern struct kimage *kexec_crash_image;
+extern const struct kexec_file_ops pe_image_ops;
 
 bool kexec_load_permitted(int kexec_image_type);
 
diff --git a/kernel/Kconfig.kexec b/kernel/Kconfig.kexec
index 4d111f8719516..686eb7cb96142 100644
--- a/kernel/Kconfig.kexec
+++ b/kernel/Kconfig.kexec
@@ -47,6 +47,14 @@ config KEXEC_FILE
 	  for kernel and initramfs as opposed to list of segments as
 	  accepted by kexec system call.
 
+config KEXEC_PE_IMAGE
+	bool "Enable parsing UEFI PE file through kexec file based system call"
+	depends on KEXEC_FILE
+	depends on DEBUG_INFO_BTF && BPF_SYSCALL
+	help
+	  This option makes the kexec_file_load() syscall cooperates with bpf-prog
+	  to parse PE format file
+
 config KEXEC_SIG
 	bool "Verify kernel signature during kexec_file_load() syscall"
 	depends on ARCH_SUPPORTS_KEXEC_SIG
diff --git a/kernel/Makefile b/kernel/Makefile
index 434929de17ef2..ab82d73d8ce81 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -79,6 +79,7 @@ obj-$(CONFIG_KEXEC_CORE) += kexec_core.o
 obj-$(CONFIG_CRASH_DUMP) += crash_core.o
 obj-$(CONFIG_KEXEC) += kexec.o
 obj-$(CONFIG_KEXEC_FILE) += kexec_file.o
+obj-$(CONFIG_KEXEC_PE_IMAGE) += kexec_pe_image.o
 obj-$(CONFIG_KEXEC_ELF) += kexec_elf.o
 obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o
 obj-$(CONFIG_COMPAT) += compat.o
diff --git a/kernel/kexec_pe_image.c b/kernel/kexec_pe_image.c
new file mode 100644
index 0000000000000..accf6b0f02e39
--- /dev/null
+++ b/kernel/kexec_pe_image.c
@@ -0,0 +1,338 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kexec PE image loader
+
+ * Copyright (C) 2025 Red Hat, Inc
+ */
+
+#define pr_fmt(fmt)	"kexec_file(Image): " fmt
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/kexec.h>
+#include <linux/pe.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+#include <asm/cpufeature.h>
+#include <asm/image.h>
+#include <asm/memory.h>
+
+
+static LIST_HEAD(phase_head);
+
+struct parsed_phase {
+	struct list_head head;
+	struct list_head res_head;
+};
+
+static struct parsed_phase *cur_phase;
+
+static char *kexec_res_names[3] = {"kernel", "initrd", "cmdline"};
+
+struct kexec_res {
+	struct list_head node;
+	char *name;
+	char *buf;
+	int size;
+	bool kmalloc;
+	bool deferred_free;
+};
+
+static struct parsed_phase *alloc_new_phase(void)
+{
+	struct parsed_phase *phase = kzalloc(sizeof(struct parsed_phase), GFP_KERNEL);
+
+	INIT_LIST_HEAD(&phase->head);
+	INIT_LIST_HEAD(&phase->res_head);
+	list_add_tail(&phase->head, &phase_head);
+
+	return phase;
+}
+
+static bool is_valid_pe(const char *kernel_buf, unsigned long kernel_len)
+{
+	struct mz_hdr *mz;
+	struct pe_hdr *pe;
+
+	if (!kernel_buf)
+		return false;
+	mz = (struct mz_hdr *)kernel_buf;
+	if (mz->magic != MZ_MAGIC)
+		return false;
+	pe = (struct pe_hdr *)(kernel_buf + mz->peaddr);
+	if (pe->magic != PE_MAGIC)
+		return false;
+	if (pe->opt_hdr_size == 0) {
+		pr_err("optional header is missing\n");
+		return false;
+	}
+
+	return true;
+}
+
+static bool is_valid_format(const char *kernel_buf, unsigned long kernel_len)
+{
+	return is_valid_pe(kernel_buf, kernel_len);
+}
+
+/*
+ * The UEFI Terse Executable (TE) image has MZ header.
+ */
+static int pe_image_probe(const char *kernel_buf, unsigned long kernel_len)
+{
+	return is_valid_pe(kernel_buf, kernel_len) ? 0 : -1;
+}
+
+static int get_pe_section(char *file_buf, const char *sect_name,
+		char **sect_start, unsigned long *sect_sz)
+{
+	struct pe_hdr *pe_hdr;
+	struct pe32plus_opt_hdr *opt_hdr;
+	struct section_header *sect_hdr;
+	int section_nr, i;
+	struct mz_hdr *mz = (struct mz_hdr *)file_buf;
+
+	*sect_start = NULL;
+	*sect_sz = 0;
+	pe_hdr = (struct pe_hdr *)(file_buf + mz->peaddr);
+	section_nr = pe_hdr->sections;
+	opt_hdr = (struct pe32plus_opt_hdr *)(file_buf + mz->peaddr + sizeof(struct pe_hdr));
+	sect_hdr = (struct section_header *)((char *)opt_hdr + pe_hdr->opt_hdr_size);
+
+	for (i = 0; i < section_nr; i++) {
+		if (strcmp(sect_hdr->name, sect_name) == 0) {
+			*sect_start = file_buf + sect_hdr->data_addr;
+			*sect_sz = sect_hdr->raw_data_size;
+			return 0;
+		}
+		sect_hdr++;
+	}
+
+	return -1;
+}
+
+static bool pe_has_bpf_section(char *file_buf, unsigned long pe_sz)
+{
+	char *sect_start = NULL;
+	unsigned long sect_sz = 0;
+	int ret;
+
+	ret = get_pe_section(file_buf, ".bpf", &sect_start, &sect_sz);
+	if (ret < 0)
+		return false;
+	return true;
+}
+
+/* Load a ELF */
+static int arm_bpf_prog(char *bpf_elf, unsigned long sz)
+{
+	return 0;
+}
+
+static void disarm_bpf_prog(void)
+{
+}
+
+/*
+ * In eBPF, functions can only pass up to five arguments through R1 to R5.
+ * If five arguments are not enough, considering parse_zboot(struct pt_regs *regs)
+ *
+ * optimize("O0") prevents inline, compiler constant propagation
+ */
+__attribute__((used, optimize("O0"))) void bpf_handle_pefile(char *image, int image_sz,
+			char *initrd, int initrd_sz, char *cmdline)
+{
+}
+
+__attribute__((used, optimize("O0"))) void bpf_post_handle_pefile(void)
+{
+}
+
+/*
+ * PE file may be nested and should be unfold one by one.
+ * Query 'kernel', 'initrd', 'cmdline' in cur_phase, as they are inputs for the
+ * next phase.
+ */
+static int prepare_nested_pe(char **kernel, unsigned long *kernel_len, char **initrd,
+		unsigned long *initrd_len, char **cmdline)
+{
+	struct kexec_res *res;
+	int ret = -1;
+
+	*kernel = NULL;
+	*kernel_len = 0;
+
+	list_for_each_entry(res, &cur_phase->res_head, node) {
+		if (res->name == kexec_res_names[0]) {
+			*kernel = res->buf;
+			*kernel_len = res->size;
+			ret = 0;
+		} else if (res->name == kexec_res_names[1]) {
+			*initrd = res->buf;
+			*initrd_len = res->size;
+		} else if (res->name == kexec_res_names[2]) {
+			*cmdline = res->buf;
+		}
+	}
+
+	return ret;
+}
+
+static void *pe_image_load(struct kimage *image,
+				char *kernel, unsigned long kernel_len,
+				char *initrd, unsigned long initrd_len,
+				char *cmdline, unsigned long cmdline_len)
+{
+	char *parsed_kernel = NULL;
+	unsigned long parsed_len;
+	char *linux_start, *initrd_start, *cmdline_start, *bpf_start;
+	unsigned long linux_sz, initrd_sz, cmdline_sz, bpf_sz;
+	struct parsed_phase *phase, *phase_tmp;
+	struct kexec_res *res, *res_tmp;
+	void *ldata;
+	int ret;
+
+	linux_start = kernel;
+	linux_sz = kernel_len;
+	initrd_start = initrd;
+	initrd_sz = initrd_len;
+	cmdline_start = cmdline;
+	cmdline_sz = cmdline_len;
+
+	while(is_valid_format(linux_start, linux_sz) &&
+	      pe_has_bpf_section(linux_start, linux_sz)) {
+
+		get_pe_section(linux_start, ".bpf", &bpf_start, &bpf_sz);
+		if (!!bpf_sz) {
+			/* load and attach bpf-prog */
+			ret = arm_bpf_prog(bpf_start, bpf_sz);
+			if (ret) {
+				pr_err("Fail to load .bpf section\n");
+				goto err;
+			}
+		}
+		cur_phase = alloc_new_phase();
+		/*
+		 * bpf-prog fentry, which handle above buffers, and
+		 * bpf_carrier_helper() fills each phase
+		 */
+		bpf_handle_pefile(linux_start, linux_sz, initrd_start, initrd_sz,
+					cmdline_start);
+
+		prepare_nested_pe(&linux_start, &linux_sz, &initrd_start,
+					&initrd_sz, &cmdline_start);
+		/* bpf-prog fentry */
+		bpf_post_handle_pefile();
+		/*
+		 * detach the current bpf-prog from their attachment points.
+		 * It also a point to free any registered interim resource.
+		 * Any resource except attached to phase is interim.
+		 */
+		disarm_bpf_prog();
+	}
+
+	/* the rear of parsed phase contains the result */
+	list_for_each_entry_reverse(phase, &phase_head, head) {
+		if (initrd != NULL && cmdline != NULL && parsed_kernel != NULL)
+			break;
+		list_for_each_entry(res, &phase->res_head, node) {
+			if (!strcmp(res->name, "kernel") && !parsed_kernel) {
+				parsed_kernel = res->buf;
+				parsed_len = res->size;
+				res->deferred_free = true;
+			} else if (!strcmp(res->name, "initrd") && !initrd) {
+				initrd = res->buf;
+				initrd_len = res->size;
+				res->deferred_free = true;
+			} else if (!strcmp(res->name, "cmdline") && !cmdline) {
+				cmdline = res->buf;
+				cmdline_len = res->size;
+				res->deferred_free = true;
+			}
+		}
+
+	}
+
+	if (initrd == NULL || cmdline == NULL || parsed_kernel == NULL) {
+		char *c, buf[64];
+
+		c = buf;
+		if (parsed_kernel == NULL) {
+			strcpy(c, "kernel ");
+			c += strlen("kernel ");
+		}
+		if (initrd == NULL) {
+			strcpy(c, "initrd ");
+			c += strlen("initrd ");
+		}
+		if (cmdline == NULL) {
+			strcpy(c, "cmdline ");
+			c += strlen("cmdline ");
+		}
+		c = '\0';
+		pr_err("Can not extract data for %s", buf);
+		ret = -EINVAL;
+		goto err;
+	}
+	/*
+	 * image's kernel_buf, initrd_buf, cmdline_buf are set. Now they should
+	 * be updated to the new content.
+	 */
+	if (image->kernel_buf != parsed_kernel) {
+		vfree(image->kernel_buf);
+		image->kernel_buf = parsed_kernel;
+		image->kernel_buf_len = parsed_len;
+	}
+	if (image->initrd_buf != initrd) {
+		vfree(image->initrd_buf);
+		image->initrd_buf = initrd;
+		image->initrd_buf_len = initrd_len;
+	}
+	if (image->cmdline_buf != cmdline) {
+		kfree(image->cmdline_buf);
+		image->cmdline_buf = cmdline;
+		image->cmdline_buf_len = cmdline_len;
+	}
+	ret = arch_kexec_kernel_image_probe(image, image->kernel_buf,
+					    image->kernel_buf_len);
+	if (ret) {
+		pr_err("Fail to find suitable image loader\n");
+		goto err;
+	}
+	ldata = kexec_image_load_default(image);
+	if (IS_ERR(ldata)) {
+		ret = PTR_ERR(ldata);
+		goto err;
+	}
+	image->image_loader_data = ldata;
+
+err:
+	list_for_each_entry_safe(phase, phase_tmp, &phase_head, head) {
+		list_for_each_entry_safe(res, res_tmp, &phase->res_head, node) {
+			list_del(&res->node);
+			/* defer to kimage_file_post_load_cleanup() */
+			if (!res->deferred_free) {
+				if (res->kmalloc)
+					kfree(res->buf);
+				else
+					vfree(res->buf);
+			}
+			kfree(res);
+		}
+		list_del(&phase->head);
+		kfree(phase);
+	}
+
+	return ERR_PTR(ret);
+}
+
+const struct kexec_file_ops kexec_pe_image_ops = {
+	.probe = pe_image_probe,
+	.load = pe_image_load,
+#ifdef CONFIG_KEXEC_IMAGE_VERIFY_SIG
+	.verify_sig = kexec_kernel_verify_pe_sig,
+#endif
+};
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFCv2 3/7] lib/decompress: Keep decompressor when CONFIG_KEXEC_PE_IMAGE
  2025-04-29  4:12 [RFCv2 0/7] kexec: Use BPF lskel to enable kexec to load PE format boot image Pingfan Liu
  2025-04-29  4:12 ` [RFCv2 1/7] kexec_file: Make kexec_image_load_default global visible Pingfan Liu
  2025-04-29  4:12 ` [RFCv2 2/7] kexec: Introduce kexec_pe_image to parse and load PE file Pingfan Liu
@ 2025-04-29  4:12 ` Pingfan Liu
  2025-04-29  4:12 ` [RFCv2 4/7] bpf/kexec: Introduce three bpf kfunc for kexec Pingfan Liu
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Pingfan Liu @ 2025-04-29  4:12 UTC (permalink / raw)
  To: linux-kernel
  Cc: Pingfan Liu, Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Jeremy Linton, Catalin Marinas, Will Deacon,
	Ard Biesheuvel, Simon Horman, Gerd Hoffmann, Vitaly Kuznetsov,
	Philipp Rudo, Viktor Malik, Jan Hendrik Farr, Baoquan He,
	Dave Young, Eric Biederman, Andrew Morton, kexec, bpf

The KEXE PE format parser needs the kernel built-in decompressor to
decompress the kernel image. So moving the decompressor out of __init
sections.

Signed-off-by: Pingfan Liu <piliu@redhat.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
To: linux-kernel@vger.kernel.org
---
 include/linux/decompress/mm.h | 7 +++++++
 lib/decompress.c              | 6 +++---
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/include/linux/decompress/mm.h b/include/linux/decompress/mm.h
index ac862422df158..e8948260e2bbe 100644
--- a/include/linux/decompress/mm.h
+++ b/include/linux/decompress/mm.h
@@ -92,7 +92,14 @@ MALLOC_VISIBLE void free(void *where)
 #define large_malloc(a) vmalloc(a)
 #define large_free(a) vfree(a)
 
+#ifdef CONFIG_KEXEC_PE_IMAGE
+#define INIT
+#define INITCONST
+#else
 #define INIT __init
+#define INITCONST __initconst
+#endif
+
 #define STATIC
 
 #include <linux/init.h>
diff --git a/lib/decompress.c b/lib/decompress.c
index ab3fc90ffc646..3d5b6304bb0f1 100644
--- a/lib/decompress.c
+++ b/lib/decompress.c
@@ -6,7 +6,7 @@
  */
 
 #include <linux/decompress/generic.h>
-
+#include <linux/decompress/mm.h>
 #include <linux/decompress/bunzip2.h>
 #include <linux/decompress/unlzma.h>
 #include <linux/decompress/unxz.h>
@@ -48,7 +48,7 @@ struct compress_format {
 	decompress_fn decompressor;
 };
 
-static const struct compress_format compressed_formats[] __initconst = {
+static const struct compress_format compressed_formats[] INITCONST = {
 	{ {0x1f, 0x8b}, "gzip", gunzip },
 	{ {0x1f, 0x9e}, "gzip", gunzip },
 	{ {0x42, 0x5a}, "bzip2", bunzip2 },
@@ -60,7 +60,7 @@ static const struct compress_format compressed_formats[] __initconst = {
 	{ {0, 0}, NULL, NULL }
 };
 
-decompress_fn __init decompress_method(const unsigned char *inbuf, long len,
+decompress_fn INIT decompress_method(const unsigned char *inbuf, long len,
 				const char **name)
 {
 	const struct compress_format *cf;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFCv2 4/7] bpf/kexec: Introduce three bpf kfunc for kexec
  2025-04-29  4:12 [RFCv2 0/7] kexec: Use BPF lskel to enable kexec to load PE format boot image Pingfan Liu
                   ` (2 preceding siblings ...)
  2025-04-29  4:12 ` [RFCv2 3/7] lib/decompress: Keep decompressor when CONFIG_KEXEC_PE_IMAGE Pingfan Liu
@ 2025-04-29  4:12 ` Pingfan Liu
  2025-04-30  0:03   ` Alexei Starovoitov
  2025-04-29  4:12 ` [RFCv2 5/7] kexec: Introduce a bpf-prog lskel to parse PE file Pingfan Liu
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Pingfan Liu @ 2025-04-29  4:12 UTC (permalink / raw)
  To: bpf, kexec
  Cc: Pingfan Liu, Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Jeremy Linton, Catalin Marinas, Will Deacon,
	Ard Biesheuvel, Simon Horman, Gerd Hoffmann, Vitaly Kuznetsov,
	Philipp Rudo, Viktor Malik, Jan Hendrik Farr, Baoquan He,
	Dave Young, Eric Biederman, Andrew Morton, KP Singh,
	Stanislav Fomichev, Hao Luo, Jiri Olsa

This patch introduces three kfunc dedicated for kexec_file_load.

In the case of kexec, kexec_trylock() ensures no concurrent, which
relieves the kexec bpf kfunc design. (Maybe later, a dedicate
BPF_PROG_TYPE_KEXEC to limit their use case to improve the safety)

bpf_kexec_decompress(): It creates a bridge to the kernel decompressor,
avoiding the need to reimplement the lib/decompress_* in bpf-programs.

bpf_kexec_result_release(): It releases the resource when bpf-prog is
done with that.

bpf_kexec_carrier(): The common data flow in bpf scheme is from kernel
to bpf-prog.  In the case of kexec_file_load, the kexec component needs
to buffer the parsed result by bpf-prog (opposite the usual direction)
to the next stage parsing. bpf_kexec_carrier() makes the opposite data
flow possible. A bpf-prog can publish the parsed payload address to the
kernel, and the latter can copy them for future use.

Signed-off-by: Pingfan Liu <piliu@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Andrii Nakryiko <andrii@kernel.org>
Cc: Martin KaFai Lau <martin.lau@linux.dev>
Cc: Eduard Zingerman <eddyz87@gmail.com>
Cc: Song Liu <song@kernel.org>
Cc: Yonghong Song <yonghong.song@linux.dev>
Cc: John Fastabend <john.fastabend@gmail.com>
Cc: KP Singh <kpsingh@kernel.org>
Cc: Stanislav Fomichev <sdf@fomichev.me>
Cc: Hao Luo <haoluo@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Baoquan He <bhe@redhat.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: Eric Biederman <ebiederm@xmission.com>
To: bpf@vger.kernel.org
To: kexec@lists.infradead.org
---
 kernel/kexec_pe_image.c | 194 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 194 insertions(+)

diff --git a/kernel/kexec_pe_image.c b/kernel/kexec_pe_image.c
index accf6b0f02e39..610bb134f5e34 100644
--- a/kernel/kexec_pe_image.c
+++ b/kernel/kexec_pe_image.c
@@ -15,6 +15,9 @@
 #include <linux/kexec.h>
 #include <linux/pe.h>
 #include <linux/string.h>
+#include <linux/bpf.h>
+#include <linux/filter.h>
+#include <linux/decompress/generic.h>
 #include <asm/byteorder.h>
 #include <asm/cpufeature.h>
 #include <asm/image.h>
@@ -52,6 +55,186 @@ static struct parsed_phase *alloc_new_phase(void)
 	return phase;
 }
 
+struct mem_range_result {
+	refcount_t usage;
+	/*
+	 * Pointer to a kernel space, which is written by kfunc and read by
+	 * bpf-prog. Hence kfunc guarantees its validation.
+	 */
+	char *buf;
+	uint32_t size;     // Size of decompressed data
+	int status;        // Status code (0 for success)
+};
+
+#define MAX_KEXEC_RES_SIZE	(1 << 29)
+
+BTF_KFUNCS_START(bpf_kexec_ids)
+BTF_ID_FLAGS(func, bpf_kexec_carrier, KF_TRUSTED_ARGS)
+BTF_ID_FLAGS(func, bpf_kexec_decompress, KF_TRUSTED_ARGS | KF_ACQUIRE)
+BTF_ID_FLAGS(func, bpf_kexec_result_release, KF_RELEASE)
+BTF_KFUNCS_END(bpf_kexec_ids)
+
+static const struct btf_kfunc_id_set kexec_kfunc_set = {
+	.owner = THIS_MODULE,
+	.set = &bpf_kexec_ids,
+};
+
+/*
+ * Copy the partial decompressed content in [buf, buf + len) to dst.
+ * If the dst size is beyond the capacity, return 0 to indicate the
+ * decompress method that something is wrong.
+ */
+//to do
+static long flush_buffer(void *buf, unsigned long len)
+{
+
+	//return len to indicate everything goest smoothly
+	return 0;
+}
+
+
+__bpf_kfunc_start_defs();
+
+/*
+ * @name should be one of : kernel, initrd, cmdline
+ */
+__bpf_kfunc int bpf_kexec_carrier(const char *name, struct mem_range_result *r)
+{
+	struct kexec_res *res;
+	int ret = 0;
+
+	if (!r) {
+		pr_err("%s, receive invalid range\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!r || !name)
+		return -EINVAL;
+	if (r->size == 0 || r->size > MAX_KEXEC_RES_SIZE) {
+		pr_err("Invalid resource size: 0x%x\n", r->size);
+		return -EINVAL;
+	}
+
+	res = kzalloc(sizeof(struct kexec_res), GFP_KERNEL);
+	if (!res)
+		return -ENOMEM;
+
+	for (int i = 0; i < ARRAY_SIZE(kexec_res_names); i++) {
+		if (!strcmp(kexec_res_names[i], name))
+			res->name = kexec_res_names[i];
+	}
+
+	if (res->name == NULL) {
+		pr_err("Invalid resource name: %s, should be 'kernel', 'initrd', 'cmdline'\n", name);
+		kfree(res);
+		return -EINVAL;
+	}
+
+	res->buf = vmalloc(r->size);
+	if (!res->buf) {
+		kfree(res);
+		return -ENOMEM;
+	}
+	ret = copy_from_kernel_nofault(res->buf, r->buf, r->size);
+	if (unlikely(ret < 0)) {
+		kfree(res->buf);
+		kfree(res);
+		return -EINVAL;
+	}
+	res->size = r->size;
+
+	INIT_LIST_HEAD(&res->node);
+	list_add_tail(&res->node, &cur_phase->res_head);
+	return 0;
+}
+
+__bpf_kfunc struct mem_range_result *bpf_kexec_decompress(char *image_gz_payload, int image_gz_sz,
+			unsigned int expected_decompressed_sz)
+{
+	decompress_fn decompressor;
+	//todo, use flush to cap the memory size used by decompression
+	long (*flush)(void*, unsigned long) = NULL;
+	struct mem_range_result *range;
+	const char *name;
+	void *output_buf;
+	char *input_buf;
+	int ret;
+
+	range = kmalloc(sizeof(struct mem_range_result), GFP_KERNEL);
+	if (!range) {
+		pr_err("fail to allocate mem_range_result\n");
+		return NULL;
+	}
+	refcount_set(&range->usage, 1);
+
+	input_buf = vmalloc(image_gz_sz);
+	if (!input_buf) {
+		pr_err("fail to allocate input buffer\n");
+		kfree(range);
+		return NULL;
+	}
+
+	ret = copy_from_kernel_nofault(input_buf, image_gz_payload, image_gz_sz);
+	if (ret < 0) {
+		pr_err("Error when copying from 0x%px, size:0x%x\n",
+				image_gz_payload, image_gz_sz);
+		kfree(range);
+		vfree(input_buf);
+		return NULL;
+	}
+
+	output_buf = vmalloc(expected_decompressed_sz);
+	if (!output_buf) {
+		pr_err("fail to allocate output buffer\n");
+		kfree(range);
+		vfree(input_buf);
+		return NULL;
+	}
+
+	decompressor = decompress_method(input_buf, image_gz_sz, &name);
+	if (!decompressor) {
+		pr_err("Can not find decompress method\n");
+		kfree(range);
+		vfree(input_buf);
+		vfree(output_buf);
+		return NULL;
+	}
+	//to do, use flush
+	ret = decompressor(image_gz_payload, image_gz_sz, NULL, NULL,
+				output_buf, NULL, NULL);
+
+	/* Update the range map */
+	if (ret == 0) {
+		range->buf = output_buf;
+		range->size = expected_decompressed_sz;
+		range->status = 0;
+	} else {
+		pr_err("Decompress error\n");
+		vfree(output_buf);
+		kfree(range);
+		return NULL;
+	}
+	pr_info("%s, return range 0x%lx\n", __func__, range);
+	return range;
+}
+
+__bpf_kfunc int bpf_kexec_result_release(struct mem_range_result *result)
+{
+	if (!result) {
+		pr_err("%s, receive invalid range\n", __func__);
+		return -EINVAL;
+	}
+
+	if (refcount_dec_and_test(&result->usage)) {
+		vfree(result->buf);
+		kfree(result);
+	}
+
+	return 0;
+}
+
+__bpf_kfunc_end_defs();
+
 static bool is_valid_pe(const char *kernel_buf, unsigned long kernel_len)
 {
 	struct mz_hdr *mz;
@@ -336,3 +519,14 @@ const struct kexec_file_ops kexec_pe_image_ops = {
 	.verify_sig = kexec_kernel_verify_pe_sig,
 #endif
 };
+
+static int __init bpf_kfunc_init(void)
+{
+	int ret;
+
+	ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &kexec_kfunc_set);
+	if (!!ret)
+		pr_err("Fail to register btf for kexec_kfunc_set\n");
+	return ret;
+}
+late_initcall(bpf_kfunc_init);
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFCv2 5/7] kexec: Introduce a bpf-prog lskel to parse PE file
  2025-04-29  4:12 [RFCv2 0/7] kexec: Use BPF lskel to enable kexec to load PE format boot image Pingfan Liu
                   ` (3 preceding siblings ...)
  2025-04-29  4:12 ` [RFCv2 4/7] bpf/kexec: Introduce three bpf kfunc for kexec Pingfan Liu
@ 2025-04-29  4:12 ` Pingfan Liu
  2025-04-29  4:12 ` [RFCv2 6/7] kexec: Integrate bpf light skeleton to load zboot image Pingfan Liu
  2025-04-29  4:12 ` [RFCv2 7/7] arm64/kexec: Add PE image format support Pingfan Liu
  6 siblings, 0 replies; 13+ messages in thread
From: Pingfan Liu @ 2025-04-29  4:12 UTC (permalink / raw)
  To: kexec
  Cc: Pingfan Liu, Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Jeremy Linton, Catalin Marinas, Will Deacon,
	Ard Biesheuvel, Simon Horman, Gerd Hoffmann, Vitaly Kuznetsov,
	Philipp Rudo, Viktor Malik, Jan Hendrik Farr, Baoquan He,
	Dave Young, Eric Biederman, Andrew Morton, bpf

This Makefile is not invoked by the Kbuild system. It is invoked
separatedly when kexec_pe_parser_bpf.c is changed and kexec_pe_parser_bpf.lskel.h
should be re-generated by the command "bpftool gen skeleton -L kexec_pe_parser_bpf.o".

kexec_pe_parser_bpf.lskel.h is used directly by the kernel kexec code in
later patch.

As exposed in kexec_pe_parser_bpf.lskel.h, the interface between
bpf-prog and the kernel are constituted by:

four maps:
                struct bpf_map_desc ringbuf_1;
                struct bpf_map_desc ringbuf_2;
                struct bpf_map_desc ringbuf_3;
                struct bpf_map_desc ringbuf_4;
four sections:
                struct bpf_map_desc rodata;
                struct bpf_map_desc data;
                struct bpf_map_desc bss;
                struct bpf_map_desc rodata_str1_1;

two progs:
        SEC("fentry/bpf_handle_pefile")
        SEC("fentry/bpf_post_handle_pefile")

They are fixed and provided for all kinds of bpf-prog which interacts
with the kexec kernel component.

Signed-off-by: Pingfan Liu <piliu@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Baoquan He <bhe@redhat.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: bpf@vger.kernel.org
To: kexec@lists.infradead.org
---
 kernel/kexec_bpf/Makefile                    |  57 +++
 kernel/kexec_bpf/kexec_pe_parser_bpf.c       |  66 +++
 kernel/kexec_bpf/kexec_pe_parser_bpf.lskel.h | 429 +++++++++++++++++++
 3 files changed, 552 insertions(+)
 create mode 100644 kernel/kexec_bpf/Makefile
 create mode 100644 kernel/kexec_bpf/kexec_pe_parser_bpf.c
 create mode 100644 kernel/kexec_bpf/kexec_pe_parser_bpf.lskel.h

diff --git a/kernel/kexec_bpf/Makefile b/kernel/kexec_bpf/Makefile
new file mode 100644
index 0000000000000..b772e78464f48
--- /dev/null
+++ b/kernel/kexec_bpf/Makefile
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: GPL-2.0
+OUTPUT := .output
+CLANG ?= clang
+LLC ?= llc
+LLVM_STRIP ?= llvm-strip
+DEFAULT_BPFTOOL := $(OUTPUT)/sbin/bpftool
+BPFTOOL ?= $(DEFAULT_BPFTOOL)
+LIBBPF_SRC := $(abspath ../../tools/lib/bpf)
+BPFOBJ := $(OUTPUT)/libbpf.a
+BPF_INCLUDE := $(OUTPUT)
+INCLUDES := -I$(OUTPUT) -I$(BPF_INCLUDE) -I$(abspath ../../tools/lib)        \
+       -I$(abspath ../../tools/include/uapi)
+CFLAGS := -g -Wall
+
+abs_out := $(abspath $(OUTPUT))
+ifeq ($(V),1)
+Q =
+msg =
+else
+Q = @
+msg = @printf '  %-8s %s%s\n' "$(1)" "$(notdir $(2))" "$(if $(3), $(3))";
+MAKEFLAGS += --no-print-directory
+submake_extras := feature_display=0
+endif
+
+.DELETE_ON_ERROR:
+
+.PHONY: all clean
+
+all: kexec_pe_parser_bpf.lskel.h
+
+clean:
+	$(call msg,CLEAN)
+	$(Q)rm -rf $(OUTPUT) kexec_pe_parser_bpf.lskel.h
+
+kexec_pe_parser_bpf.lskel.h: $(OUTPUT)/kexec_pe_parser_bpf.o | $(BPFTOOL)
+	$(call msg,GEN-SKEL,$@)
+	$(Q)$(BPFTOOL) gen skeleton -L $< > $@
+
+
+$(OUTPUT)/kexec_pe_parser_bpf.o: kexec_pe_parser_bpf.c $(BPFOBJ) | $(OUTPUT)
+	$(call msg,BPF,$@)
+	$(Q)$(CLANG) -g -O2 -target bpf $(INCLUDES)			      \
+		 -c $(filter %.c,$^) -o $@ &&				      \
+	$(LLVM_STRIP) -g $@
+
+$(OUTPUT):
+	$(call msg,MKDIR,$@)
+	$(Q)mkdir -p $(OUTPUT)
+
+$(BPFOBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(OUTPUT)
+	$(Q)$(MAKE) $(submake_extras) -C $(LIBBPF_SRC)			       \
+		    OUTPUT=$(abspath $(dir $@))/ $(abspath $@)
+
+$(DEFAULT_BPFTOOL):
+	$(Q)$(MAKE) $(submake_extras) -C ../../tools/bpf/bpftool			      \
+		    prefix= OUTPUT=$(abs_out)/ DESTDIR=$(abs_out) install
diff --git a/kernel/kexec_bpf/kexec_pe_parser_bpf.c b/kernel/kexec_bpf/kexec_pe_parser_bpf.c
new file mode 100644
index 0000000000000..bbadcfa48ad1c
--- /dev/null
+++ b/kernel/kexec_bpf/kexec_pe_parser_bpf.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_core_read.h>
+#include <bpf/bpf_endian.h>
+#include <bpf/bpf_tracing.h>
+
+
+/* 1GB =  1^28 * sizeof(__uint) */
+#define MAX_BUF_SIZE	(1 << 28)
+/* 512MB is big enough to hold either kernel or initramfs */
+#define MAX_RECORD_SIZE	(1 << 27)
+
+#define KEXEC_RES_KERNEL_NAME "kernel"
+#define KEXEC_RES_INITRD_NAME "initrd"
+#define KEXEC_RES_CMDLINE_NAME "cmdline"
+
+/* ringbuf is safe since the user space has no write access to them */
+struct {
+	__uint(type, BPF_MAP_TYPE_RINGBUF);
+	__uint(max_entries, MAX_BUF_SIZE);
+} ringbuf_1 SEC(".maps");
+
+struct {
+	__uint(type, BPF_MAP_TYPE_RINGBUF);
+	__uint(max_entries, MAX_BUF_SIZE);
+} ringbuf_2 SEC(".maps");
+
+struct {
+	__uint(type, BPF_MAP_TYPE_RINGBUF);
+	__uint(max_entries, MAX_BUF_SIZE);
+} ringbuf_3 SEC(".maps");
+
+struct {
+	__uint(type, BPF_MAP_TYPE_RINGBUF);
+	__uint(max_entries, MAX_BUF_SIZE);
+} ringbuf_4 SEC(".maps");
+
+char LICENSE[] SEC("license") = "GPL";
+
+/*
+ * This function ensures that the sections .rodata, .data .bss and .rodata.str1.1
+ * are created for a bpf prog.
+ */
+__attribute__((used)) static int dummy(void)
+{
+	static const char res_kernel[16] __attribute__((used, section(".rodata"))) = KEXEC_RES_KERNEL_NAME;
+	static char local_name[16] __attribute__((used, section(".data"))) = KEXEC_RES_CMDLINE_NAME;
+	static char res_cmdline[16] __attribute__((used, section(".bss")));
+
+	__builtin_memcpy(local_name, KEXEC_RES_INITRD_NAME, 16);
+	return __builtin_memcmp(local_name, res_kernel, 4);
+}
+
+SEC("fentry/bpf_handle_pefile")
+__attribute__((used)) int BPF_PROG(parse_pe, char *image_buf, unsigned int image_sz, char *initrd,
+		unsigned int initrd_sz, char *cmdline)
+{
+	return 0;
+}
+
+SEC("fentry/bpf_post_handle_pefile")
+__attribute__((used)) int BPF_PROG(post_parse_pe, char *image_buf, int buf_sz)
+{
+	return 0;
+}
diff --git a/kernel/kexec_bpf/kexec_pe_parser_bpf.lskel.h b/kernel/kexec_bpf/kexec_pe_parser_bpf.lskel.h
new file mode 100644
index 0000000000000..d8a181609c32e
--- /dev/null
+++ b/kernel/kexec_bpf/kexec_pe_parser_bpf.lskel.h
@@ -0,0 +1,429 @@
+/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
+/* THIS FILE IS AUTOGENERATED BY BPFTOOL! */
+#ifndef __KEXEC_PE_PARSER_BPF_SKEL_H__
+#define __KEXEC_PE_PARSER_BPF_SKEL_H__
+
+#include <bpf/skel_internal.h>
+
+struct kexec_pe_parser_bpf {
+	struct bpf_loader_ctx ctx;
+	struct {
+		struct bpf_map_desc ringbuf_1;
+		struct bpf_map_desc ringbuf_2;
+		struct bpf_map_desc ringbuf_3;
+		struct bpf_map_desc ringbuf_4;
+		struct bpf_map_desc rodata;
+		struct bpf_map_desc data;
+		struct bpf_map_desc bss;
+		struct bpf_map_desc rodata_str1_1;
+	} maps;
+	struct {
+		struct bpf_prog_desc parse_pe;
+		struct bpf_prog_desc post_parse_pe;
+	} progs;
+	struct {
+		int parse_pe_fd;
+		int post_parse_pe_fd;
+	} links;
+};
+
+static inline int
+kexec_pe_parser_bpf__parse_pe__attach(struct kexec_pe_parser_bpf *skel)
+{
+	int prog_fd = skel->progs.parse_pe.prog_fd;
+	int fd = skel_raw_tracepoint_open(NULL, prog_fd);
+
+	if (fd > 0)
+		skel->links.parse_pe_fd = fd;
+	return fd;
+}
+
+static inline int
+kexec_pe_parser_bpf__post_parse_pe__attach(struct kexec_pe_parser_bpf *skel)
+{
+	int prog_fd = skel->progs.post_parse_pe.prog_fd;
+	int fd = skel_raw_tracepoint_open(NULL, prog_fd);
+
+	if (fd > 0)
+		skel->links.post_parse_pe_fd = fd;
+	return fd;
+}
+
+static inline int
+kexec_pe_parser_bpf__attach(struct kexec_pe_parser_bpf *skel)
+{
+	int ret = 0;
+
+	ret = ret < 0 ? ret : kexec_pe_parser_bpf__parse_pe__attach(skel);
+	ret = ret < 0 ? ret : kexec_pe_parser_bpf__post_parse_pe__attach(skel);
+	return ret < 0 ? ret : 0;
+}
+
+static inline void
+kexec_pe_parser_bpf__detach(struct kexec_pe_parser_bpf *skel)
+{
+	skel_closenz(skel->links.parse_pe_fd);
+	skel_closenz(skel->links.post_parse_pe_fd);
+}
+static void
+kexec_pe_parser_bpf__destroy(struct kexec_pe_parser_bpf *skel)
+{
+	if (!skel)
+		return;
+	kexec_pe_parser_bpf__detach(skel);
+	skel_closenz(skel->progs.parse_pe.prog_fd);
+	skel_closenz(skel->progs.post_parse_pe.prog_fd);
+	skel_closenz(skel->maps.ringbuf_1.map_fd);
+	skel_closenz(skel->maps.ringbuf_2.map_fd);
+	skel_closenz(skel->maps.ringbuf_3.map_fd);
+	skel_closenz(skel->maps.ringbuf_4.map_fd);
+	skel_closenz(skel->maps.rodata.map_fd);
+	skel_closenz(skel->maps.data.map_fd);
+	skel_closenz(skel->maps.bss.map_fd);
+	skel_closenz(skel->maps.rodata_str1_1.map_fd);
+	skel_free(skel);
+}
+static inline struct kexec_pe_parser_bpf *
+kexec_pe_parser_bpf__open(void)
+{
+	struct kexec_pe_parser_bpf *skel;
+
+	skel = skel_alloc(sizeof(*skel));
+	if (!skel)
+		goto cleanup;
+	skel->ctx.sz = (void *)&skel->links - (void *)skel;
+	return skel;
+cleanup:
+	kexec_pe_parser_bpf__destroy(skel);
+	return NULL;
+}
+
+static inline int
+kexec_pe_parser_bpf__load(struct kexec_pe_parser_bpf *skel)
+{
+	struct bpf_load_and_run_opts opts = {};
+	int err;
+	static const char opts_data[] __attribute__((__aligned__(8))) = "\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9f\xeb\x01\0\
+\x18\0\0\0\0\0\0\0\x04\x03\0\0\x04\x03\0\0\x79\x02\0\0\0\0\0\0\0\0\0\x02\x03\0\
+\0\0\x01\0\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\x01\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\
+\0\0\x04\0\0\0\x1b\0\0\0\x05\0\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\0\0\0\0\0\0\0\0\
+\x02\x06\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\0\0\0\x10\0\0\0\0\
+\x02\0\0\x04\x10\0\0\0\x19\0\0\0\x01\0\0\0\0\0\0\0\x1e\0\0\0\x05\0\0\0\x40\0\0\
+\0\x2a\0\0\0\0\0\0\x0e\x07\0\0\0\x01\0\0\0\0\0\0\0\x02\0\0\x04\x10\0\0\0\x19\0\
+\0\0\x01\0\0\0\0\0\0\0\x1e\0\0\0\x05\0\0\0\x40\0\0\0\x34\0\0\0\0\0\0\x0e\x09\0\
+\0\0\x01\0\0\0\0\0\0\0\x02\0\0\x04\x10\0\0\0\x19\0\0\0\x01\0\0\0\0\0\0\0\x1e\0\
+\0\0\x05\0\0\0\x40\0\0\0\x3e\0\0\0\0\0\0\x0e\x0b\0\0\0\x01\0\0\0\0\0\0\0\x02\0\
+\0\x04\x10\0\0\0\x19\0\0\0\x01\0\0\0\0\0\0\0\x1e\0\0\0\x05\0\0\0\x40\0\0\0\x48\
+\0\0\0\0\0\0\x0e\x0d\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\x0d\x02\0\0\0\x52\0\0\0\0\0\
+\0\x0c\x0f\0\0\0\0\0\0\0\0\0\0\x02\x12\0\0\0\0\x01\0\0\0\0\0\x01\x08\0\0\0\x40\
+\0\0\0\0\0\0\0\x01\0\0\x0d\x02\0\0\0\x13\x01\0\0\x11\0\0\0\x17\x01\0\0\x01\0\0\
+\x0c\x13\0\0\0\0\0\0\0\x01\0\0\x0d\x02\0\0\0\x13\x01\0\0\x11\0\0\0\x9c\x01\0\0\
+\x01\0\0\x0c\x15\0\0\0\x17\x02\0\0\0\0\0\x01\x01\0\0\0\x08\0\0\x01\0\0\0\0\0\0\
+\0\x03\0\0\0\0\x17\0\0\0\x04\0\0\0\x04\0\0\0\x1c\x02\0\0\0\0\0\x0e\x18\0\0\0\
+\x01\0\0\0\0\0\0\0\0\0\0\x0a\x17\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x1a\0\0\0\x04\
+\0\0\0\x10\0\0\0\x24\x02\0\0\0\0\0\x0e\x1b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\
+\0\0\x17\0\0\0\x04\0\0\0\x10\0\0\0\x35\x02\0\0\0\0\0\x0e\x1d\0\0\0\0\0\0\0\x46\
+\x02\0\0\0\0\0\x0e\x1d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x17\0\0\0\x04\0\
+\0\0\x07\0\0\0\x58\x02\0\0\x01\0\0\x0f\x10\0\0\0\x1f\0\0\0\0\0\0\0\x10\0\0\0\
+\x5d\x02\0\0\x01\0\0\x0f\x10\0\0\0\x1e\0\0\0\0\0\0\0\x10\0\0\0\x63\x02\0\0\x04\
+\0\0\x0f\x40\0\0\0\x08\0\0\0\0\0\0\0\x10\0\0\0\x0a\0\0\0\x10\0\0\0\x10\0\0\0\
+\x0c\0\0\0\x20\0\0\0\x10\0\0\0\x0e\0\0\0\x30\0\0\0\x10\0\0\0\x69\x02\0\0\x01\0\
+\0\x0f\x10\0\0\0\x1c\0\0\0\0\0\0\0\x10\0\0\0\x71\x02\0\0\x01\0\0\x0f\x04\0\0\0\
+\x19\0\0\0\0\0\0\0\x04\0\0\0\0\x69\x6e\x74\0\x5f\x5f\x41\x52\x52\x41\x59\x5f\
+\x53\x49\x5a\x45\x5f\x54\x59\x50\x45\x5f\x5f\0\x74\x79\x70\x65\0\x6d\x61\x78\
+\x5f\x65\x6e\x74\x72\x69\x65\x73\0\x72\x69\x6e\x67\x62\x75\x66\x5f\x31\0\x72\
+\x69\x6e\x67\x62\x75\x66\x5f\x32\0\x72\x69\x6e\x67\x62\x75\x66\x5f\x33\0\x72\
+\x69\x6e\x67\x62\x75\x66\x5f\x34\0\x64\x75\x6d\x6d\x79\0\x2e\x74\x65\x78\x74\0\
+\x2f\x68\x6f\x6d\x65\x2f\x6c\x69\x6e\x75\x78\x2f\x6b\x65\x72\x6e\x65\x6c\x2f\
+\x6b\x65\x78\x65\x63\x5f\x62\x70\x66\x2f\x6b\x65\x78\x65\x63\x5f\x70\x65\x5f\
+\x70\x61\x72\x73\x65\x72\x5f\x62\x70\x66\x2e\x63\0\x09\x5f\x5f\x62\x75\x69\x6c\
+\x74\x69\x6e\x5f\x6d\x65\x6d\x63\x70\x79\x28\x6c\x6f\x63\x61\x6c\x5f\x6e\x61\
+\x6d\x65\x2c\x20\x4b\x45\x58\x45\x43\x5f\x52\x45\x53\x5f\x49\x4e\x49\x54\x52\
+\x44\x5f\x4e\x41\x4d\x45\x2c\x20\x31\x36\x29\x3b\0\x09\x72\x65\x74\x75\x72\x6e\
+\x20\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x5f\x6d\x65\x6d\x63\x6d\x70\x28\x6c\
+\x6f\x63\x61\x6c\x5f\x6e\x61\x6d\x65\x2c\x20\x72\x65\x73\x5f\x6b\x65\x72\x6e\
+\x65\x6c\x2c\x20\x34\x29\x3b\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x6c\x6f\x6e\
+\x67\x20\x6c\x6f\x6e\x67\0\x63\x74\x78\0\x70\x61\x72\x73\x65\x5f\x70\x65\0\x66\
+\x65\x6e\x74\x72\x79\x2f\x62\x70\x66\x5f\x68\x61\x6e\x64\x6c\x65\x5f\x70\x65\
+\x66\x69\x6c\x65\0\x5f\x5f\x61\x74\x74\x72\x69\x62\x75\x74\x65\x5f\x5f\x28\x28\
+\x75\x73\x65\x64\x29\x29\x20\x69\x6e\x74\x20\x42\x50\x46\x5f\x50\x52\x4f\x47\
+\x28\x70\x61\x72\x73\x65\x5f\x70\x65\x2c\x20\x63\x68\x61\x72\x20\x2a\x69\x6d\
+\x61\x67\x65\x5f\x62\x75\x66\x2c\x20\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\
+\x6e\x74\x20\x69\x6d\x61\x67\x65\x5f\x73\x7a\x2c\x20\x63\x68\x61\x72\x20\x2a\
+\x69\x6e\x69\x74\x72\x64\x2c\0\x70\x6f\x73\x74\x5f\x70\x61\x72\x73\x65\x5f\x70\
+\x65\0\x66\x65\x6e\x74\x72\x79\x2f\x62\x70\x66\x5f\x70\x6f\x73\x74\x5f\x68\x61\
+\x6e\x64\x6c\x65\x5f\x70\x65\x66\x69\x6c\x65\0\x5f\x5f\x61\x74\x74\x72\x69\x62\
+\x75\x74\x65\x5f\x5f\x28\x28\x75\x73\x65\x64\x29\x29\x20\x69\x6e\x74\x20\x42\
+\x50\x46\x5f\x50\x52\x4f\x47\x28\x70\x6f\x73\x74\x5f\x70\x61\x72\x73\x65\x5f\
+\x70\x65\x2c\x20\x63\x68\x61\x72\x20\x2a\x69\x6d\x61\x67\x65\x5f\x62\x75\x66\
+\x2c\x20\x69\x6e\x74\x20\x62\x75\x66\x5f\x73\x7a\x29\0\x63\x68\x61\x72\0\x4c\
+\x49\x43\x45\x4e\x53\x45\0\x64\x75\x6d\x6d\x79\x2e\x72\x65\x73\x5f\x6b\x65\x72\
+\x6e\x65\x6c\0\x64\x75\x6d\x6d\x79\x2e\x6c\x6f\x63\x61\x6c\x5f\x6e\x61\x6d\x65\
+\0\x64\x75\x6d\x6d\x79\x2e\x72\x65\x73\x5f\x63\x6d\x64\x6c\x69\x6e\x65\0\x2e\
+\x62\x73\x73\0\x2e\x64\x61\x74\x61\0\x2e\x6d\x61\x70\x73\0\x2e\x72\x6f\x64\x61\
+\x74\x61\0\x6c\x69\x63\x65\x6e\x73\x65\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x95\x05\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\
+\0\0\0\0\0\0\0\0\0\x72\x69\x6e\x67\x62\x75\x66\x5f\x31\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x10\0\0\0\0\0\0\0\0\0\0\0\0\x72\x69\x6e\x67\x62\x75\x66\x5f\x32\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1b\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\x10\0\0\0\0\0\0\0\0\0\0\0\0\x72\x69\x6e\x67\x62\x75\x66\x5f\x33\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1b\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\0\0\0\0\0\x72\x69\x6e\x67\x62\x75\x66\
+\x5f\x34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x02\0\0\0\x04\0\0\0\x10\0\0\0\x01\0\0\0\x80\0\0\0\0\0\0\0\0\0\0\0\x6b\x65\x78\
+\x65\x63\x5f\x70\x65\x2e\x72\x6f\x64\x61\x74\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\x24\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6b\x65\x72\x6e\x65\x6c\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\x02\0\0\0\x04\0\0\0\x10\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x6b\x65\x78\x65\x63\x5f\x70\x65\x2e\x64\x61\x74\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\x22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x63\x6d\x64\x6c\x69\x6e\x65\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\x02\0\0\0\x04\0\0\0\x10\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6b\
+\x65\x78\x65\x63\x5f\x70\x65\x2e\x62\x73\x73\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x21\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02\0\0\0\
+\x04\0\0\0\x07\0\0\0\x01\0\0\0\x80\0\0\0\0\0\0\0\0\0\0\0\x2e\x72\x6f\x64\x61\
+\x74\x61\x2e\x73\x74\x72\x31\x2e\x31\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\x69\x6e\x69\x74\x72\x64\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x47\x50\x4c\0\
+\0\0\0\0\xb7\0\0\0\0\0\0\0\x95\0\0\0\0\0\0\0\0\0\0\0\x14\0\0\0\0\0\0\0\x5e\0\0\
+\0\x39\x01\0\0\x1b\xe0\0\0\x1a\0\0\0\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x70\x61\x72\x73\x65\x5f\x70\
+\x65\0\0\0\0\0\0\0\0\0\0\0\0\x18\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\x01\0\
+\0\0\x10\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x62\x70\x66\x5f\x68\x61\x6e\x64\x6c\x65\
+\x5f\x70\x65\x66\x69\x6c\x65\0\0\0\0\0\0\0\x47\x50\x4c\0\0\0\0\0\xb7\0\0\0\0\0\
+\0\0\x95\0\0\0\0\0\0\0\0\0\0\0\x16\0\0\0\0\0\0\0\x5e\0\0\0\xc8\x01\0\0\x1b\xfc\
+\0\0\x1a\0\0\0\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\x70\x6f\x73\x74\x5f\x70\x61\x72\x73\x65\x5f\x70\x65\
+\0\0\0\0\0\0\0\x18\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\x10\0\0\0\
+\0\0\0\0\0\0\0\0\x01\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\x10\0\0\0\0\0\0\0\x62\x70\x66\x5f\x70\x6f\x73\x74\x5f\x68\x61\x6e\x64\
+\x6c\x65\x5f\x70\x65\x66\x69\x6c\x65\0\0";
+	static const char opts_insn[] __attribute__((__aligned__(8))) = "\
+\xbf\x16\0\0\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\x78\xff\xff\xff\xb7\x02\0\
+\0\x88\0\0\0\xb7\x03\0\0\0\0\0\0\x85\0\0\0\x71\0\0\0\x05\0\x41\0\0\0\0\0\x61\
+\xa1\x78\xff\0\0\0\0\xd5\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x7c\xff\
+\0\0\0\0\xd5\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x80\xff\0\0\0\0\xd5\
+\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x84\xff\0\0\0\0\xd5\x01\x01\0\0\
+\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x88\xff\0\0\0\0\xd5\x01\x01\0\0\0\0\0\x85\0\
+\0\0\xa8\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x61\x01\0\0\0\0\0\0\xd5\x01\
+\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x18\x60\0\0\0\0\0\0\0\0\
+\0\0\x04\0\0\0\x61\x01\0\0\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\
+\x85\0\0\0\xa8\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x08\0\0\0\x61\x01\0\0\0\0\0\0\
+\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x18\x60\0\0\0\0\
+\0\0\0\0\0\0\x0c\0\0\0\x61\x01\0\0\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\
+\0\0\0\x85\0\0\0\xa8\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\x61\x01\0\0\0\
+\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x18\x60\0\
+\0\0\0\0\0\0\0\0\0\x14\0\0\0\x61\x01\0\0\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\
+\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x18\0\0\0\x61\x01\
+\0\0\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x18\
+\x60\0\0\0\0\0\0\0\0\0\0\x1c\0\0\0\x61\x01\0\0\0\0\0\0\xd5\x01\x02\0\0\0\0\0\
+\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\xbf\x70\0\0\0\0\0\0\x95\0\0\0\0\0\0\0\
+\x61\x60\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xb0\x0a\0\0\x63\x01\0\0\0\0\
+\0\0\x61\x60\x0c\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xac\x0a\0\0\x63\x01\0\0\
+\0\0\0\0\x79\x60\x10\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xa0\x0a\0\0\x7b\x01\
+\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\x05\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
+\x98\x0a\0\0\x7b\x01\0\0\0\0\0\0\xb7\x01\0\0\x12\0\0\0\x18\x62\0\0\0\0\0\0\0\0\
+\0\0\x98\x0a\0\0\xb7\x03\0\0\x1c\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\
+\xc5\x07\xa7\xff\0\0\0\0\x63\x7a\x78\xff\0\0\0\0\x61\x60\x1c\0\0\0\0\0\x15\0\
+\x03\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xc4\x0a\0\0\x63\x01\0\0\0\0\0\0\xb7\
+\x01\0\0\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\xb8\x0a\0\0\xb7\x03\0\0\x48\0\0\0\
+\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x9a\xff\0\0\0\0\x18\x61\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x63\x71\0\0\0\0\0\0\x61\x60\x2c\0\0\0\0\0\x15\0\x03\0\0\
+\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x0c\x0b\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\
+\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\0\x0b\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\
+\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x8b\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\
+\0\0\x04\0\0\0\x63\x71\0\0\0\0\0\0\x61\x60\x3c\0\0\0\0\0\x15\0\x03\0\0\0\0\0\
+\x18\x61\0\0\0\0\0\0\0\0\0\0\x54\x0b\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\
+\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x48\x0b\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\
+\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x7c\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
+\x08\0\0\0\x63\x71\0\0\0\0\0\0\x61\x60\x4c\0\0\0\0\0\x15\0\x03\0\0\0\0\0\x18\
+\x61\0\0\0\0\0\0\0\0\0\0\x9c\x0b\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\
+\x18\x62\0\0\0\0\0\0\0\0\0\0\x90\x0b\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\0\
+\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x6d\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
+\x0c\0\0\0\x63\x71\0\0\0\0\0\0\x61\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\
+\0\0\x08\x0c\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x5c\0\0\0\0\0\x15\0\x03\0\0\0\0\0\
+\x18\x61\0\0\0\0\0\0\0\0\0\0\xe4\x0b\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\
+\0\x18\x62\0\0\0\0\0\0\0\0\0\0\xd8\x0b\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\
+\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x5a\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
+\x10\0\0\0\x63\x71\0\0\0\0\0\0\x79\x63\x60\0\0\0\0\0\x15\x03\x08\0\0\0\0\0\x18\
+\x61\0\0\0\0\0\0\0\0\0\0\x20\x0c\0\0\xb7\x02\0\0\x10\0\0\0\x61\x60\x04\0\0\0\0\
+\0\x45\0\x02\0\x01\0\0\0\x85\0\0\0\x94\0\0\0\x05\0\x01\0\0\0\0\0\x85\0\0\0\x71\
+\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\x61\x20\0\0\0\0\0\0\x18\x61\0\0\0\
+\0\0\0\0\0\0\0\x38\x0c\0\0\x63\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x30\
+\x0c\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x40\x0c\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\
+\0\0\0\0\0\0\0\0\0\x20\x0c\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x48\x0c\0\0\x7b\x01\
+\0\0\0\0\0\0\xb7\x01\0\0\x02\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x38\x0c\0\0\xb7\
+\x03\0\0\x20\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x36\xff\0\0\
+\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\x61\x20\0\0\0\0\0\0\x18\x61\0\0\0\0\
+\0\0\0\0\0\0\x58\x0c\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\x16\0\0\0\x18\x62\0\0\
+\0\0\0\0\0\0\0\0\x58\x0c\0\0\xb7\x03\0\0\x04\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\
+\0\0\0\0\0\0\xc5\x07\x29\xff\0\0\0\0\x61\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\
+\0\0\0\0\0\x90\x0c\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x6c\0\0\0\0\0\x15\0\x03\0\0\
+\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x6c\x0c\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\
+\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x60\x0c\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\
+\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x19\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\
+\0\0\0\x14\0\0\0\x63\x71\0\0\0\0\0\0\x79\x63\x70\0\0\0\0\0\x15\x03\x08\0\0\0\0\
+\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xa8\x0c\0\0\xb7\x02\0\0\x10\0\0\0\x61\x60\x04\0\
+\0\0\0\0\x45\0\x02\0\x01\0\0\0\x85\0\0\0\x94\0\0\0\x05\0\x01\0\0\0\0\0\x85\0\0\
+\0\x71\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x14\0\0\0\x61\x20\0\0\0\0\0\0\x18\x61\
+\0\0\0\0\0\0\0\0\0\0\xc0\x0c\0\0\x63\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\
+\0\xb8\x0c\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xc8\x0c\0\0\x7b\x01\0\0\0\0\0\0\x18\
+\x60\0\0\0\0\0\0\0\0\0\0\xa8\x0c\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xd0\x0c\0\0\
+\x7b\x01\0\0\0\0\0\0\xb7\x01\0\0\x02\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\xc0\x0c\
+\0\0\xb7\x03\0\0\x20\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\xf5\
+\xfe\0\0\0\0\x61\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x10\x0d\0\0\
+\x63\x01\0\0\0\0\0\0\x61\x60\x7c\0\0\0\0\0\x15\0\x03\0\0\0\0\0\x18\x61\0\0\0\0\
+\0\0\0\0\0\0\xec\x0c\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x18\x62\0\0\0\
+\0\0\0\0\0\0\0\xe0\x0c\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\
+\0\0\0\0\0\xc5\x07\xe5\xfe\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x18\0\0\0\x63\
+\x71\0\0\0\0\0\0\x79\x63\x80\0\0\0\0\0\x15\x03\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\
+\0\0\0\0\0\x28\x0d\0\0\xb7\x02\0\0\x10\0\0\0\x61\x60\x04\0\0\0\0\0\x45\0\x02\0\
+\x01\0\0\0\x85\0\0\0\x94\0\0\0\x05\0\x01\0\0\0\0\0\x85\0\0\0\x71\0\0\0\x18\x62\
+\0\0\0\0\0\0\0\0\0\0\x18\0\0\0\x61\x20\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
+\x40\x0d\0\0\x63\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x38\x0d\0\0\x18\
+\x61\0\0\0\0\0\0\0\0\0\0\x48\x0d\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\
+\0\0\0\x28\x0d\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x50\x0d\0\0\x7b\x01\0\0\0\0\0\0\
+\xb7\x01\0\0\x02\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x40\x0d\0\0\xb7\x03\0\0\x20\
+\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\xc1\xfe\0\0\0\0\x61\x60\
+\x8c\0\0\0\0\0\x15\0\x03\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x6c\x0d\0\0\x63\
+\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x60\x0d\0\0\
+\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\xb5\xfe\
+\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x1c\0\0\0\x63\x71\0\0\0\0\0\0\x79\x63\x90\
+\0\0\0\0\0\x15\x03\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xa8\x0d\0\0\xb7\
+\x02\0\0\x07\0\0\0\x61\x60\x04\0\0\0\0\0\x45\0\x02\0\x01\0\0\0\x85\0\0\0\x94\0\
+\0\0\x05\0\x01\0\0\0\0\0\x85\0\0\0\x71\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x1c\0\
+\0\0\x61\x20\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xb8\x0d\0\0\x63\x01\0\0\0\
+\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xb0\x0d\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xc0\
+\x0d\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xa8\x0d\0\0\x18\x61\0\
+\0\0\0\0\0\0\0\0\0\xc8\x0d\0\0\x7b\x01\0\0\0\0\0\0\xb7\x01\0\0\x02\0\0\0\x18\
+\x62\0\0\0\0\0\0\0\0\0\0\xb8\x0d\0\0\xb7\x03\0\0\x20\0\0\0\x85\0\0\0\xa6\0\0\0\
+\xbf\x07\0\0\0\0\0\0\xc5\x07\x91\xfe\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x1c\0\
+\0\0\x61\x20\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xd8\x0d\0\0\x63\x01\0\0\0\
+\0\0\0\xb7\x01\0\0\x16\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\xd8\x0d\0\0\xb7\x03\0\
+\0\x04\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x84\xfe\0\0\0\0\
+\x18\x60\0\0\0\0\0\0\0\0\0\0\xe0\x0d\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x20\x0e\0\
+\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xe8\x0d\0\0\x18\x61\0\0\0\0\
+\0\0\0\0\0\0\x18\x0e\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xf8\
+\x0d\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x60\x0e\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\
+\0\0\0\0\0\0\0\0\0\0\x0e\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x70\x0e\0\0\x7b\x01\0\
+\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x10\x0e\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
+\x90\x0e\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x18\x61\0\
+\0\0\0\0\0\0\0\0\0\x88\x0e\0\0\x7b\x01\0\0\0\0\0\0\x61\x60\x08\0\0\0\0\0\x18\
+\x61\0\0\0\0\0\0\0\0\0\0\x28\x0e\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\0\0\0\0\0\
+\x18\x61\0\0\0\0\0\0\0\0\0\0\x2c\x0e\0\0\x63\x01\0\0\0\0\0\0\x79\x60\x10\0\0\0\
+\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x30\x0e\0\0\x7b\x01\0\0\0\0\0\0\x61\xa0\x78\
+\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x58\x0e\0\0\x63\x01\0\0\0\0\0\0\x18\
+\x61\0\0\0\0\0\0\0\0\0\0\xa0\x0e\0\0\xb7\x02\0\0\x12\0\0\0\xb7\x03\0\0\x0c\0\0\
+\0\xb7\x04\0\0\0\0\0\0\x85\0\0\0\xa7\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x4e\xfe\
+\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x10\x0e\0\0\x63\x70\x6c\0\0\0\0\0\x77\x07\
+\0\0\x20\0\0\0\x63\x70\x70\0\0\0\0\0\xb7\x01\0\0\x05\0\0\0\x18\x62\0\0\0\0\0\0\
+\0\0\0\0\x10\x0e\0\0\xb7\x03\0\0\x8c\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\
+\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x80\x0e\0\0\x61\x01\0\0\0\0\0\0\xd5\x01\x02\0\
+\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\xc5\x07\x3c\xfe\0\0\0\0\x63\
+\x7a\x80\xff\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xb8\x0e\0\0\x18\x61\0\0\0\0\0\
+\0\0\0\0\0\xf8\x0e\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xc0\x0e\
+\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xf0\x0e\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\
+\0\0\0\0\0\0\0\xd0\x0e\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x38\x0f\0\0\x7b\x01\0\0\
+\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xd8\x0e\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
+\x48\x0f\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xe8\x0e\0\0\x18\
+\x61\0\0\0\0\0\0\0\0\0\0\x68\x0f\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x60\x0f\0\0\x7b\x01\0\0\0\0\0\0\x61\
+\x60\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\0\x0f\0\0\x63\x01\0\0\0\0\0\0\
+\x61\x60\x0c\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x04\x0f\0\0\x63\x01\0\0\0\0\
+\0\0\x79\x60\x10\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x08\x0f\0\0\x7b\x01\0\0\
+\0\0\0\0\x61\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x30\x0f\0\0\x63\
+\x01\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x78\x0f\0\0\xb7\x02\0\0\x17\0\0\0\
+\xb7\x03\0\0\x0c\0\0\0\xb7\x04\0\0\0\0\0\0\x85\0\0\0\xa7\0\0\0\xbf\x07\0\0\0\0\
+\0\0\xc5\x07\x05\xfe\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xe8\x0e\0\0\x63\x70\
+\x6c\0\0\0\0\0\x77\x07\0\0\x20\0\0\0\x63\x70\x70\0\0\0\0\0\xb7\x01\0\0\x05\0\0\
+\0\x18\x62\0\0\0\0\0\0\0\0\0\0\xe8\x0e\0\0\xb7\x03\0\0\x8c\0\0\0\x85\0\0\0\xa6\
+\0\0\0\xbf\x07\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x58\x0f\0\0\x61\x01\0\0\
+\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\xc5\x07\
+\xf3\xfd\0\0\0\0\x63\x7a\x84\xff\0\0\0\0\x61\xa1\x78\xff\0\0\0\0\xd5\x01\x02\0\
+\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa0\x80\xff\0\0\0\0\x63\
+\x06\x98\0\0\0\0\0\x61\xa0\x84\xff\0\0\0\0\x63\x06\x9c\0\0\0\0\0\x18\x61\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x18\0\0\0\0\0\x18\x61\0\0\0\
+\0\0\0\0\0\0\0\x04\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x28\0\0\0\0\0\x18\x61\0\0\
+\0\0\0\0\0\0\0\0\x08\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x38\0\0\0\0\0\x18\x61\0\
+\0\0\0\0\0\0\0\0\0\x0c\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x48\0\0\0\0\0\x18\x61\
+\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x58\0\0\0\0\0\x18\
+\x61\0\0\0\0\0\0\0\0\0\0\x14\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x68\0\0\0\0\0\
+\x18\x61\0\0\0\0\0\0\0\0\0\0\x18\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x78\0\0\0\0\
+\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x1c\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x88\0\0\0\
+\0\0\xb7\0\0\0\0\0\0\0\x95\0\0\0\0\0\0\0";
+
+	opts.ctx = (struct bpf_loader_ctx *)skel;
+	opts.data_sz = sizeof(opts_data) - 1;
+	opts.data = (void *)opts_data;
+	opts.insns_sz = sizeof(opts_insn) - 1;
+	opts.insns = (void *)opts_insn;
+
+	err = bpf_load_and_run(&opts);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static inline struct kexec_pe_parser_bpf *
+kexec_pe_parser_bpf__open_and_load(void)
+{
+	struct kexec_pe_parser_bpf *skel;
+
+	skel = kexec_pe_parser_bpf__open();
+	if (!skel)
+		return NULL;
+	if (kexec_pe_parser_bpf__load(skel)) {
+		kexec_pe_parser_bpf__destroy(skel);
+		return NULL;
+	}
+	return skel;
+}
+
+__attribute__((unused)) static void
+kexec_pe_parser_bpf__assert(struct kexec_pe_parser_bpf *s __attribute__((unused)))
+{
+#ifdef __cplusplus
+#define _Static_assert static_assert
+#endif
+#ifdef __cplusplus
+#undef _Static_assert
+#endif
+}
+
+#endif /* __KEXEC_PE_PARSER_BPF_SKEL_H__ */
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFCv2 6/7] kexec: Integrate bpf light skeleton to load zboot image
  2025-04-29  4:12 [RFCv2 0/7] kexec: Use BPF lskel to enable kexec to load PE format boot image Pingfan Liu
                   ` (4 preceding siblings ...)
  2025-04-29  4:12 ` [RFCv2 5/7] kexec: Introduce a bpf-prog lskel to parse PE file Pingfan Liu
@ 2025-04-29  4:12 ` Pingfan Liu
  2025-04-29  4:12 ` [RFCv2 7/7] arm64/kexec: Add PE image format support Pingfan Liu
  6 siblings, 0 replies; 13+ messages in thread
From: Pingfan Liu @ 2025-04-29  4:12 UTC (permalink / raw)
  To: kexec
  Cc: Pingfan Liu, Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Jeremy Linton, Catalin Marinas, Will Deacon,
	Ard Biesheuvel, Simon Horman, Gerd Hoffmann, Vitaly Kuznetsov,
	Philipp Rudo, Viktor Malik, Jan Hendrik Farr, Baoquan He,
	Dave Young, Eric Biederman, Andrew Morton, bpf

All kexec PE bpf prog should align with the interface exposed by the
light skeleton
    four maps:
                    struct bpf_map_desc ringbuf_1;
                    struct bpf_map_desc ringbuf_2;
                    struct bpf_map_desc ringbuf_3;
                    struct bpf_map_desc ringbuf_4;
    four sections:
                    struct bpf_map_desc rodata;
                    struct bpf_map_desc data;
                    struct bpf_map_desc bss;
                    struct bpf_map_desc rodata_str1_1;
    two progs:
            SEC("fentry/bpf_handle_pefile")
            SEC("fentry/bpf_post_handle_pefile")

With the above presumption, the integration consists of two parts:
  -1. Call API exposed by light skeleton from kexec
  -2. The opts_insn[] and opts_data[] are bpf-prog dependent and
      can be extracted and passed in from the user space. In the
      kexec_file_load design, a PE file has a .bpf section, which data
      content is a ELF, and the ELF contains opts_insn[] opts_data[].
      As a bonus, BPF bytecode can be placed under the protection of the
      entire PE signature

Signed-off-by: Pingfan Liu <piliu@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Baoquan He <bhe@redhat.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: bpf@vger.kernel.org
To: kexec@lists.infradead.org
---
 kernel/Makefile                              |   1 +
 kernel/kexec_bpf/Makefile                    |   8 +
 kernel/kexec_bpf/kexec_pe_parser_bpf.lskel.h | 290 +------------------
 kernel/kexec_pe_image.c                      |  71 +++++
 4 files changed, 84 insertions(+), 286 deletions(-)

diff --git a/kernel/Makefile b/kernel/Makefile
index ab82d73d8ce81..7c384bf62535a 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -139,6 +139,7 @@ obj-$(CONFIG_RESOURCE_KUNIT_TEST) += resource_kunit.o
 obj-$(CONFIG_SYSCTL_KUNIT_TEST) += sysctl-test.o
 
 CFLAGS_stackleak.o += $(DISABLE_STACKLEAK_PLUGIN)
+CFLAGS_kexec_pe_image.o += -I$(srctree)/tools/lib
 obj-$(CONFIG_GCC_PLUGIN_STACKLEAK) += stackleak.o
 KASAN_SANITIZE_stackleak.o := n
 KCSAN_SANITIZE_stackleak.o := n
diff --git a/kernel/kexec_bpf/Makefile b/kernel/kexec_bpf/Makefile
index b772e78464f48..91d3fb8b4caf7 100644
--- a/kernel/kexec_bpf/Makefile
+++ b/kernel/kexec_bpf/Makefile
@@ -36,6 +36,14 @@ clean:
 kexec_pe_parser_bpf.lskel.h: $(OUTPUT)/kexec_pe_parser_bpf.o | $(BPFTOOL)
 	$(call msg,GEN-SKEL,$@)
 	$(Q)$(BPFTOOL) gen skeleton -L $< > $@
+	@# The following sed commands make opts_data[] and opts_insn[] visible in a file instead of only in a function.
+	@# And it removes the bytecode
+	$(Q) sed -i '/static const char opts_data\[\].*=/,/";$$/d' $@
+	$(Q) sed -i '/static const char opts_insn\[\].*=/,/";$$/d' $@
+	$(Q) sed -i \
+		-e 's/opts\.data_sz = sizeof(opts_data) - 1;/opts.data_sz = opts_data_sz;/' \
+		-e 's/opts\.insns_sz = sizeof(opts_insn) - 1;/opts.insns_sz = opts_insn_sz;/' $@
+	$(Q) sed -i '7i static char *opts_data, *opts_insn;\nstatic unsigned int opts_data_sz, opts_insn_sz;' $@
 
 
 $(OUTPUT)/kexec_pe_parser_bpf.o: kexec_pe_parser_bpf.c $(BPFOBJ) | $(OUTPUT)
diff --git a/kernel/kexec_bpf/kexec_pe_parser_bpf.lskel.h b/kernel/kexec_bpf/kexec_pe_parser_bpf.lskel.h
index d8a181609c32e..88a3aa90d5e04 100644
--- a/kernel/kexec_bpf/kexec_pe_parser_bpf.lskel.h
+++ b/kernel/kexec_bpf/kexec_pe_parser_bpf.lskel.h
@@ -4,6 +4,8 @@
 #define __KEXEC_PE_PARSER_BPF_SKEL_H__
 
 #include <bpf/skel_internal.h>
+static char *opts_data, *opts_insn;
+static unsigned int opts_data_sz, opts_insn_sz;
 
 struct kexec_pe_parser_bpf {
 	struct bpf_loader_ctx ctx;
@@ -103,295 +105,11 @@ kexec_pe_parser_bpf__load(struct kexec_pe_parser_bpf *skel)
 {
 	struct bpf_load_and_run_opts opts = {};
 	int err;
-	static const char opts_data[] __attribute__((__aligned__(8))) = "\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9f\xeb\x01\0\
-\x18\0\0\0\0\0\0\0\x04\x03\0\0\x04\x03\0\0\x79\x02\0\0\0\0\0\0\0\0\0\x02\x03\0\
-\0\0\x01\0\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\x01\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\
-\0\0\x04\0\0\0\x1b\0\0\0\x05\0\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\0\0\0\0\0\0\0\0\
-\x02\x06\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\0\0\0\x10\0\0\0\0\
-\x02\0\0\x04\x10\0\0\0\x19\0\0\0\x01\0\0\0\0\0\0\0\x1e\0\0\0\x05\0\0\0\x40\0\0\
-\0\x2a\0\0\0\0\0\0\x0e\x07\0\0\0\x01\0\0\0\0\0\0\0\x02\0\0\x04\x10\0\0\0\x19\0\
-\0\0\x01\0\0\0\0\0\0\0\x1e\0\0\0\x05\0\0\0\x40\0\0\0\x34\0\0\0\0\0\0\x0e\x09\0\
-\0\0\x01\0\0\0\0\0\0\0\x02\0\0\x04\x10\0\0\0\x19\0\0\0\x01\0\0\0\0\0\0\0\x1e\0\
-\0\0\x05\0\0\0\x40\0\0\0\x3e\0\0\0\0\0\0\x0e\x0b\0\0\0\x01\0\0\0\0\0\0\0\x02\0\
-\0\x04\x10\0\0\0\x19\0\0\0\x01\0\0\0\0\0\0\0\x1e\0\0\0\x05\0\0\0\x40\0\0\0\x48\
-\0\0\0\0\0\0\x0e\x0d\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\x0d\x02\0\0\0\x52\0\0\0\0\0\
-\0\x0c\x0f\0\0\0\0\0\0\0\0\0\0\x02\x12\0\0\0\0\x01\0\0\0\0\0\x01\x08\0\0\0\x40\
-\0\0\0\0\0\0\0\x01\0\0\x0d\x02\0\0\0\x13\x01\0\0\x11\0\0\0\x17\x01\0\0\x01\0\0\
-\x0c\x13\0\0\0\0\0\0\0\x01\0\0\x0d\x02\0\0\0\x13\x01\0\0\x11\0\0\0\x9c\x01\0\0\
-\x01\0\0\x0c\x15\0\0\0\x17\x02\0\0\0\0\0\x01\x01\0\0\0\x08\0\0\x01\0\0\0\0\0\0\
-\0\x03\0\0\0\0\x17\0\0\0\x04\0\0\0\x04\0\0\0\x1c\x02\0\0\0\0\0\x0e\x18\0\0\0\
-\x01\0\0\0\0\0\0\0\0\0\0\x0a\x17\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x1a\0\0\0\x04\
-\0\0\0\x10\0\0\0\x24\x02\0\0\0\0\0\x0e\x1b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\
-\0\0\x17\0\0\0\x04\0\0\0\x10\0\0\0\x35\x02\0\0\0\0\0\x0e\x1d\0\0\0\0\0\0\0\x46\
-\x02\0\0\0\0\0\x0e\x1d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x17\0\0\0\x04\0\
-\0\0\x07\0\0\0\x58\x02\0\0\x01\0\0\x0f\x10\0\0\0\x1f\0\0\0\0\0\0\0\x10\0\0\0\
-\x5d\x02\0\0\x01\0\0\x0f\x10\0\0\0\x1e\0\0\0\0\0\0\0\x10\0\0\0\x63\x02\0\0\x04\
-\0\0\x0f\x40\0\0\0\x08\0\0\0\0\0\0\0\x10\0\0\0\x0a\0\0\0\x10\0\0\0\x10\0\0\0\
-\x0c\0\0\0\x20\0\0\0\x10\0\0\0\x0e\0\0\0\x30\0\0\0\x10\0\0\0\x69\x02\0\0\x01\0\
-\0\x0f\x10\0\0\0\x1c\0\0\0\0\0\0\0\x10\0\0\0\x71\x02\0\0\x01\0\0\x0f\x04\0\0\0\
-\x19\0\0\0\0\0\0\0\x04\0\0\0\0\x69\x6e\x74\0\x5f\x5f\x41\x52\x52\x41\x59\x5f\
-\x53\x49\x5a\x45\x5f\x54\x59\x50\x45\x5f\x5f\0\x74\x79\x70\x65\0\x6d\x61\x78\
-\x5f\x65\x6e\x74\x72\x69\x65\x73\0\x72\x69\x6e\x67\x62\x75\x66\x5f\x31\0\x72\
-\x69\x6e\x67\x62\x75\x66\x5f\x32\0\x72\x69\x6e\x67\x62\x75\x66\x5f\x33\0\x72\
-\x69\x6e\x67\x62\x75\x66\x5f\x34\0\x64\x75\x6d\x6d\x79\0\x2e\x74\x65\x78\x74\0\
-\x2f\x68\x6f\x6d\x65\x2f\x6c\x69\x6e\x75\x78\x2f\x6b\x65\x72\x6e\x65\x6c\x2f\
-\x6b\x65\x78\x65\x63\x5f\x62\x70\x66\x2f\x6b\x65\x78\x65\x63\x5f\x70\x65\x5f\
-\x70\x61\x72\x73\x65\x72\x5f\x62\x70\x66\x2e\x63\0\x09\x5f\x5f\x62\x75\x69\x6c\
-\x74\x69\x6e\x5f\x6d\x65\x6d\x63\x70\x79\x28\x6c\x6f\x63\x61\x6c\x5f\x6e\x61\
-\x6d\x65\x2c\x20\x4b\x45\x58\x45\x43\x5f\x52\x45\x53\x5f\x49\x4e\x49\x54\x52\
-\x44\x5f\x4e\x41\x4d\x45\x2c\x20\x31\x36\x29\x3b\0\x09\x72\x65\x74\x75\x72\x6e\
-\x20\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x5f\x6d\x65\x6d\x63\x6d\x70\x28\x6c\
-\x6f\x63\x61\x6c\x5f\x6e\x61\x6d\x65\x2c\x20\x72\x65\x73\x5f\x6b\x65\x72\x6e\
-\x65\x6c\x2c\x20\x34\x29\x3b\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x6c\x6f\x6e\
-\x67\x20\x6c\x6f\x6e\x67\0\x63\x74\x78\0\x70\x61\x72\x73\x65\x5f\x70\x65\0\x66\
-\x65\x6e\x74\x72\x79\x2f\x62\x70\x66\x5f\x68\x61\x6e\x64\x6c\x65\x5f\x70\x65\
-\x66\x69\x6c\x65\0\x5f\x5f\x61\x74\x74\x72\x69\x62\x75\x74\x65\x5f\x5f\x28\x28\
-\x75\x73\x65\x64\x29\x29\x20\x69\x6e\x74\x20\x42\x50\x46\x5f\x50\x52\x4f\x47\
-\x28\x70\x61\x72\x73\x65\x5f\x70\x65\x2c\x20\x63\x68\x61\x72\x20\x2a\x69\x6d\
-\x61\x67\x65\x5f\x62\x75\x66\x2c\x20\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\
-\x6e\x74\x20\x69\x6d\x61\x67\x65\x5f\x73\x7a\x2c\x20\x63\x68\x61\x72\x20\x2a\
-\x69\x6e\x69\x74\x72\x64\x2c\0\x70\x6f\x73\x74\x5f\x70\x61\x72\x73\x65\x5f\x70\
-\x65\0\x66\x65\x6e\x74\x72\x79\x2f\x62\x70\x66\x5f\x70\x6f\x73\x74\x5f\x68\x61\
-\x6e\x64\x6c\x65\x5f\x70\x65\x66\x69\x6c\x65\0\x5f\x5f\x61\x74\x74\x72\x69\x62\
-\x75\x74\x65\x5f\x5f\x28\x28\x75\x73\x65\x64\x29\x29\x20\x69\x6e\x74\x20\x42\
-\x50\x46\x5f\x50\x52\x4f\x47\x28\x70\x6f\x73\x74\x5f\x70\x61\x72\x73\x65\x5f\
-\x70\x65\x2c\x20\x63\x68\x61\x72\x20\x2a\x69\x6d\x61\x67\x65\x5f\x62\x75\x66\
-\x2c\x20\x69\x6e\x74\x20\x62\x75\x66\x5f\x73\x7a\x29\0\x63\x68\x61\x72\0\x4c\
-\x49\x43\x45\x4e\x53\x45\0\x64\x75\x6d\x6d\x79\x2e\x72\x65\x73\x5f\x6b\x65\x72\
-\x6e\x65\x6c\0\x64\x75\x6d\x6d\x79\x2e\x6c\x6f\x63\x61\x6c\x5f\x6e\x61\x6d\x65\
-\0\x64\x75\x6d\x6d\x79\x2e\x72\x65\x73\x5f\x63\x6d\x64\x6c\x69\x6e\x65\0\x2e\
-\x62\x73\x73\0\x2e\x64\x61\x74\x61\0\x2e\x6d\x61\x70\x73\0\x2e\x72\x6f\x64\x61\
-\x74\x61\0\x6c\x69\x63\x65\x6e\x73\x65\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\x95\x05\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\
-\0\0\0\0\0\0\0\0\0\x72\x69\x6e\x67\x62\x75\x66\x5f\x31\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\x10\0\0\0\0\0\0\0\0\0\0\0\0\x72\x69\x6e\x67\x62\x75\x66\x5f\x32\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1b\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\x10\0\0\0\0\0\0\0\0\0\0\0\0\x72\x69\x6e\x67\x62\x75\x66\x5f\x33\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1b\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\0\0\0\0\0\x72\x69\x6e\x67\x62\x75\x66\
-\x5f\x34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\x02\0\0\0\x04\0\0\0\x10\0\0\0\x01\0\0\0\x80\0\0\0\0\0\0\0\0\0\0\0\x6b\x65\x78\
-\x65\x63\x5f\x70\x65\x2e\x72\x6f\x64\x61\x74\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\x24\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6b\x65\x72\x6e\x65\x6c\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\x02\0\0\0\x04\0\0\0\x10\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\x6b\x65\x78\x65\x63\x5f\x70\x65\x2e\x64\x61\x74\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\x22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x63\x6d\x64\x6c\x69\x6e\x65\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\x02\0\0\0\x04\0\0\0\x10\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6b\
-\x65\x78\x65\x63\x5f\x70\x65\x2e\x62\x73\x73\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\x21\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02\0\0\0\
-\x04\0\0\0\x07\0\0\0\x01\0\0\0\x80\0\0\0\0\0\0\0\0\0\0\0\x2e\x72\x6f\x64\x61\
-\x74\x61\x2e\x73\x74\x72\x31\x2e\x31\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\x69\x6e\x69\x74\x72\x64\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x47\x50\x4c\0\
-\0\0\0\0\xb7\0\0\0\0\0\0\0\x95\0\0\0\0\0\0\0\0\0\0\0\x14\0\0\0\0\0\0\0\x5e\0\0\
-\0\x39\x01\0\0\x1b\xe0\0\0\x1a\0\0\0\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x70\x61\x72\x73\x65\x5f\x70\
-\x65\0\0\0\0\0\0\0\0\0\0\0\0\x18\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\x01\0\
-\0\0\x10\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x62\x70\x66\x5f\x68\x61\x6e\x64\x6c\x65\
-\x5f\x70\x65\x66\x69\x6c\x65\0\0\0\0\0\0\0\x47\x50\x4c\0\0\0\0\0\xb7\0\0\0\0\0\
-\0\0\x95\0\0\0\0\0\0\0\0\0\0\0\x16\0\0\0\0\0\0\0\x5e\0\0\0\xc8\x01\0\0\x1b\xfc\
-\0\0\x1a\0\0\0\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\0\0\x70\x6f\x73\x74\x5f\x70\x61\x72\x73\x65\x5f\x70\x65\
-\0\0\0\0\0\0\0\x18\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\x10\0\0\0\
-\0\0\0\0\0\0\0\0\x01\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
-\0\0\0\x10\0\0\0\0\0\0\0\x62\x70\x66\x5f\x70\x6f\x73\x74\x5f\x68\x61\x6e\x64\
-\x6c\x65\x5f\x70\x65\x66\x69\x6c\x65\0\0";
-	static const char opts_insn[] __attribute__((__aligned__(8))) = "\
-\xbf\x16\0\0\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\x78\xff\xff\xff\xb7\x02\0\
-\0\x88\0\0\0\xb7\x03\0\0\0\0\0\0\x85\0\0\0\x71\0\0\0\x05\0\x41\0\0\0\0\0\x61\
-\xa1\x78\xff\0\0\0\0\xd5\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x7c\xff\
-\0\0\0\0\xd5\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x80\xff\0\0\0\0\xd5\
-\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x84\xff\0\0\0\0\xd5\x01\x01\0\0\
-\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x88\xff\0\0\0\0\xd5\x01\x01\0\0\0\0\0\x85\0\
-\0\0\xa8\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x61\x01\0\0\0\0\0\0\xd5\x01\
-\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x18\x60\0\0\0\0\0\0\0\0\
-\0\0\x04\0\0\0\x61\x01\0\0\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\
-\x85\0\0\0\xa8\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x08\0\0\0\x61\x01\0\0\0\0\0\0\
-\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x18\x60\0\0\0\0\
-\0\0\0\0\0\0\x0c\0\0\0\x61\x01\0\0\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\
-\0\0\0\x85\0\0\0\xa8\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\x61\x01\0\0\0\
-\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x18\x60\0\
-\0\0\0\0\0\0\0\0\0\x14\0\0\0\x61\x01\0\0\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\
-\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x18\0\0\0\x61\x01\
-\0\0\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x18\
-\x60\0\0\0\0\0\0\0\0\0\0\x1c\0\0\0\x61\x01\0\0\0\0\0\0\xd5\x01\x02\0\0\0\0\0\
-\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\xbf\x70\0\0\0\0\0\0\x95\0\0\0\0\0\0\0\
-\x61\x60\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xb0\x0a\0\0\x63\x01\0\0\0\0\
-\0\0\x61\x60\x0c\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xac\x0a\0\0\x63\x01\0\0\
-\0\0\0\0\x79\x60\x10\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xa0\x0a\0\0\x7b\x01\
-\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\x05\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
-\x98\x0a\0\0\x7b\x01\0\0\0\0\0\0\xb7\x01\0\0\x12\0\0\0\x18\x62\0\0\0\0\0\0\0\0\
-\0\0\x98\x0a\0\0\xb7\x03\0\0\x1c\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\
-\xc5\x07\xa7\xff\0\0\0\0\x63\x7a\x78\xff\0\0\0\0\x61\x60\x1c\0\0\0\0\0\x15\0\
-\x03\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xc4\x0a\0\0\x63\x01\0\0\0\0\0\0\xb7\
-\x01\0\0\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\xb8\x0a\0\0\xb7\x03\0\0\x48\0\0\0\
-\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x9a\xff\0\0\0\0\x18\x61\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\x63\x71\0\0\0\0\0\0\x61\x60\x2c\0\0\0\0\0\x15\0\x03\0\0\
-\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x0c\x0b\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\
-\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\0\x0b\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\
-\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x8b\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\
-\0\0\x04\0\0\0\x63\x71\0\0\0\0\0\0\x61\x60\x3c\0\0\0\0\0\x15\0\x03\0\0\0\0\0\
-\x18\x61\0\0\0\0\0\0\0\0\0\0\x54\x0b\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\
-\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x48\x0b\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\
-\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x7c\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
-\x08\0\0\0\x63\x71\0\0\0\0\0\0\x61\x60\x4c\0\0\0\0\0\x15\0\x03\0\0\0\0\0\x18\
-\x61\0\0\0\0\0\0\0\0\0\0\x9c\x0b\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\
-\x18\x62\0\0\0\0\0\0\0\0\0\0\x90\x0b\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\0\
-\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x6d\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
-\x0c\0\0\0\x63\x71\0\0\0\0\0\0\x61\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\
-\0\0\x08\x0c\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x5c\0\0\0\0\0\x15\0\x03\0\0\0\0\0\
-\x18\x61\0\0\0\0\0\0\0\0\0\0\xe4\x0b\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\
-\0\x18\x62\0\0\0\0\0\0\0\0\0\0\xd8\x0b\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\
-\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x5a\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
-\x10\0\0\0\x63\x71\0\0\0\0\0\0\x79\x63\x60\0\0\0\0\0\x15\x03\x08\0\0\0\0\0\x18\
-\x61\0\0\0\0\0\0\0\0\0\0\x20\x0c\0\0\xb7\x02\0\0\x10\0\0\0\x61\x60\x04\0\0\0\0\
-\0\x45\0\x02\0\x01\0\0\0\x85\0\0\0\x94\0\0\0\x05\0\x01\0\0\0\0\0\x85\0\0\0\x71\
-\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\x61\x20\0\0\0\0\0\0\x18\x61\0\0\0\
-\0\0\0\0\0\0\0\x38\x0c\0\0\x63\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x30\
-\x0c\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x40\x0c\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\
-\0\0\0\0\0\0\0\0\0\x20\x0c\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x48\x0c\0\0\x7b\x01\
-\0\0\0\0\0\0\xb7\x01\0\0\x02\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x38\x0c\0\0\xb7\
-\x03\0\0\x20\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x36\xff\0\0\
-\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\x61\x20\0\0\0\0\0\0\x18\x61\0\0\0\0\
-\0\0\0\0\0\0\x58\x0c\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\x16\0\0\0\x18\x62\0\0\
-\0\0\0\0\0\0\0\0\x58\x0c\0\0\xb7\x03\0\0\x04\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\
-\0\0\0\0\0\0\xc5\x07\x29\xff\0\0\0\0\x61\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\
-\0\0\0\0\0\x90\x0c\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x6c\0\0\0\0\0\x15\0\x03\0\0\
-\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x6c\x0c\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\
-\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x60\x0c\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\
-\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x19\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\
-\0\0\0\x14\0\0\0\x63\x71\0\0\0\0\0\0\x79\x63\x70\0\0\0\0\0\x15\x03\x08\0\0\0\0\
-\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xa8\x0c\0\0\xb7\x02\0\0\x10\0\0\0\x61\x60\x04\0\
-\0\0\0\0\x45\0\x02\0\x01\0\0\0\x85\0\0\0\x94\0\0\0\x05\0\x01\0\0\0\0\0\x85\0\0\
-\0\x71\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x14\0\0\0\x61\x20\0\0\0\0\0\0\x18\x61\
-\0\0\0\0\0\0\0\0\0\0\xc0\x0c\0\0\x63\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\
-\0\xb8\x0c\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xc8\x0c\0\0\x7b\x01\0\0\0\0\0\0\x18\
-\x60\0\0\0\0\0\0\0\0\0\0\xa8\x0c\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xd0\x0c\0\0\
-\x7b\x01\0\0\0\0\0\0\xb7\x01\0\0\x02\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\xc0\x0c\
-\0\0\xb7\x03\0\0\x20\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\xf5\
-\xfe\0\0\0\0\x61\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x10\x0d\0\0\
-\x63\x01\0\0\0\0\0\0\x61\x60\x7c\0\0\0\0\0\x15\0\x03\0\0\0\0\0\x18\x61\0\0\0\0\
-\0\0\0\0\0\0\xec\x0c\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x18\x62\0\0\0\
-\0\0\0\0\0\0\0\xe0\x0c\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\
-\0\0\0\0\0\xc5\x07\xe5\xfe\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x18\0\0\0\x63\
-\x71\0\0\0\0\0\0\x79\x63\x80\0\0\0\0\0\x15\x03\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\
-\0\0\0\0\0\x28\x0d\0\0\xb7\x02\0\0\x10\0\0\0\x61\x60\x04\0\0\0\0\0\x45\0\x02\0\
-\x01\0\0\0\x85\0\0\0\x94\0\0\0\x05\0\x01\0\0\0\0\0\x85\0\0\0\x71\0\0\0\x18\x62\
-\0\0\0\0\0\0\0\0\0\0\x18\0\0\0\x61\x20\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
-\x40\x0d\0\0\x63\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x38\x0d\0\0\x18\
-\x61\0\0\0\0\0\0\0\0\0\0\x48\x0d\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\
-\0\0\0\x28\x0d\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x50\x0d\0\0\x7b\x01\0\0\0\0\0\0\
-\xb7\x01\0\0\x02\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x40\x0d\0\0\xb7\x03\0\0\x20\
-\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\xc1\xfe\0\0\0\0\x61\x60\
-\x8c\0\0\0\0\0\x15\0\x03\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x6c\x0d\0\0\x63\
-\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x60\x0d\0\0\
-\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\xb5\xfe\
-\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x1c\0\0\0\x63\x71\0\0\0\0\0\0\x79\x63\x90\
-\0\0\0\0\0\x15\x03\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xa8\x0d\0\0\xb7\
-\x02\0\0\x07\0\0\0\x61\x60\x04\0\0\0\0\0\x45\0\x02\0\x01\0\0\0\x85\0\0\0\x94\0\
-\0\0\x05\0\x01\0\0\0\0\0\x85\0\0\0\x71\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x1c\0\
-\0\0\x61\x20\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xb8\x0d\0\0\x63\x01\0\0\0\
-\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xb0\x0d\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xc0\
-\x0d\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xa8\x0d\0\0\x18\x61\0\
-\0\0\0\0\0\0\0\0\0\xc8\x0d\0\0\x7b\x01\0\0\0\0\0\0\xb7\x01\0\0\x02\0\0\0\x18\
-\x62\0\0\0\0\0\0\0\0\0\0\xb8\x0d\0\0\xb7\x03\0\0\x20\0\0\0\x85\0\0\0\xa6\0\0\0\
-\xbf\x07\0\0\0\0\0\0\xc5\x07\x91\xfe\0\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x1c\0\
-\0\0\x61\x20\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xd8\x0d\0\0\x63\x01\0\0\0\
-\0\0\0\xb7\x01\0\0\x16\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\xd8\x0d\0\0\xb7\x03\0\
-\0\x04\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x84\xfe\0\0\0\0\
-\x18\x60\0\0\0\0\0\0\0\0\0\0\xe0\x0d\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x20\x0e\0\
-\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xe8\x0d\0\0\x18\x61\0\0\0\0\
-\0\0\0\0\0\0\x18\x0e\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xf8\
-\x0d\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x60\x0e\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\
-\0\0\0\0\0\0\0\0\0\0\x0e\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x70\x0e\0\0\x7b\x01\0\
-\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x10\x0e\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
-\x90\x0e\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x18\x61\0\
-\0\0\0\0\0\0\0\0\0\x88\x0e\0\0\x7b\x01\0\0\0\0\0\0\x61\x60\x08\0\0\0\0\0\x18\
-\x61\0\0\0\0\0\0\0\0\0\0\x28\x0e\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\0\0\0\0\0\
-\x18\x61\0\0\0\0\0\0\0\0\0\0\x2c\x0e\0\0\x63\x01\0\0\0\0\0\0\x79\x60\x10\0\0\0\
-\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x30\x0e\0\0\x7b\x01\0\0\0\0\0\0\x61\xa0\x78\
-\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x58\x0e\0\0\x63\x01\0\0\0\0\0\0\x18\
-\x61\0\0\0\0\0\0\0\0\0\0\xa0\x0e\0\0\xb7\x02\0\0\x12\0\0\0\xb7\x03\0\0\x0c\0\0\
-\0\xb7\x04\0\0\0\0\0\0\x85\0\0\0\xa7\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\x4e\xfe\
-\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x10\x0e\0\0\x63\x70\x6c\0\0\0\0\0\x77\x07\
-\0\0\x20\0\0\0\x63\x70\x70\0\0\0\0\0\xb7\x01\0\0\x05\0\0\0\x18\x62\0\0\0\0\0\0\
-\0\0\0\0\x10\x0e\0\0\xb7\x03\0\0\x8c\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\
-\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x80\x0e\0\0\x61\x01\0\0\0\0\0\0\xd5\x01\x02\0\
-\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\xc5\x07\x3c\xfe\0\0\0\0\x63\
-\x7a\x80\xff\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xb8\x0e\0\0\x18\x61\0\0\0\0\0\
-\0\0\0\0\0\xf8\x0e\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xc0\x0e\
-\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xf0\x0e\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\
-\0\0\0\0\0\0\0\xd0\x0e\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x38\x0f\0\0\x7b\x01\0\0\
-\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xd8\x0e\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\
-\x48\x0f\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xe8\x0e\0\0\x18\
-\x61\0\0\0\0\0\0\0\0\0\0\x68\x0f\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\
-\0\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x60\x0f\0\0\x7b\x01\0\0\0\0\0\0\x61\
-\x60\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\0\x0f\0\0\x63\x01\0\0\0\0\0\0\
-\x61\x60\x0c\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x04\x0f\0\0\x63\x01\0\0\0\0\
-\0\0\x79\x60\x10\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x08\x0f\0\0\x7b\x01\0\0\
-\0\0\0\0\x61\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x30\x0f\0\0\x63\
-\x01\0\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x78\x0f\0\0\xb7\x02\0\0\x17\0\0\0\
-\xb7\x03\0\0\x0c\0\0\0\xb7\x04\0\0\0\0\0\0\x85\0\0\0\xa7\0\0\0\xbf\x07\0\0\0\0\
-\0\0\xc5\x07\x05\xfe\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xe8\x0e\0\0\x63\x70\
-\x6c\0\0\0\0\0\x77\x07\0\0\x20\0\0\0\x63\x70\x70\0\0\0\0\0\xb7\x01\0\0\x05\0\0\
-\0\x18\x62\0\0\0\0\0\0\0\0\0\0\xe8\x0e\0\0\xb7\x03\0\0\x8c\0\0\0\x85\0\0\0\xa6\
-\0\0\0\xbf\x07\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x58\x0f\0\0\x61\x01\0\0\
-\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\xc5\x07\
-\xf3\xfd\0\0\0\0\x63\x7a\x84\xff\0\0\0\0\x61\xa1\x78\xff\0\0\0\0\xd5\x01\x02\0\
-\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa0\x80\xff\0\0\0\0\x63\
-\x06\x98\0\0\0\0\0\x61\xa0\x84\xff\0\0\0\0\x63\x06\x9c\0\0\0\0\0\x18\x61\0\0\0\
-\0\0\0\0\0\0\0\0\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x18\0\0\0\0\0\x18\x61\0\0\0\
-\0\0\0\0\0\0\0\x04\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x28\0\0\0\0\0\x18\x61\0\0\
-\0\0\0\0\0\0\0\0\x08\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x38\0\0\0\0\0\x18\x61\0\
-\0\0\0\0\0\0\0\0\0\x0c\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x48\0\0\0\0\0\x18\x61\
-\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x58\0\0\0\0\0\x18\
-\x61\0\0\0\0\0\0\0\0\0\0\x14\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x68\0\0\0\0\0\
-\x18\x61\0\0\0\0\0\0\0\0\0\0\x18\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x78\0\0\0\0\
-\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x1c\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x88\0\0\0\
-\0\0\xb7\0\0\0\0\0\0\0\x95\0\0\0\0\0\0\0";
 
 	opts.ctx = (struct bpf_loader_ctx *)skel;
-	opts.data_sz = sizeof(opts_data) - 1;
+	opts.data_sz = opts_data_sz;
 	opts.data = (void *)opts_data;
-	opts.insns_sz = sizeof(opts_insn) - 1;
+	opts.insns_sz = opts_insn_sz;
 	opts.insns = (void *)opts_insn;
 
 	err = bpf_load_and_run(&opts);
diff --git a/kernel/kexec_pe_image.c b/kernel/kexec_pe_image.c
index 610bb134f5e34..a6e299c657475 100644
--- a/kernel/kexec_pe_image.c
+++ b/kernel/kexec_pe_image.c
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/vmalloc.h>
 #include <linux/kexec.h>
+#include <linux/elf.h>
 #include <linux/pe.h>
 #include <linux/string.h>
 #include <linux/bpf.h>
@@ -23,6 +24,7 @@
 #include <asm/image.h>
 #include <asm/memory.h>
 
+#include "kexec_bpf/kexec_pe_parser_bpf.lskel.h"
 
 static LIST_HEAD(phase_head);
 
@@ -309,14 +311,83 @@ static bool pe_has_bpf_section(char *file_buf, unsigned long pe_sz)
 	return true;
 }
 
+static struct kexec_pe_parser_bpf *pe_parser;
+
+static void *get_symbol_from_elf(const char *elf_data, size_t elf_size,
+		const char *symbol_name, unsigned int *symbol_size)
+{
+	Elf_Ehdr *ehdr = (Elf_Ehdr *)elf_data;
+	Elf_Shdr *shdr, *symtab_shdr, *strtab_shdr, *dst_shdr;
+	Elf64_Sym *sym, *symtab = NULL;
+	char *strtab = NULL;
+	void *symbol_data = NULL;
+	int i;
+
+	symtab_shdr = strtab_shdr = NULL;
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
+		pr_err("Not a valid ELF file\n");
+		goto out;
+	}
+
+	shdr = (struct elf_shdr *)(elf_data + ehdr->e_shoff);
+	for (i = 0; i < ehdr->e_shnum; i++) {
+		if (shdr[i].sh_type == SHT_SYMTAB) {
+			symtab_shdr = &shdr[i];
+		} else if (shdr[i].sh_type == SHT_STRTAB && i != ehdr->e_shstrndx) {
+			strtab_shdr = &shdr[i];
+		}
+	}
+
+	if (!symtab_shdr || !strtab_shdr) {
+		pr_err("Symbol table or string table not found\n");
+		goto out;
+	}
+	symtab = (Elf64_Sym *)(elf_data + symtab_shdr->sh_offset);
+	strtab = (char *)(elf_data + strtab_shdr->sh_offset);
+	for (i = 0; i < symtab_shdr->sh_size / sizeof(Elf64_Sym); i++) {
+		sym = &symtab[i];
+		if (strcmp(&strtab[sym->st_name], symbol_name) == 0) {
+			if (sym->st_shndx >= SHN_LORESERVE)
+			    return NULL; // No section data for these
+			dst_shdr = &shdr[sym->st_shndx];
+			symbol_data = (void *)(elf_data + dst_shdr->sh_offset + sym->st_value);
+			*symbol_size = symtab[i].st_size;
+			break;
+		}
+	}
+
+out:
+    return symbol_data;
+}
+
 /* Load a ELF */
 static int arm_bpf_prog(char *bpf_elf, unsigned long sz)
 {
+	opts_data = get_symbol_from_elf(bpf_elf, sz, "opts_data", &opts_data_sz);
+	opts_insn = get_symbol_from_elf(bpf_elf, sz, "opts_insn", &opts_insn_sz);
+	if (!opts_data || !opts_insn)
+		return -1;
+	/*
+	 * When light skeleton generates opts_data[] and opts_insn[], it appends a
+	 * NULL terminator at the end of string
+	 */
+	opts_data_sz = opts_data_sz - 1;
+	opts_insn_sz = opts_insn_sz - 1;
+
+	pe_parser = kexec_pe_parser_bpf__open_and_load();
+	if (!pe_parser)
+		return -1;
+	kexec_pe_parser_bpf__attach(pe_parser);
+
 	return 0;
 }
 
 static void disarm_bpf_prog(void)
 {
+	kexec_pe_parser_bpf__destroy(pe_parser);
+	pe_parser = NULL;
+	opts_data = NULL;
+	opts_insn = NULL;
 }
 
 /*
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [RFCv2 7/7] arm64/kexec: Add PE image format support
  2025-04-29  4:12 [RFCv2 0/7] kexec: Use BPF lskel to enable kexec to load PE format boot image Pingfan Liu
                   ` (5 preceding siblings ...)
  2025-04-29  4:12 ` [RFCv2 6/7] kexec: Integrate bpf light skeleton to load zboot image Pingfan Liu
@ 2025-04-29  4:12 ` Pingfan Liu
  2025-04-30  5:35   ` kernel test robot
  6 siblings, 1 reply; 13+ messages in thread
From: Pingfan Liu @ 2025-04-29  4:12 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Pingfan Liu, Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Jeremy Linton, Catalin Marinas, Will Deacon,
	Ard Biesheuvel, Simon Horman, Gerd Hoffmann, Vitaly Kuznetsov,
	Philipp Rudo, Viktor Malik, Jan Hendrik Farr, Baoquan He,
	Dave Young, Eric Biederman, Andrew Morton, kexec, bpf

Now everything is ready for kexec PE image parser. Select it for zboot
and UKI image support.

Signed-off-by: Pingfan Liu <piliu@redhat.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
To: linux-arm-kernel@lists.infradead.org
---
 arch/arm64/Kconfig                     | 1 +
 arch/arm64/include/asm/kexec.h         | 1 +
 arch/arm64/kernel/machine_kexec_file.c | 3 +++
 3 files changed, 5 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index a182295e6f08b..80b365fb7643e 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1592,6 +1592,7 @@ config ARCH_SELECTS_KEXEC_FILE
 	def_bool y
 	depends on KEXEC_FILE
 	select HAVE_IMA_KEXEC if IMA
+	select KEXEC_PE_IMAGE
 
 config ARCH_SUPPORTS_KEXEC_SIG
 	def_bool y
diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h
index 4d9cc7a76d9ca..d50796bd2f1e6 100644
--- a/arch/arm64/include/asm/kexec.h
+++ b/arch/arm64/include/asm/kexec.h
@@ -120,6 +120,7 @@ struct kimage_arch {
 
 #ifdef CONFIG_KEXEC_FILE
 extern const struct kexec_file_ops kexec_image_ops;
+extern const struct kexec_file_ops kexec_pe_image_ops;
 
 int arch_kimage_file_post_load_cleanup(struct kimage *image);
 #define arch_kimage_file_post_load_cleanup arch_kimage_file_post_load_cleanup
diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index af1ca875c52ce..7c544c385a9ab 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -24,6 +24,9 @@
 
 const struct kexec_file_ops * const kexec_file_loaders[] = {
 	&kexec_image_ops,
+#ifdef CONFIG_KEXEC_PE_IMAGE
+	&kexec_pe_image_ops,
+#endif
 	NULL
 };
 
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [RFCv2 4/7] bpf/kexec: Introduce three bpf kfunc for kexec
  2025-04-29  4:12 ` [RFCv2 4/7] bpf/kexec: Introduce three bpf kfunc for kexec Pingfan Liu
@ 2025-04-30  0:03   ` Alexei Starovoitov
  2025-04-30 10:47     ` Pingfan Liu
  0 siblings, 1 reply; 13+ messages in thread
From: Alexei Starovoitov @ 2025-04-30  0:03 UTC (permalink / raw)
  To: Pingfan Liu
  Cc: bpf, kexec, Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Jeremy Linton, Catalin Marinas, Will Deacon,
	Ard Biesheuvel, Simon Horman, Gerd Hoffmann, Vitaly Kuznetsov,
	Philipp Rudo, Viktor Malik, Jan Hendrik Farr, Baoquan He,
	Dave Young, Eric Biederman, Andrew Morton, KP Singh,
	Stanislav Fomichev, Hao Luo, Jiri Olsa

On Mon, Apr 28, 2025 at 9:13 PM Pingfan Liu <piliu@redhat.com> wrote:
 +__bpf_kfunc struct mem_range_result *bpf_kexec_decompress(char
*image_gz_payload, int image_gz_sz,
> +                       unsigned int expected_decompressed_sz)
> +{
> +       decompress_fn decompressor;
> +       //todo, use flush to cap the memory size used by decompression
> +       long (*flush)(void*, unsigned long) = NULL;
> +       struct mem_range_result *range;
> +       const char *name;
> +       void *output_buf;
> +       char *input_buf;
> +       int ret;
> +
> +       range = kmalloc(sizeof(struct mem_range_result), GFP_KERNEL);
> +       if (!range) {
> +               pr_err("fail to allocate mem_range_result\n");
> +               return NULL;
> +       }
> +       refcount_set(&range->usage, 1);
> +
> +       input_buf = vmalloc(image_gz_sz);
> +       if (!input_buf) {
> +               pr_err("fail to allocate input buffer\n");
> +               kfree(range);
> +               return NULL;
> +       }
> +
> +       ret = copy_from_kernel_nofault(input_buf, image_gz_payload, image_gz_sz);
> +       if (ret < 0) {
> +               pr_err("Error when copying from 0x%px, size:0x%x\n",
> +                               image_gz_payload, image_gz_sz);
> +               kfree(range);
> +               vfree(input_buf);
> +               return NULL;
> +       }
> +
> +       output_buf = vmalloc(expected_decompressed_sz);
> +       if (!output_buf) {
> +               pr_err("fail to allocate output buffer\n");
> +               kfree(range);
> +               vfree(input_buf);
> +               return NULL;
> +       }
> +
> +       decompressor = decompress_method(input_buf, image_gz_sz, &name);
> +       if (!decompressor) {
> +               pr_err("Can not find decompress method\n");
> +               kfree(range);
> +               vfree(input_buf);
> +               vfree(output_buf);
> +               return NULL;
> +       }
> +       //to do, use flush
> +       ret = decompressor(image_gz_payload, image_gz_sz, NULL, NULL,
> +                               output_buf, NULL, NULL);
> +
> +       /* Update the range map */
> +       if (ret == 0) {
> +               range->buf = output_buf;
> +               range->size = expected_decompressed_sz;
> +               range->status = 0;
> +       } else {
> +               pr_err("Decompress error\n");
> +               vfree(output_buf);
> +               kfree(range);
> +               return NULL;
> +       }
> +       pr_info("%s, return range 0x%lx\n", __func__, range);
> +       return range;
> +}

These kfuncs look like generic decompress routines.
They're not related to kexec and probably should be in kernel/bpf/helpers.c
or kernel/bpf/compression.c instead of kernel/kexec_pe_image.c.

They also must be KF_SLEEPABLE.
Please test your patches with all kernel debugs enabled.
Otherwise you would have seen all these "sleeping while atomic"
issues yourself.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFCv2 7/7] arm64/kexec: Add PE image format support
  2025-04-29  4:12 ` [RFCv2 7/7] arm64/kexec: Add PE image format support Pingfan Liu
@ 2025-04-30  5:35   ` kernel test robot
  0 siblings, 0 replies; 13+ messages in thread
From: kernel test robot @ 2025-04-30  5:35 UTC (permalink / raw)
  To: Pingfan Liu; +Cc: llvm, oe-kbuild-all

Hi Pingfan,

[This is a private test report for your RFC patch.]
kernel test robot noticed the following build warnings:

[auto build test WARNING on arm64/for-next/core]
[also build test WARNING on bpf-next/net bpf-next/master bpf/master linus/master v6.15-rc4 next-20250429]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Pingfan-Liu/kexec_file-Make-kexec_image_load_default-global-visible/20250429-121621
base:   https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/core
patch link:    https://lore.kernel.org/r/20250429041214.13291-8-piliu%40redhat.com
patch subject: [RFCv2 7/7] arm64/kexec: Add PE image format support
config: arm64-randconfig-002-20250430 (https://download.01.org/0day-ci/archive/20250430/202504301314.NaE4JGVw-lkp@intel.com/config)
compiler: clang version 21.0.0git (https://github.com/llvm/llvm-project f819f46284f2a79790038e1f6649172789734ae8)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250430/202504301314.NaE4JGVw-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202504301314.NaE4JGVw-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> kernel/kexec_pe_image.c:219:48: warning: format specifies type 'unsigned long' but the argument has type 'struct mem_range_result *' [-Wformat]
     219 |         pr_info("%s, return range 0x%lx\n", __func__, range);
         |                                     ~~~               ^~~~~
   include/linux/printk.h:580:34: note: expanded from macro 'pr_info'
     580 |         printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
         |                                 ~~~     ^~~~~~~~~~~
   include/linux/printk.h:507:60: note: expanded from macro 'printk'
     507 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
         |                                                     ~~~    ^~~~~~~~~~~
   include/linux/printk.h:479:19: note: expanded from macro 'printk_index_wrap'
     479 |                 _p_func(_fmt, ##__VA_ARGS__);                           \
         |                         ~~~~    ^~~~~~~~~~~
>> kernel/kexec_pe_image.c:158:9: warning: unused variable 'flush' [-Wunused-variable]
     158 |         long (*flush)(void*, unsigned long) = NULL;
         |                ^~~~~
>> kernel/kexec_pe_image.c:399:22: warning: unknown attribute 'optimize' ignored [-Wunknown-attributes]
     399 | __attribute__((used, optimize("O0"))) void bpf_handle_pefile(char *image, int image_sz,
         |                      ^~~~~~~~~~~~~~
>> kernel/kexec_pe_image.c:399:44: warning: no previous prototype for function 'bpf_handle_pefile' [-Wmissing-prototypes]
     399 | __attribute__((used, optimize("O0"))) void bpf_handle_pefile(char *image, int image_sz,
         |                                            ^
   kernel/kexec_pe_image.c:399:39: note: declare 'static' if the function is not intended to be used outside of this translation unit
     399 | __attribute__((used, optimize("O0"))) void bpf_handle_pefile(char *image, int image_sz,
         |                                       ^
         |                                       static 
   kernel/kexec_pe_image.c:404:22: warning: unknown attribute 'optimize' ignored [-Wunknown-attributes]
     404 | __attribute__((used, optimize("O0"))) void bpf_post_handle_pefile(void)
         |                      ^~~~~~~~~~~~~~
>> kernel/kexec_pe_image.c:404:44: warning: no previous prototype for function 'bpf_post_handle_pefile' [-Wmissing-prototypes]
     404 | __attribute__((used, optimize("O0"))) void bpf_post_handle_pefile(void)
         |                                            ^
   kernel/kexec_pe_image.c:404:39: note: declare 'static' if the function is not intended to be used outside of this translation unit
     404 | __attribute__((used, optimize("O0"))) void bpf_post_handle_pefile(void)
         |                                       ^
         |                                       static 
>> kernel/kexec_pe_image.c:529:7: warning: expression which evaluates to zero treated as a null pointer constant of type 'char *' [-Wnon-literal-null-conversion]
     529 |                 c = '\0';
         |                     ^~~~
>> kernel/kexec_pe_image.c:446:37: warning: variable 'cmdline_sz' set but not used [-Wunused-but-set-variable]
     446 |         unsigned long linux_sz, initrd_sz, cmdline_sz, bpf_sz;
         |                                            ^
   kernel/kexec_pe_image.c:90:13: warning: unused function 'flush_buffer' [-Wunused-function]
      90 | static long flush_buffer(void *buf, unsigned long len)
         |             ^~~~~~~~~~~~
   9 warnings generated.

Kconfig warnings: (for reference only)
   WARNING: unmet direct dependencies detected for KEXEC_PE_IMAGE
   Depends on [n]: KEXEC_FILE [=y] && DEBUG_INFO_BTF [=n] && BPF_SYSCALL [=y]
   Selected by [y]:
   - ARCH_SELECTS_KEXEC_FILE [=y] && KEXEC_FILE [=y]


vim +219 kernel/kexec_pe_image.c

318ac91dd61443 Pingfan Liu 2025-04-29  152  
318ac91dd61443 Pingfan Liu 2025-04-29  153  __bpf_kfunc struct mem_range_result *bpf_kexec_decompress(char *image_gz_payload, int image_gz_sz,
318ac91dd61443 Pingfan Liu 2025-04-29  154  			unsigned int expected_decompressed_sz)
318ac91dd61443 Pingfan Liu 2025-04-29  155  {
318ac91dd61443 Pingfan Liu 2025-04-29  156  	decompress_fn decompressor;
318ac91dd61443 Pingfan Liu 2025-04-29  157  	//todo, use flush to cap the memory size used by decompression
318ac91dd61443 Pingfan Liu 2025-04-29 @158  	long (*flush)(void*, unsigned long) = NULL;
318ac91dd61443 Pingfan Liu 2025-04-29  159  	struct mem_range_result *range;
318ac91dd61443 Pingfan Liu 2025-04-29  160  	const char *name;
318ac91dd61443 Pingfan Liu 2025-04-29  161  	void *output_buf;
318ac91dd61443 Pingfan Liu 2025-04-29  162  	char *input_buf;
318ac91dd61443 Pingfan Liu 2025-04-29  163  	int ret;
318ac91dd61443 Pingfan Liu 2025-04-29  164  
318ac91dd61443 Pingfan Liu 2025-04-29  165  	range = kmalloc(sizeof(struct mem_range_result), GFP_KERNEL);
318ac91dd61443 Pingfan Liu 2025-04-29  166  	if (!range) {
318ac91dd61443 Pingfan Liu 2025-04-29  167  		pr_err("fail to allocate mem_range_result\n");
318ac91dd61443 Pingfan Liu 2025-04-29  168  		return NULL;
318ac91dd61443 Pingfan Liu 2025-04-29  169  	}
318ac91dd61443 Pingfan Liu 2025-04-29  170  	refcount_set(&range->usage, 1);
318ac91dd61443 Pingfan Liu 2025-04-29  171  
318ac91dd61443 Pingfan Liu 2025-04-29  172  	input_buf = vmalloc(image_gz_sz);
318ac91dd61443 Pingfan Liu 2025-04-29  173  	if (!input_buf) {
318ac91dd61443 Pingfan Liu 2025-04-29  174  		pr_err("fail to allocate input buffer\n");
318ac91dd61443 Pingfan Liu 2025-04-29  175  		kfree(range);
318ac91dd61443 Pingfan Liu 2025-04-29  176  		return NULL;
318ac91dd61443 Pingfan Liu 2025-04-29  177  	}
318ac91dd61443 Pingfan Liu 2025-04-29  178  
318ac91dd61443 Pingfan Liu 2025-04-29  179  	ret = copy_from_kernel_nofault(input_buf, image_gz_payload, image_gz_sz);
318ac91dd61443 Pingfan Liu 2025-04-29  180  	if (ret < 0) {
318ac91dd61443 Pingfan Liu 2025-04-29  181  		pr_err("Error when copying from 0x%px, size:0x%x\n",
318ac91dd61443 Pingfan Liu 2025-04-29  182  				image_gz_payload, image_gz_sz);
318ac91dd61443 Pingfan Liu 2025-04-29  183  		kfree(range);
318ac91dd61443 Pingfan Liu 2025-04-29  184  		vfree(input_buf);
318ac91dd61443 Pingfan Liu 2025-04-29  185  		return NULL;
318ac91dd61443 Pingfan Liu 2025-04-29  186  	}
318ac91dd61443 Pingfan Liu 2025-04-29  187  
318ac91dd61443 Pingfan Liu 2025-04-29  188  	output_buf = vmalloc(expected_decompressed_sz);
318ac91dd61443 Pingfan Liu 2025-04-29  189  	if (!output_buf) {
318ac91dd61443 Pingfan Liu 2025-04-29  190  		pr_err("fail to allocate output buffer\n");
318ac91dd61443 Pingfan Liu 2025-04-29  191  		kfree(range);
318ac91dd61443 Pingfan Liu 2025-04-29  192  		vfree(input_buf);
318ac91dd61443 Pingfan Liu 2025-04-29  193  		return NULL;
318ac91dd61443 Pingfan Liu 2025-04-29  194  	}
318ac91dd61443 Pingfan Liu 2025-04-29  195  
318ac91dd61443 Pingfan Liu 2025-04-29  196  	decompressor = decompress_method(input_buf, image_gz_sz, &name);
318ac91dd61443 Pingfan Liu 2025-04-29  197  	if (!decompressor) {
318ac91dd61443 Pingfan Liu 2025-04-29  198  		pr_err("Can not find decompress method\n");
318ac91dd61443 Pingfan Liu 2025-04-29  199  		kfree(range);
318ac91dd61443 Pingfan Liu 2025-04-29  200  		vfree(input_buf);
318ac91dd61443 Pingfan Liu 2025-04-29  201  		vfree(output_buf);
318ac91dd61443 Pingfan Liu 2025-04-29  202  		return NULL;
318ac91dd61443 Pingfan Liu 2025-04-29  203  	}
318ac91dd61443 Pingfan Liu 2025-04-29  204  	//to do, use flush
318ac91dd61443 Pingfan Liu 2025-04-29  205  	ret = decompressor(image_gz_payload, image_gz_sz, NULL, NULL,
318ac91dd61443 Pingfan Liu 2025-04-29  206  				output_buf, NULL, NULL);
318ac91dd61443 Pingfan Liu 2025-04-29  207  
318ac91dd61443 Pingfan Liu 2025-04-29  208  	/* Update the range map */
318ac91dd61443 Pingfan Liu 2025-04-29  209  	if (ret == 0) {
318ac91dd61443 Pingfan Liu 2025-04-29  210  		range->buf = output_buf;
318ac91dd61443 Pingfan Liu 2025-04-29  211  		range->size = expected_decompressed_sz;
318ac91dd61443 Pingfan Liu 2025-04-29  212  		range->status = 0;
318ac91dd61443 Pingfan Liu 2025-04-29  213  	} else {
318ac91dd61443 Pingfan Liu 2025-04-29  214  		pr_err("Decompress error\n");
318ac91dd61443 Pingfan Liu 2025-04-29  215  		vfree(output_buf);
318ac91dd61443 Pingfan Liu 2025-04-29  216  		kfree(range);
318ac91dd61443 Pingfan Liu 2025-04-29  217  		return NULL;
318ac91dd61443 Pingfan Liu 2025-04-29  218  	}
318ac91dd61443 Pingfan Liu 2025-04-29 @219  	pr_info("%s, return range 0x%lx\n", __func__, range);
318ac91dd61443 Pingfan Liu 2025-04-29  220  	return range;
318ac91dd61443 Pingfan Liu 2025-04-29  221  }
318ac91dd61443 Pingfan Liu 2025-04-29  222  
318ac91dd61443 Pingfan Liu 2025-04-29  223  __bpf_kfunc int bpf_kexec_result_release(struct mem_range_result *result)
318ac91dd61443 Pingfan Liu 2025-04-29  224  {
318ac91dd61443 Pingfan Liu 2025-04-29  225  	if (!result) {
318ac91dd61443 Pingfan Liu 2025-04-29  226  		pr_err("%s, receive invalid range\n", __func__);
318ac91dd61443 Pingfan Liu 2025-04-29  227  		return -EINVAL;
318ac91dd61443 Pingfan Liu 2025-04-29  228  	}
318ac91dd61443 Pingfan Liu 2025-04-29  229  
318ac91dd61443 Pingfan Liu 2025-04-29  230  	if (refcount_dec_and_test(&result->usage)) {
318ac91dd61443 Pingfan Liu 2025-04-29  231  		vfree(result->buf);
318ac91dd61443 Pingfan Liu 2025-04-29  232  		kfree(result);
318ac91dd61443 Pingfan Liu 2025-04-29  233  	}
318ac91dd61443 Pingfan Liu 2025-04-29  234  
318ac91dd61443 Pingfan Liu 2025-04-29  235  	return 0;
318ac91dd61443 Pingfan Liu 2025-04-29  236  }
318ac91dd61443 Pingfan Liu 2025-04-29  237  
318ac91dd61443 Pingfan Liu 2025-04-29  238  __bpf_kfunc_end_defs();
318ac91dd61443 Pingfan Liu 2025-04-29  239  
2e57f9ba29ca48 Pingfan Liu 2025-04-29  240  static bool is_valid_pe(const char *kernel_buf, unsigned long kernel_len)
2e57f9ba29ca48 Pingfan Liu 2025-04-29  241  {
2e57f9ba29ca48 Pingfan Liu 2025-04-29  242  	struct mz_hdr *mz;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  243  	struct pe_hdr *pe;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  244  
2e57f9ba29ca48 Pingfan Liu 2025-04-29  245  	if (!kernel_buf)
2e57f9ba29ca48 Pingfan Liu 2025-04-29  246  		return false;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  247  	mz = (struct mz_hdr *)kernel_buf;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  248  	if (mz->magic != MZ_MAGIC)
2e57f9ba29ca48 Pingfan Liu 2025-04-29  249  		return false;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  250  	pe = (struct pe_hdr *)(kernel_buf + mz->peaddr);
2e57f9ba29ca48 Pingfan Liu 2025-04-29  251  	if (pe->magic != PE_MAGIC)
2e57f9ba29ca48 Pingfan Liu 2025-04-29  252  		return false;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  253  	if (pe->opt_hdr_size == 0) {
2e57f9ba29ca48 Pingfan Liu 2025-04-29  254  		pr_err("optional header is missing\n");
2e57f9ba29ca48 Pingfan Liu 2025-04-29  255  		return false;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  256  	}
2e57f9ba29ca48 Pingfan Liu 2025-04-29  257  
2e57f9ba29ca48 Pingfan Liu 2025-04-29  258  	return true;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  259  }
2e57f9ba29ca48 Pingfan Liu 2025-04-29  260  
2e57f9ba29ca48 Pingfan Liu 2025-04-29  261  static bool is_valid_format(const char *kernel_buf, unsigned long kernel_len)
2e57f9ba29ca48 Pingfan Liu 2025-04-29  262  {
2e57f9ba29ca48 Pingfan Liu 2025-04-29  263  	return is_valid_pe(kernel_buf, kernel_len);
2e57f9ba29ca48 Pingfan Liu 2025-04-29  264  }
2e57f9ba29ca48 Pingfan Liu 2025-04-29  265  
2e57f9ba29ca48 Pingfan Liu 2025-04-29  266  /*
2e57f9ba29ca48 Pingfan Liu 2025-04-29  267   * The UEFI Terse Executable (TE) image has MZ header.
2e57f9ba29ca48 Pingfan Liu 2025-04-29  268   */
2e57f9ba29ca48 Pingfan Liu 2025-04-29  269  static int pe_image_probe(const char *kernel_buf, unsigned long kernel_len)
2e57f9ba29ca48 Pingfan Liu 2025-04-29  270  {
2e57f9ba29ca48 Pingfan Liu 2025-04-29  271  	return is_valid_pe(kernel_buf, kernel_len) ? 0 : -1;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  272  }
2e57f9ba29ca48 Pingfan Liu 2025-04-29  273  
2e57f9ba29ca48 Pingfan Liu 2025-04-29  274  static int get_pe_section(char *file_buf, const char *sect_name,
2e57f9ba29ca48 Pingfan Liu 2025-04-29  275  		char **sect_start, unsigned long *sect_sz)
2e57f9ba29ca48 Pingfan Liu 2025-04-29  276  {
2e57f9ba29ca48 Pingfan Liu 2025-04-29  277  	struct pe_hdr *pe_hdr;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  278  	struct pe32plus_opt_hdr *opt_hdr;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  279  	struct section_header *sect_hdr;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  280  	int section_nr, i;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  281  	struct mz_hdr *mz = (struct mz_hdr *)file_buf;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  282  
2e57f9ba29ca48 Pingfan Liu 2025-04-29  283  	*sect_start = NULL;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  284  	*sect_sz = 0;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  285  	pe_hdr = (struct pe_hdr *)(file_buf + mz->peaddr);
2e57f9ba29ca48 Pingfan Liu 2025-04-29  286  	section_nr = pe_hdr->sections;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  287  	opt_hdr = (struct pe32plus_opt_hdr *)(file_buf + mz->peaddr + sizeof(struct pe_hdr));
2e57f9ba29ca48 Pingfan Liu 2025-04-29  288  	sect_hdr = (struct section_header *)((char *)opt_hdr + pe_hdr->opt_hdr_size);
2e57f9ba29ca48 Pingfan Liu 2025-04-29  289  
2e57f9ba29ca48 Pingfan Liu 2025-04-29  290  	for (i = 0; i < section_nr; i++) {
2e57f9ba29ca48 Pingfan Liu 2025-04-29  291  		if (strcmp(sect_hdr->name, sect_name) == 0) {
2e57f9ba29ca48 Pingfan Liu 2025-04-29  292  			*sect_start = file_buf + sect_hdr->data_addr;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  293  			*sect_sz = sect_hdr->raw_data_size;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  294  			return 0;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  295  		}
2e57f9ba29ca48 Pingfan Liu 2025-04-29  296  		sect_hdr++;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  297  	}
2e57f9ba29ca48 Pingfan Liu 2025-04-29  298  
2e57f9ba29ca48 Pingfan Liu 2025-04-29  299  	return -1;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  300  }
2e57f9ba29ca48 Pingfan Liu 2025-04-29  301  
2e57f9ba29ca48 Pingfan Liu 2025-04-29  302  static bool pe_has_bpf_section(char *file_buf, unsigned long pe_sz)
2e57f9ba29ca48 Pingfan Liu 2025-04-29  303  {
2e57f9ba29ca48 Pingfan Liu 2025-04-29  304  	char *sect_start = NULL;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  305  	unsigned long sect_sz = 0;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  306  	int ret;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  307  
2e57f9ba29ca48 Pingfan Liu 2025-04-29  308  	ret = get_pe_section(file_buf, ".bpf", &sect_start, &sect_sz);
2e57f9ba29ca48 Pingfan Liu 2025-04-29  309  	if (ret < 0)
2e57f9ba29ca48 Pingfan Liu 2025-04-29  310  		return false;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  311  	return true;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  312  }
2e57f9ba29ca48 Pingfan Liu 2025-04-29  313  
5e8d32eeac7956 Pingfan Liu 2025-04-29  314  static struct kexec_pe_parser_bpf *pe_parser;
5e8d32eeac7956 Pingfan Liu 2025-04-29  315  
5e8d32eeac7956 Pingfan Liu 2025-04-29  316  static void *get_symbol_from_elf(const char *elf_data, size_t elf_size,
5e8d32eeac7956 Pingfan Liu 2025-04-29  317  		const char *symbol_name, unsigned int *symbol_size)
5e8d32eeac7956 Pingfan Liu 2025-04-29  318  {
5e8d32eeac7956 Pingfan Liu 2025-04-29  319  	Elf_Ehdr *ehdr = (Elf_Ehdr *)elf_data;
5e8d32eeac7956 Pingfan Liu 2025-04-29  320  	Elf_Shdr *shdr, *symtab_shdr, *strtab_shdr, *dst_shdr;
5e8d32eeac7956 Pingfan Liu 2025-04-29  321  	Elf64_Sym *sym, *symtab = NULL;
5e8d32eeac7956 Pingfan Liu 2025-04-29  322  	char *strtab = NULL;
5e8d32eeac7956 Pingfan Liu 2025-04-29  323  	void *symbol_data = NULL;
5e8d32eeac7956 Pingfan Liu 2025-04-29  324  	int i;
5e8d32eeac7956 Pingfan Liu 2025-04-29  325  
5e8d32eeac7956 Pingfan Liu 2025-04-29  326  	symtab_shdr = strtab_shdr = NULL;
5e8d32eeac7956 Pingfan Liu 2025-04-29  327  	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
5e8d32eeac7956 Pingfan Liu 2025-04-29  328  		pr_err("Not a valid ELF file\n");
5e8d32eeac7956 Pingfan Liu 2025-04-29  329  		goto out;
5e8d32eeac7956 Pingfan Liu 2025-04-29  330  	}
5e8d32eeac7956 Pingfan Liu 2025-04-29  331  
5e8d32eeac7956 Pingfan Liu 2025-04-29  332  	shdr = (struct elf_shdr *)(elf_data + ehdr->e_shoff);
5e8d32eeac7956 Pingfan Liu 2025-04-29  333  	for (i = 0; i < ehdr->e_shnum; i++) {
5e8d32eeac7956 Pingfan Liu 2025-04-29  334  		if (shdr[i].sh_type == SHT_SYMTAB) {
5e8d32eeac7956 Pingfan Liu 2025-04-29  335  			symtab_shdr = &shdr[i];
5e8d32eeac7956 Pingfan Liu 2025-04-29  336  		} else if (shdr[i].sh_type == SHT_STRTAB && i != ehdr->e_shstrndx) {
5e8d32eeac7956 Pingfan Liu 2025-04-29  337  			strtab_shdr = &shdr[i];
5e8d32eeac7956 Pingfan Liu 2025-04-29  338  		}
5e8d32eeac7956 Pingfan Liu 2025-04-29  339  	}
5e8d32eeac7956 Pingfan Liu 2025-04-29  340  
5e8d32eeac7956 Pingfan Liu 2025-04-29  341  	if (!symtab_shdr || !strtab_shdr) {
5e8d32eeac7956 Pingfan Liu 2025-04-29  342  		pr_err("Symbol table or string table not found\n");
5e8d32eeac7956 Pingfan Liu 2025-04-29  343  		goto out;
5e8d32eeac7956 Pingfan Liu 2025-04-29  344  	}
5e8d32eeac7956 Pingfan Liu 2025-04-29  345  	symtab = (Elf64_Sym *)(elf_data + symtab_shdr->sh_offset);
5e8d32eeac7956 Pingfan Liu 2025-04-29  346  	strtab = (char *)(elf_data + strtab_shdr->sh_offset);
5e8d32eeac7956 Pingfan Liu 2025-04-29  347  	for (i = 0; i < symtab_shdr->sh_size / sizeof(Elf64_Sym); i++) {
5e8d32eeac7956 Pingfan Liu 2025-04-29  348  		sym = &symtab[i];
5e8d32eeac7956 Pingfan Liu 2025-04-29  349  		if (strcmp(&strtab[sym->st_name], symbol_name) == 0) {
5e8d32eeac7956 Pingfan Liu 2025-04-29  350  			if (sym->st_shndx >= SHN_LORESERVE)
5e8d32eeac7956 Pingfan Liu 2025-04-29  351  			    return NULL; // No section data for these
5e8d32eeac7956 Pingfan Liu 2025-04-29  352  			dst_shdr = &shdr[sym->st_shndx];
5e8d32eeac7956 Pingfan Liu 2025-04-29  353  			symbol_data = (void *)(elf_data + dst_shdr->sh_offset + sym->st_value);
5e8d32eeac7956 Pingfan Liu 2025-04-29  354  			*symbol_size = symtab[i].st_size;
5e8d32eeac7956 Pingfan Liu 2025-04-29  355  			break;
5e8d32eeac7956 Pingfan Liu 2025-04-29  356  		}
5e8d32eeac7956 Pingfan Liu 2025-04-29  357  	}
5e8d32eeac7956 Pingfan Liu 2025-04-29  358  
5e8d32eeac7956 Pingfan Liu 2025-04-29  359  out:
5e8d32eeac7956 Pingfan Liu 2025-04-29  360      return symbol_data;
5e8d32eeac7956 Pingfan Liu 2025-04-29  361  }
5e8d32eeac7956 Pingfan Liu 2025-04-29  362  
2e57f9ba29ca48 Pingfan Liu 2025-04-29  363  /* Load a ELF */
2e57f9ba29ca48 Pingfan Liu 2025-04-29  364  static int arm_bpf_prog(char *bpf_elf, unsigned long sz)
2e57f9ba29ca48 Pingfan Liu 2025-04-29  365  {
5e8d32eeac7956 Pingfan Liu 2025-04-29  366  	opts_data = get_symbol_from_elf(bpf_elf, sz, "opts_data", &opts_data_sz);
5e8d32eeac7956 Pingfan Liu 2025-04-29  367  	opts_insn = get_symbol_from_elf(bpf_elf, sz, "opts_insn", &opts_insn_sz);
5e8d32eeac7956 Pingfan Liu 2025-04-29  368  	if (!opts_data || !opts_insn)
5e8d32eeac7956 Pingfan Liu 2025-04-29  369  		return -1;
5e8d32eeac7956 Pingfan Liu 2025-04-29  370  	/*
5e8d32eeac7956 Pingfan Liu 2025-04-29  371  	 * When light skeleton generates opts_data[] and opts_insn[], it appends a
5e8d32eeac7956 Pingfan Liu 2025-04-29  372  	 * NULL terminator at the end of string
5e8d32eeac7956 Pingfan Liu 2025-04-29  373  	 */
5e8d32eeac7956 Pingfan Liu 2025-04-29  374  	opts_data_sz = opts_data_sz - 1;
5e8d32eeac7956 Pingfan Liu 2025-04-29  375  	opts_insn_sz = opts_insn_sz - 1;
5e8d32eeac7956 Pingfan Liu 2025-04-29  376  
5e8d32eeac7956 Pingfan Liu 2025-04-29  377  	pe_parser = kexec_pe_parser_bpf__open_and_load();
5e8d32eeac7956 Pingfan Liu 2025-04-29  378  	if (!pe_parser)
5e8d32eeac7956 Pingfan Liu 2025-04-29  379  		return -1;
5e8d32eeac7956 Pingfan Liu 2025-04-29  380  	kexec_pe_parser_bpf__attach(pe_parser);
5e8d32eeac7956 Pingfan Liu 2025-04-29  381  
2e57f9ba29ca48 Pingfan Liu 2025-04-29  382  	return 0;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  383  }
2e57f9ba29ca48 Pingfan Liu 2025-04-29  384  
2e57f9ba29ca48 Pingfan Liu 2025-04-29  385  static void disarm_bpf_prog(void)
2e57f9ba29ca48 Pingfan Liu 2025-04-29  386  {
5e8d32eeac7956 Pingfan Liu 2025-04-29  387  	kexec_pe_parser_bpf__destroy(pe_parser);
5e8d32eeac7956 Pingfan Liu 2025-04-29  388  	pe_parser = NULL;
5e8d32eeac7956 Pingfan Liu 2025-04-29  389  	opts_data = NULL;
5e8d32eeac7956 Pingfan Liu 2025-04-29  390  	opts_insn = NULL;
2e57f9ba29ca48 Pingfan Liu 2025-04-29  391  }
2e57f9ba29ca48 Pingfan Liu 2025-04-29  392  
2e57f9ba29ca48 Pingfan Liu 2025-04-29  393  /*
2e57f9ba29ca48 Pingfan Liu 2025-04-29  394   * In eBPF, functions can only pass up to five arguments through R1 to R5.
2e57f9ba29ca48 Pingfan Liu 2025-04-29  395   * If five arguments are not enough, considering parse_zboot(struct pt_regs *regs)
2e57f9ba29ca48 Pingfan Liu 2025-04-29  396   *
2e57f9ba29ca48 Pingfan Liu 2025-04-29  397   * optimize("O0") prevents inline, compiler constant propagation
2e57f9ba29ca48 Pingfan Liu 2025-04-29  398   */
2e57f9ba29ca48 Pingfan Liu 2025-04-29 @399  __attribute__((used, optimize("O0"))) void bpf_handle_pefile(char *image, int image_sz,
2e57f9ba29ca48 Pingfan Liu 2025-04-29  400  			char *initrd, int initrd_sz, char *cmdline)
2e57f9ba29ca48 Pingfan Liu 2025-04-29  401  {
2e57f9ba29ca48 Pingfan Liu 2025-04-29  402  }
2e57f9ba29ca48 Pingfan Liu 2025-04-29  403  
2e57f9ba29ca48 Pingfan Liu 2025-04-29 @404  __attribute__((used, optimize("O0"))) void bpf_post_handle_pefile(void)
2e57f9ba29ca48 Pingfan Liu 2025-04-29  405  {
2e57f9ba29ca48 Pingfan Liu 2025-04-29  406  }
2e57f9ba29ca48 Pingfan Liu 2025-04-29  407  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFCv2 4/7] bpf/kexec: Introduce three bpf kfunc for kexec
  2025-04-30  0:03   ` Alexei Starovoitov
@ 2025-04-30 10:47     ` Pingfan Liu
  2025-04-30 16:16       ` Alexei Starovoitov
  0 siblings, 1 reply; 13+ messages in thread
From: Pingfan Liu @ 2025-04-30 10:47 UTC (permalink / raw)
  To: Alexei Starovoitov
  Cc: bpf, kexec, Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Jeremy Linton, Catalin Marinas, Will Deacon,
	Ard Biesheuvel, Simon Horman, Gerd Hoffmann, Vitaly Kuznetsov,
	Philipp Rudo, Viktor Malik, Jan Hendrik Farr, Baoquan He,
	Dave Young, Eric Biederman, Andrew Morton, KP Singh,
	Stanislav Fomichev, Hao Luo, Jiri Olsa

On Wed, Apr 30, 2025 at 8:04 AM Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
>
> On Mon, Apr 28, 2025 at 9:13 PM Pingfan Liu <piliu@redhat.com> wrote:
>  +__bpf_kfunc struct mem_range_result *bpf_kexec_decompress(char
> *image_gz_payload, int image_gz_sz,
> > +                       unsigned int expected_decompressed_sz)
> > +{
> > +       decompress_fn decompressor;
> > +       //todo, use flush to cap the memory size used by decompression
> > +       long (*flush)(void*, unsigned long) = NULL;
> > +       struct mem_range_result *range;
> > +       const char *name;
> > +       void *output_buf;
> > +       char *input_buf;
> > +       int ret;
> > +
> > +       range = kmalloc(sizeof(struct mem_range_result), GFP_KERNEL);
> > +       if (!range) {
> > +               pr_err("fail to allocate mem_range_result\n");
> > +               return NULL;
> > +       }
> > +       refcount_set(&range->usage, 1);
> > +
> > +       input_buf = vmalloc(image_gz_sz);
> > +       if (!input_buf) {
> > +               pr_err("fail to allocate input buffer\n");
> > +               kfree(range);
> > +               return NULL;
> > +       }
> > +
> > +       ret = copy_from_kernel_nofault(input_buf, image_gz_payload, image_gz_sz);
> > +       if (ret < 0) {
> > +               pr_err("Error when copying from 0x%px, size:0x%x\n",
> > +                               image_gz_payload, image_gz_sz);
> > +               kfree(range);
> > +               vfree(input_buf);
> > +               return NULL;
> > +       }
> > +
> > +       output_buf = vmalloc(expected_decompressed_sz);
> > +       if (!output_buf) {
> > +               pr_err("fail to allocate output buffer\n");
> > +               kfree(range);
> > +               vfree(input_buf);
> > +               return NULL;
> > +       }
> > +
> > +       decompressor = decompress_method(input_buf, image_gz_sz, &name);
> > +       if (!decompressor) {
> > +               pr_err("Can not find decompress method\n");
> > +               kfree(range);
> > +               vfree(input_buf);
> > +               vfree(output_buf);
> > +               return NULL;
> > +       }
> > +       //to do, use flush
> > +       ret = decompressor(image_gz_payload, image_gz_sz, NULL, NULL,
> > +                               output_buf, NULL, NULL);
> > +
> > +       /* Update the range map */
> > +       if (ret == 0) {
> > +               range->buf = output_buf;
> > +               range->size = expected_decompressed_sz;
> > +               range->status = 0;
> > +       } else {
> > +               pr_err("Decompress error\n");
> > +               vfree(output_buf);
> > +               kfree(range);
> > +               return NULL;
> > +       }
> > +       pr_info("%s, return range 0x%lx\n", __func__, range);
> > +       return range;
> > +}
>
> These kfuncs look like generic decompress routines.
> They're not related to kexec and probably should be in kernel/bpf/helpers.c
> or kernel/bpf/compression.c instead of kernel/kexec_pe_image.c.
>

Thanks for your suggestion. I originally considered using these kfuncs
only in kexec context (Later, introducing a dedicated BPF_PROG_TYPE
for kexec). They are placed under a lock so that a malice attack can
not exhaust the memory through repeatedly calling to the decompress
kfunc.

To generalize these kfunc, I think I can add some boundary control of
the memory usage to prevent such attacks.

> They also must be KF_SLEEPABLE.
> Please test your patches with all kernel debugs enabled.
> Otherwise you would have seen all these "sleeping while atomic"
> issues yourself.
>

See, I will have all these debug options for the V3 test.

Appreciate your insight.

Regards,

Pingfan


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFCv2 4/7] bpf/kexec: Introduce three bpf kfunc for kexec
  2025-04-30 10:47     ` Pingfan Liu
@ 2025-04-30 16:16       ` Alexei Starovoitov
  2025-05-06  0:37         ` Pingfan Liu
  0 siblings, 1 reply; 13+ messages in thread
From: Alexei Starovoitov @ 2025-04-30 16:16 UTC (permalink / raw)
  To: Pingfan Liu
  Cc: bpf, kexec, Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Jeremy Linton, Catalin Marinas, Will Deacon,
	Ard Biesheuvel, Simon Horman, Gerd Hoffmann, Vitaly Kuznetsov,
	Philipp Rudo, Viktor Malik, Jan Hendrik Farr, Baoquan He,
	Dave Young, Eric Biederman, Andrew Morton, KP Singh,
	Stanislav Fomichev, Hao Luo, Jiri Olsa

On Wed, Apr 30, 2025 at 3:47 AM Pingfan Liu <piliu@redhat.com> wrote:
>
> On Wed, Apr 30, 2025 at 8:04 AM Alexei Starovoitov
> <alexei.starovoitov@gmail.com> wrote:
> >
> > On Mon, Apr 28, 2025 at 9:13 PM Pingfan Liu <piliu@redhat.com> wrote:
> >  +__bpf_kfunc struct mem_range_result *bpf_kexec_decompress(char
> > *image_gz_payload, int image_gz_sz,
> > > +                       unsigned int expected_decompressed_sz)
> > > +{
> > > +       decompress_fn decompressor;
> > > +       //todo, use flush to cap the memory size used by decompression
> > > +       long (*flush)(void*, unsigned long) = NULL;
> > > +       struct mem_range_result *range;
> > > +       const char *name;
> > > +       void *output_buf;
> > > +       char *input_buf;
> > > +       int ret;
> > > +
> > > +       range = kmalloc(sizeof(struct mem_range_result), GFP_KERNEL);
> > > +       if (!range) {
> > > +               pr_err("fail to allocate mem_range_result\n");
> > > +               return NULL;
> > > +       }
> > > +       refcount_set(&range->usage, 1);
> > > +
> > > +       input_buf = vmalloc(image_gz_sz);
> > > +       if (!input_buf) {
> > > +               pr_err("fail to allocate input buffer\n");
> > > +               kfree(range);
> > > +               return NULL;
> > > +       }
> > > +
> > > +       ret = copy_from_kernel_nofault(input_buf, image_gz_payload, image_gz_sz);
> > > +       if (ret < 0) {
> > > +               pr_err("Error when copying from 0x%px, size:0x%x\n",
> > > +                               image_gz_payload, image_gz_sz);
> > > +               kfree(range);
> > > +               vfree(input_buf);
> > > +               return NULL;
> > > +       }
> > > +
> > > +       output_buf = vmalloc(expected_decompressed_sz);
> > > +       if (!output_buf) {
> > > +               pr_err("fail to allocate output buffer\n");
> > > +               kfree(range);
> > > +               vfree(input_buf);
> > > +               return NULL;
> > > +       }
> > > +
> > > +       decompressor = decompress_method(input_buf, image_gz_sz, &name);
> > > +       if (!decompressor) {
> > > +               pr_err("Can not find decompress method\n");
> > > +               kfree(range);
> > > +               vfree(input_buf);
> > > +               vfree(output_buf);
> > > +               return NULL;
> > > +       }
> > > +       //to do, use flush
> > > +       ret = decompressor(image_gz_payload, image_gz_sz, NULL, NULL,
> > > +                               output_buf, NULL, NULL);
> > > +
> > > +       /* Update the range map */
> > > +       if (ret == 0) {
> > > +               range->buf = output_buf;
> > > +               range->size = expected_decompressed_sz;
> > > +               range->status = 0;
> > > +       } else {
> > > +               pr_err("Decompress error\n");
> > > +               vfree(output_buf);
> > > +               kfree(range);
> > > +               return NULL;
> > > +       }
> > > +       pr_info("%s, return range 0x%lx\n", __func__, range);
> > > +       return range;
> > > +}
> >
> > These kfuncs look like generic decompress routines.
> > They're not related to kexec and probably should be in kernel/bpf/helpers.c
> > or kernel/bpf/compression.c instead of kernel/kexec_pe_image.c.
> >
>
> Thanks for your suggestion. I originally considered using these kfuncs
> only in kexec context (Later, introducing a dedicated BPF_PROG_TYPE
> for kexec).

We do not add new prog types anymore.
They're frozen just like the list of helpers.

> They are placed under a lock so that a malice attack can
> not exhaust the memory through repeatedly calling to the decompress
> kfunc.

attack? This is all root only anyway and all memory is counted
towards memcg.
Make sure to use GFP_KERNEL_ACCOUNT and something similar
to bpf_map_get_memcg.

> To generalize these kfunc, I think I can add some boundary control of
> the memory usage to prevent such attacks.

Don't reinvent the wheel. memcg is the mechanism.

> > They also must be KF_SLEEPABLE.
> > Please test your patches with all kernel debugs enabled.
> > Otherwise you would have seen all these "sleeping while atomic"
> > issues yourself.
> >
>
> See, I will have all these debug options for the V3 test.
>
> Appreciate your insight.
>
> Regards,
>
> Pingfan
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFCv2 4/7] bpf/kexec: Introduce three bpf kfunc for kexec
  2025-04-30 16:16       ` Alexei Starovoitov
@ 2025-05-06  0:37         ` Pingfan Liu
  0 siblings, 0 replies; 13+ messages in thread
From: Pingfan Liu @ 2025-05-06  0:37 UTC (permalink / raw)
  To: Alexei Starovoitov
  Cc: bpf, kexec, Alexei Starovoitov, Daniel Borkmann, John Fastabend,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, Jeremy Linton, Catalin Marinas, Will Deacon,
	Ard Biesheuvel, Simon Horman, Gerd Hoffmann, Vitaly Kuznetsov,
	Philipp Rudo, Viktor Malik, Jan Hendrik Farr, Baoquan He,
	Dave Young, Eric Biederman, Andrew Morton, KP Singh,
	Stanislav Fomichev, Hao Luo, Jiri Olsa

Hi Alexei,

Sorry to reply late since I just got back from holiday.

On Thu, May 1, 2025 at 12:16 AM Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
>
> On Wed, Apr 30, 2025 at 3:47 AM Pingfan Liu <piliu@redhat.com> wrote:
> >
> > On Wed, Apr 30, 2025 at 8:04 AM Alexei Starovoitov
> > <alexei.starovoitov@gmail.com> wrote:
> > >
[...]

> >
> > Thanks for your suggestion. I originally considered using these kfuncs
> > only in kexec context (Later, introducing a dedicated BPF_PROG_TYPE
> > for kexec).
>
> We do not add new prog types anymore.
> They're frozen just like the list of helpers.
>

Got it.

> > They are placed under a lock so that a malice attack can
> > not exhaust the memory through repeatedly calling to the decompress
> > kfunc.
>
> attack? This is all root only anyway and all memory is counted
> towards memcg.
> Make sure to use GFP_KERNEL_ACCOUNT and something similar
> to bpf_map_get_memcg.
>

Your clarification makes sense. I will follow that guide.

> > To generalize these kfunc, I think I can add some boundary control of
> > the memory usage to prevent such attacks.
>
> Don't reinvent the wheel. memcg is the mechanism.
>

Sure. Thanks for your insight. It is helpful.

Best Regards,

Pingfan

> > > They also must be KF_SLEEPABLE.
> > > Please test your patches with all kernel debugs enabled.
> > > Otherwise you would have seen all these "sleeping while atomic"
> > > issues yourself.
> > >
> >
> > See, I will have all these debug options for the V3 test.
> >
> > Appreciate your insight.
> >
> > Regards,
> >
> > Pingfan
> >
>


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2025-05-06  0:38 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-29  4:12 [RFCv2 0/7] kexec: Use BPF lskel to enable kexec to load PE format boot image Pingfan Liu
2025-04-29  4:12 ` [RFCv2 1/7] kexec_file: Make kexec_image_load_default global visible Pingfan Liu
2025-04-29  4:12 ` [RFCv2 2/7] kexec: Introduce kexec_pe_image to parse and load PE file Pingfan Liu
2025-04-29  4:12 ` [RFCv2 3/7] lib/decompress: Keep decompressor when CONFIG_KEXEC_PE_IMAGE Pingfan Liu
2025-04-29  4:12 ` [RFCv2 4/7] bpf/kexec: Introduce three bpf kfunc for kexec Pingfan Liu
2025-04-30  0:03   ` Alexei Starovoitov
2025-04-30 10:47     ` Pingfan Liu
2025-04-30 16:16       ` Alexei Starovoitov
2025-05-06  0:37         ` Pingfan Liu
2025-04-29  4:12 ` [RFCv2 5/7] kexec: Introduce a bpf-prog lskel to parse PE file Pingfan Liu
2025-04-29  4:12 ` [RFCv2 6/7] kexec: Integrate bpf light skeleton to load zboot image Pingfan Liu
2025-04-29  4:12 ` [RFCv2 7/7] arm64/kexec: Add PE image format support Pingfan Liu
2025-04-30  5:35   ` kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.