* [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; 12+ 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] 12+ 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; 12+ 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] 12+ 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; 12+ 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", §_start, §_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] 12+ 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; 12+ 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] 12+ 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; 12+ 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] 12+ 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; 12+ 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] 12+ 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; 12+ 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] 12+ 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
6 siblings, 0 replies; 12+ 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] 12+ 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; 12+ 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] 12+ 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; 12+ 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] 12+ 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; 12+ 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] 12+ 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; 12+ 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] 12+ messages in thread
end of thread, other threads:[~2025-05-06 5:13 UTC | newest]
Thread overview: 12+ 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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).