All of lore.kernel.org
 help / color / mirror / Atom feed
From: Yusheng Zheng <yunwei356@gmail.com>
To: bpf@vger.kernel.org
Cc: Alexei Starovoitov <ast@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Andrii Nakryiko <andrii@kernel.org>,
	Eduard Zingerman <eddyz87@gmail.com>,
	Kumar Kartikeya Dwivedi <memxor@gmail.com>,
	Martin KaFai Lau <martin.lau@linux.dev>,
	Song Liu <song@kernel.org>,
	Yonghong Song <yonghong.song@linux.dev>,
	Jiri Olsa <jolsa@kernel.org>,
	John Fastabend <john.fastabend@gmail.com>,
	Emil Tsalapatis <emil@etsalapatis.com>,
	Ihor Solodrai <ihor.solodrai@linux.dev>,
	x86@kernel.org, Thomas Gleixner <tglx@kernel.org>,
	Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
	Dave Hansen <dave.hansen@linux.intel.com>,
	"H . Peter Anvin" <hpa@zytor.com>,
	Leon Hwang <leon.hwang@linux.dev>,
	Puranjay Mohan <puranjay@kernel.org>,
	Hao Sun <sunhao.th@gmail.com>,
	Yusheng Zheng <yunwei356@gmail.com>
Subject: [RFC PATCH bpf-next 4/7] bpf: Add kfuncs with bodies for common operations
Date: Mon,  5 Oct 2026 07:22:16 -0700	[thread overview]
Message-ID: <20261005142219.33451-5-yunwei356@gmail.com> (raw)
In-Reply-To: <20261005142219.33451-1-yunwei356@gmail.com>

Add kfuncs with bodies for the operation families evaluated in [1]:
bpf_rol64() (rotate), bpf_select64() (conditional select),
bpf_extract64() (bit field extract), bpf_load_be64() (big-endian load),
bpf_prefetch(), bpf_copy16() (16-byte copy) and bpf_lea64() (address
computation). They are in kernel/bpf/insn_kfuncs/, apart from the
verifier and the JITs, under the new CONFIG_BPF_INSN_KFUNCS, which can
be built in or as a module. The x86-64 JIT inlines copies of their
compiled code.

A prefetch is a load whose value is not used, so the verifier checks the
address like that of any load. bpf_copy16() loads both halves before it
stores them, like its body, so that a copy of it and the body agree
when the buffers overlap.

[1] https://arxiv.org/abs/2606.24213

Assisted-by: LLM
Signed-off-by: Yusheng Zheng <yunwei356@gmail.com>
---
 kernel/bpf/Kconfig                       |   1 +
 kernel/bpf/Makefile                      |   1 +
 kernel/bpf/insn_kfuncs/Kconfig           |  11 ++
 kernel/bpf/insn_kfuncs/Makefile          |   2 +
 kernel/bpf/insn_kfuncs/bpf_insn_kfuncs.c | 173 +++++++++++++++++++++++
 5 files changed, 188 insertions(+)
 create mode 100644 kernel/bpf/insn_kfuncs/Kconfig
 create mode 100644 kernel/bpf/insn_kfuncs/Makefile
 create mode 100644 kernel/bpf/insn_kfuncs/bpf_insn_kfuncs.c

diff --git a/kernel/bpf/Kconfig b/kernel/bpf/Kconfig
index 98493e32db2ad..ca0dbfa1f81c5 100644
--- a/kernel/bpf/Kconfig
+++ b/kernel/bpf/Kconfig
@@ -101,6 +101,7 @@ config BPF_CRYPTO
 	  data. The supported algorithms are AES-CBC and AES-ECB.
 
 source "kernel/bpf/preload/Kconfig"
+source "kernel/bpf/insn_kfuncs/Kconfig"
 
 config BPF_LSM
 	bool "Enable BPF LSM Instrumentation"
diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
index ae3d04dae2d33..94c81491a8e65 100644
--- a/kernel/bpf/Makefile
+++ b/kernel/bpf/Makefile
@@ -60,6 +60,7 @@ obj-${CONFIG_BPF_LSM} += bpf_lsm_proto.o bpf_lsm.o
 endif
 obj-$(CONFIG_BPF_CRYPTO) += crypto.o
 obj-$(CONFIG_BPF_PRELOAD) += preload/
+obj-$(CONFIG_BPF_INSN_KFUNCS) += insn_kfuncs/
 
 obj-$(CONFIG_BPF_SYSCALL) += relo_core.o
 obj-$(CONFIG_BPF_SYSCALL) += btf_iter.o
diff --git a/kernel/bpf/insn_kfuncs/Kconfig b/kernel/bpf/insn_kfuncs/Kconfig
new file mode 100644
index 0000000000000..b2469853899dc
--- /dev/null
+++ b/kernel/bpf/insn_kfuncs/Kconfig
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config BPF_INSN_KFUNCS
+	tristate "Kfuncs for CPU instructions that BPF lacks"
+	depends on BPF_SYSCALL && BPF_JIT && DEBUG_INFO_BTF
+	help
+	  Provide kfuncs for rotate, conditional select, bit field extract,
+	  big-endian load, prefetch, 16-byte copy and address computation.
+	  The verifier checks each call as the kfunc's BPF body, and the JIT
+	  puts native code in its place where it can.
+
+	  If unsure, say N.
diff --git a/kernel/bpf/insn_kfuncs/Makefile b/kernel/bpf/insn_kfuncs/Makefile
new file mode 100644
index 0000000000000..e397f626a17a8
--- /dev/null
+++ b/kernel/bpf/insn_kfuncs/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_BPF_INSN_KFUNCS) += bpf_insn_kfuncs.o
diff --git a/kernel/bpf/insn_kfuncs/bpf_insn_kfuncs.c b/kernel/bpf/insn_kfuncs/bpf_insn_kfuncs.c
new file mode 100644
index 0000000000000..1bcc049a5603f
--- /dev/null
+++ b/kernel/bpf/insn_kfuncs/bpf_insn_kfuncs.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kfuncs for CPU instructions that BPF lacks, with BPF bodies, see struct
+ * bpf_kfunc_body. Arguments named __k must be known constants.
+ */
+#include <linux/bitops.h>
+#include <linux/btf.h>
+#include <linux/btf_ids.h>
+#include <linux/filter.h>
+#include <linux/module.h>
+#include <linux/unaligned.h>
+
+__bpf_kfunc_start_defs();
+
+__bpf_kfunc u64 bpf_rol64(u64 x, u32 n__k)
+{
+	return rol64(x, n__k);
+}
+
+__bpf_kfunc u64 bpf_select64(u64 cond, u64 a, u64 b)
+{
+	return cond ? a : b;
+}
+
+__bpf_kfunc u64 bpf_extract64(u64 x, u32 start__k, u32 len__k)
+{
+	return x << (64 - start__k - len__k) >> (64 - len__k);
+}
+
+__bpf_kfunc u64 bpf_load_be64(const void *p, s32 off__k)
+{
+	return get_unaligned_be64(p + off__k);
+}
+
+__bpf_kfunc void bpf_prefetch(const void *p)
+{
+	/* not prefetch(), which boot-time alternatives may rewrite */
+	__builtin_prefetch(p);
+}
+
+__bpf_kfunc void bpf_copy16(void *dst, const void *src)
+{
+	/* both loads first, as in the body, in case the buffers overlap */
+	u64 lo = get_unaligned((const u64 *)src);
+	u64 hi = get_unaligned((const u64 *)(src + 8));
+
+	put_unaligned(lo, (u64 *)dst);
+	put_unaligned(hi, (u64 *)(dst + 8));
+}
+
+__bpf_kfunc u64 bpf_lea64(u64 base, u64 index, u32 scale__k, s32 disp__k)
+{
+	return base + index * scale__k + disp__k;
+}
+
+__bpf_kfunc_end_defs();
+
+/* x << n | x >> (-n & 63) */
+static const struct bpf_insn rol64_body[] = {
+	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 63),
+	BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
+	BPF_ALU64_REG(BPF_LSH, BPF_REG_0, BPF_REG_2),
+	BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
+	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 63),
+	BPF_ALU64_REG(BPF_RSH, BPF_REG_1, BPF_REG_2),
+	BPF_ALU64_REG(BPF_OR, BPF_REG_0, BPF_REG_1),
+};
+
+/* the jump lands within the body, here on its last instruction */
+static const struct bpf_insn select64_body[] = {
+	BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 1),
+	BPF_MOV64_REG(BPF_REG_2, BPF_REG_3),
+	BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
+};
+
+/* x << (64 - start - len) >> (64 - len) */
+static const struct bpf_insn extract64_body[] = {
+	BPF_MOV32_IMM(BPF_REG_4, 64),
+	BPF_ALU32_REG(BPF_SUB, BPF_REG_4, BPF_REG_2),
+	BPF_ALU32_REG(BPF_SUB, BPF_REG_4, BPF_REG_3),
+	BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
+	BPF_ALU64_REG(BPF_LSH, BPF_REG_0, BPF_REG_4),
+	BPF_MOV32_IMM(BPF_REG_4, 64),
+	BPF_ALU32_REG(BPF_SUB, BPF_REG_4, BPF_REG_3),
+	BPF_ALU64_REG(BPF_RSH, BPF_REG_0, BPF_REG_4),
+};
+
+/* the offset is an s32 */
+static const struct bpf_insn load_be64_body[] = {
+	BPF_ALU64_IMM(BPF_LSH, BPF_REG_2, 32),
+	BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 32),
+	BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2),
+	BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 0),
+	BPF_ENDIAN(BPF_TO_BE, BPF_REG_0, 64),
+};
+
+/* a load whose value is not used, of memory that the program may read */
+static const struct bpf_insn prefetch_body[] = {
+	BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_1, 0),
+};
+
+/* two loads, then two stores */
+static const struct bpf_insn copy16_body[] = {
+	BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_2, 0),
+	BPF_LDX_MEM(BPF_DW, BPF_REG_5, BPF_REG_2, 8),
+	BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_4, 0),
+	BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_5, 8),
+};
+
+/* base + index * scale + disp, scale a u32 and disp an s32 */
+static const struct bpf_insn lea64_body[] = {
+	BPF_MOV32_REG(BPF_REG_3, BPF_REG_3),
+	BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
+	BPF_ALU64_REG(BPF_MUL, BPF_REG_0, BPF_REG_3),
+	BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
+	BPF_ALU64_IMM(BPF_LSH, BPF_REG_4, 32),
+	BPF_ALU64_IMM(BPF_ARSH, BPF_REG_4, 32),
+	BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_4),
+};
+
+BTF_KFUNCS_START(insn_kfunc_ids)
+BTF_ID_FLAGS(func, bpf_rol64)
+BTF_ID_FLAGS(func, bpf_select64)
+BTF_ID_FLAGS(func, bpf_extract64)
+BTF_ID_FLAGS(func, bpf_load_be64)
+BTF_ID_FLAGS(func, bpf_prefetch)
+BTF_ID_FLAGS(func, bpf_copy16)
+BTF_ID_FLAGS(func, bpf_lea64)
+BTF_KFUNCS_END(insn_kfunc_ids)
+
+BTF_ID_LIST(body_ids)
+BTF_ID(func, bpf_rol64)
+BTF_ID(func, bpf_select64)
+BTF_ID(func, bpf_extract64)
+BTF_ID(func, bpf_load_be64)
+BTF_ID(func, bpf_prefetch)
+BTF_ID(func, bpf_copy16)
+BTF_ID(func, bpf_lea64)
+
+#define BODY(i, op, emit)	{ &body_ids[i], op##_body, ARRAY_SIZE(op##_body), emit }
+
+static const struct bpf_kfunc_body bodies[] = {
+	BODY(0, rol64, NULL),
+	BODY(1, select64, NULL),
+	BODY(2, extract64, NULL),
+	BODY(3, load_be64, NULL),
+	BODY(4, prefetch, NULL),
+	BODY(5, copy16, NULL),
+	BODY(6, lea64, NULL),
+};
+
+static const struct btf_kfunc_id_set insn_kfunc_set = {
+	.owner    = THIS_MODULE,
+	.set      = &insn_kfunc_ids,
+	.bodies   = bodies,
+	.body_cnt = ARRAY_SIZE(bodies),
+};
+
+static int __init insn_kfuncs_init(void)
+{
+	return register_btf_kfunc_id_set(BPF_PROG_TYPE_UNSPEC, &insn_kfunc_set);
+}
+
+/* the kfunc set goes away with the module's BTF */
+static void __exit insn_kfuncs_exit(void)
+{
+}
+
+module_init(insn_kfuncs_init);
+module_exit(insn_kfuncs_exit);
+
+MODULE_DESCRIPTION("Kfuncs for CPU instructions that BPF lacks");
+MODULE_LICENSE("GPL");
-- 
2.51.1


  parent reply	other threads:[~2026-10-05 14:22 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-05 14:22 [RFC PATCH bpf-next 0/7] bpf: Inline kfuncs that have a BPF body Yusheng Zheng
2026-10-05 14:22 ` [RFC PATCH bpf-next 1/7] bpf: Let kfunc sets give kfuncs " Yusheng Zheng
2026-10-05 14:38   ` sashiko-bot
2026-10-05 15:16   ` bot+bpf-ci
2026-10-05 14:22 ` [RFC PATCH bpf-next 2/7] bpf: Verify calls of kfuncs with a body through the body Yusheng Zheng
2026-10-05 14:41   ` sashiko-bot
2026-10-05 14:22 ` [RFC PATCH bpf-next 3/7] bpf, x86: Inline native code for kfuncs that have a body Yusheng Zheng
2026-10-05 14:22 ` Yusheng Zheng [this message]
2026-10-05 14:39   ` [RFC PATCH bpf-next 4/7] bpf: Add kfuncs with bodies for common operations sashiko-bot
2026-10-05 14:22 ` [RFC PATCH bpf-next 5/7] bpf, x86: Add native code for some inline kfuncs Yusheng Zheng
2026-10-05 14:22 ` [RFC PATCH bpf-next 6/7] selftests/bpf: Test " Yusheng Zheng
2026-10-05 14:22 ` [RFC PATCH bpf-next 7/7] Documentation/bpf: Describe " Yusheng Zheng
2026-10-05 15:16   ` bot+bpf-ci

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261005142219.33451-5-yunwei356@gmail.com \
    --to=yunwei356@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bp@alien8.de \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=dave.hansen@linux.intel.com \
    --cc=eddyz87@gmail.com \
    --cc=emil@etsalapatis.com \
    --cc=hpa@zytor.com \
    --cc=ihor.solodrai@linux.dev \
    --cc=john.fastabend@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=leon.hwang@linux.dev \
    --cc=martin.lau@linux.dev \
    --cc=memxor@gmail.com \
    --cc=mingo@redhat.com \
    --cc=puranjay@kernel.org \
    --cc=song@kernel.org \
    --cc=sunhao.th@gmail.com \
    --cc=tglx@kernel.org \
    --cc=x86@kernel.org \
    --cc=yonghong.song@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.