public inbox for bpf@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH bpf-next 0/3] s390/bpf: Implement exceptions
@ 2024-07-03  0:48 Ilya Leoshkevich
  2024-07-03  0:48 ` [PATCH bpf-next 1/3] s390/bpf: Change seen_reg to a mask Ilya Leoshkevich
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Ilya Leoshkevich @ 2024-07-03  0:48 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
  Cc: bpf, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Ilya Leoshkevich

Hi,

this series implements exceptions in the s390x JIT. Patch 1 is a small
refactoring, patch 2 is the implementation, and patch 3 enables the
tests in the CI.

Best regards,
Ilya

Ilya Leoshkevich (3):
  s390/bpf: Change seen_reg to a mask
  s390/bpf: Implement exceptions
  selftests/bpf: Remove exceptions tests from DENYLIST.s390x

 arch/s390/net/bpf_jit_comp.c               | 85 +++++++++++++++++-----
 tools/testing/selftests/bpf/DENYLIST.s390x |  1 -
 2 files changed, 68 insertions(+), 18 deletions(-)

-- 
2.45.2


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

* [PATCH bpf-next 1/3] s390/bpf: Change seen_reg to a mask
  2024-07-03  0:48 [PATCH bpf-next 0/3] s390/bpf: Implement exceptions Ilya Leoshkevich
@ 2024-07-03  0:48 ` Ilya Leoshkevich
  2024-07-03  0:48 ` [PATCH bpf-next 2/3] s390/bpf: Implement exceptions Ilya Leoshkevich
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Ilya Leoshkevich @ 2024-07-03  0:48 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
  Cc: bpf, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Ilya Leoshkevich

Using a mask instead of an array saves a small amount of memory and
allows marking multiple registers as seen with a simple "or". Another
positive side-effect is that it speeds up verification with jitterbug.

Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 arch/s390/net/bpf_jit_comp.c | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index ddfc0e99872e..945f2ee6511b 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -35,7 +35,7 @@
 
 struct bpf_jit {
 	u32 seen;		/* Flags to remember seen eBPF instructions */
-	u32 seen_reg[16];	/* Array to remember which registers are used */
+	u16 seen_regs;		/* Mask to remember which registers are used */
 	u32 *addrs;		/* Array with relative instruction addresses */
 	u8 *prg_buf;		/* Start of program */
 	int size;		/* Size of program and literal pool */
@@ -120,8 +120,8 @@ static inline void reg_set_seen(struct bpf_jit *jit, u32 b1)
 {
 	u32 r1 = reg2hex[b1];
 
-	if (r1 >= 6 && r1 <= 15 && !jit->seen_reg[r1])
-		jit->seen_reg[r1] = 1;
+	if (r1 >= 6 && r1 <= 15)
+		jit->seen_regs |= (1 << r1);
 }
 
 #define REG_SET_SEEN(b1)					\
@@ -129,8 +129,6 @@ static inline void reg_set_seen(struct bpf_jit *jit, u32 b1)
 	reg_set_seen(jit, b1);					\
 })
 
-#define REG_SEEN(b1) jit->seen_reg[reg2hex[(b1)]]
-
 /*
  * EMIT macros for code generation
  */
@@ -438,12 +436,12 @@ static void restore_regs(struct bpf_jit *jit, u32 rs, u32 re, u32 stack_depth)
 /*
  * Return first seen register (from start)
  */
-static int get_start(struct bpf_jit *jit, int start)
+static int get_start(u16 seen_regs, int start)
 {
 	int i;
 
 	for (i = start; i <= 15; i++) {
-		if (jit->seen_reg[i])
+		if (seen_regs & (1 << i))
 			return i;
 	}
 	return 0;
@@ -452,15 +450,15 @@ static int get_start(struct bpf_jit *jit, int start)
 /*
  * Return last seen register (from start) (gap >= 2)
  */
-static int get_end(struct bpf_jit *jit, int start)
+static int get_end(u16 seen_regs, int start)
 {
 	int i;
 
 	for (i = start; i < 15; i++) {
-		if (!jit->seen_reg[i] && !jit->seen_reg[i + 1])
+		if (!(seen_regs & (3 << i)))
 			return i - 1;
 	}
-	return jit->seen_reg[15] ? 15 : 14;
+	return (seen_regs & (1 << 15)) ? 15 : 14;
 }
 
 #define REGS_SAVE	1
@@ -469,8 +467,10 @@ static int get_end(struct bpf_jit *jit, int start)
  * Save and restore clobbered registers (6-15) on stack.
  * We save/restore registers in chunks with gap >= 2 registers.
  */
-static void save_restore_regs(struct bpf_jit *jit, int op, u32 stack_depth)
+static void save_restore_regs(struct bpf_jit *jit, int op, u32 stack_depth,
+			      u16 extra_regs)
 {
+	u16 seen_regs = jit->seen_regs | extra_regs;
 	const int last = 15, save_restore_size = 6;
 	int re = 6, rs;
 
@@ -484,10 +484,10 @@ static void save_restore_regs(struct bpf_jit *jit, int op, u32 stack_depth)
 	}
 
 	do {
-		rs = get_start(jit, re);
+		rs = get_start(seen_regs, re);
 		if (!rs)
 			break;
-		re = get_end(jit, rs + 1);
+		re = get_end(seen_regs, rs + 1);
 		if (op == REGS_SAVE)
 			save_regs(jit, rs, re);
 		else
@@ -573,7 +573,7 @@ static void bpf_jit_prologue(struct bpf_jit *jit, struct bpf_prog *fp,
 	/* Tail calls have to skip above initialization */
 	jit->tail_call_start = jit->prg;
 	/* Save registers */
-	save_restore_regs(jit, REGS_SAVE, stack_depth);
+	save_restore_regs(jit, REGS_SAVE, stack_depth, 0);
 	/* Setup literal pool */
 	if (is_first_pass(jit) || (jit->seen & SEEN_LITERAL)) {
 		if (!is_first_pass(jit) &&
@@ -649,7 +649,7 @@ static void bpf_jit_epilogue(struct bpf_jit *jit, u32 stack_depth)
 	/* Load exit code: lgr %r2,%b0 */
 	EMIT4(0xb9040000, REG_2, BPF_REG_0);
 	/* Restore registers */
-	save_restore_regs(jit, REGS_RESTORE, stack_depth);
+	save_restore_regs(jit, REGS_RESTORE, stack_depth, 0);
 	if (nospec_uses_trampoline()) {
 		jit->r14_thunk_ip = jit->prg;
 		/* Generate __s390_indirect_jump_r14 thunk */
@@ -1847,7 +1847,7 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
 		/*
 		 * Restore registers before calling function
 		 */
-		save_restore_regs(jit, REGS_RESTORE, stack_depth);
+		save_restore_regs(jit, REGS_RESTORE, stack_depth, 0);
 
 		/*
 		 * goto *(prog->bpf_func + tail_call_start);
-- 
2.45.2


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

* [PATCH bpf-next 2/3] s390/bpf: Implement exceptions
  2024-07-03  0:48 [PATCH bpf-next 0/3] s390/bpf: Implement exceptions Ilya Leoshkevich
  2024-07-03  0:48 ` [PATCH bpf-next 1/3] s390/bpf: Change seen_reg to a mask Ilya Leoshkevich
@ 2024-07-03  0:48 ` Ilya Leoshkevich
  2024-07-03  0:48 ` [PATCH bpf-next 3/3] selftests/bpf: Remove exceptions tests from DENYLIST.s390x Ilya Leoshkevich
  2024-07-08 14:40 ` [PATCH bpf-next 0/3] s390/bpf: Implement exceptions patchwork-bot+netdevbpf
  3 siblings, 0 replies; 5+ messages in thread
From: Ilya Leoshkevich @ 2024-07-03  0:48 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
  Cc: bpf, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Ilya Leoshkevich

Implement the following three pieces required from the JIT:

- A "top-level" BPF prog (exception_boundary) must save all
  non-volatile registers, and not only the ones that it clobbers.
- A "handler" BPF prog (exception_cb) must switch stack to that of
  exception_boundary, and restore the registers that exception_boundary
  saved.
- arch_bpf_stack_walk() must unwind the stack and provide the results
  in a way that satisfies both bpf_throw() and exception_cb.

Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 arch/s390/net/bpf_jit_comp.c | 55 ++++++++++++++++++++++++++++++++++--
 1 file changed, 53 insertions(+), 2 deletions(-)

diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index 945f2ee6511b..9d440a0b729e 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -31,6 +31,7 @@
 #include <asm/nospec-branch.h>
 #include <asm/set_memory.h>
 #include <asm/text-patching.h>
+#include <asm/unwind.h>
 #include "bpf_jit.h"
 
 struct bpf_jit {
@@ -62,6 +63,8 @@ struct bpf_jit {
 #define SEEN_FUNC	BIT(2)		/* calls C functions */
 #define SEEN_STACK	(SEEN_FUNC | SEEN_MEM)
 
+#define NVREGS		0xffc0		/* %r6-%r15 */
+
 /*
  * s390 registers
  */
@@ -572,8 +575,21 @@ static void bpf_jit_prologue(struct bpf_jit *jit, struct bpf_prog *fp,
 	}
 	/* Tail calls have to skip above initialization */
 	jit->tail_call_start = jit->prg;
-	/* Save registers */
-	save_restore_regs(jit, REGS_SAVE, stack_depth, 0);
+	if (fp->aux->exception_cb) {
+		/*
+		 * Switch stack, the new address is in the 2nd parameter.
+		 *
+		 * Arrange the restoration of %r6-%r15 in the epilogue.
+		 * Do not restore them now, the prog does not need them.
+		 */
+		/* lgr %r15,%r3 */
+		EMIT4(0xb9040000, REG_15, REG_3);
+		jit->seen_regs |= NVREGS;
+	} else {
+		/* Save registers */
+		save_restore_regs(jit, REGS_SAVE, stack_depth,
+				  fp->aux->exception_boundary ? NVREGS : 0);
+	}
 	/* Setup literal pool */
 	if (is_first_pass(jit) || (jit->seen & SEEN_LITERAL)) {
 		if (!is_first_pass(jit) &&
@@ -2909,3 +2925,38 @@ bool bpf_jit_supports_insn(struct bpf_insn *insn, bool in_arena)
 	 */
 	return true;
 }
+
+bool bpf_jit_supports_exceptions(void)
+{
+	/*
+	 * Exceptions require unwinding support, which is always available,
+	 * because the kernel is always built with backchain.
+	 */
+	return true;
+}
+
+void arch_bpf_stack_walk(bool (*consume_fn)(void *, u64, u64, u64),
+			 void *cookie)
+{
+	unsigned long addr, prev_addr = 0;
+	struct unwind_state state;
+
+	unwind_for_each_frame(&state, NULL, NULL, 0) {
+		addr = unwind_get_return_address(&state);
+		if (!addr)
+			break;
+		/*
+		 * addr is a return address and state.sp is the value of %r15
+		 * at this address. exception_cb needs %r15 at entry to the
+		 * function containing addr, so take the next state.sp.
+		 *
+		 * There is no bp, and the exception_cb prog does not need one
+		 * to perform a quasi-longjmp. The common code requires a
+		 * non-zero bp, so pass sp there as well.
+		 */
+		if (prev_addr && !consume_fn(cookie, prev_addr, state.sp,
+					     state.sp))
+			break;
+		prev_addr = addr;
+	}
+}
-- 
2.45.2


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

* [PATCH bpf-next 3/3] selftests/bpf: Remove exceptions tests from DENYLIST.s390x
  2024-07-03  0:48 [PATCH bpf-next 0/3] s390/bpf: Implement exceptions Ilya Leoshkevich
  2024-07-03  0:48 ` [PATCH bpf-next 1/3] s390/bpf: Change seen_reg to a mask Ilya Leoshkevich
  2024-07-03  0:48 ` [PATCH bpf-next 2/3] s390/bpf: Implement exceptions Ilya Leoshkevich
@ 2024-07-03  0:48 ` Ilya Leoshkevich
  2024-07-08 14:40 ` [PATCH bpf-next 0/3] s390/bpf: Implement exceptions patchwork-bot+netdevbpf
  3 siblings, 0 replies; 5+ messages in thread
From: Ilya Leoshkevich @ 2024-07-03  0:48 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
  Cc: bpf, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Ilya Leoshkevich

Now that the s390x JIT supports exceptions, remove the respective tests
from the denylist.

Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 tools/testing/selftests/bpf/DENYLIST.s390x | 1 -
 1 file changed, 1 deletion(-)

diff --git a/tools/testing/selftests/bpf/DENYLIST.s390x b/tools/testing/selftests/bpf/DENYLIST.s390x
index cb810a98e78f..3ebd77206f98 100644
--- a/tools/testing/selftests/bpf/DENYLIST.s390x
+++ b/tools/testing/selftests/bpf/DENYLIST.s390x
@@ -1,6 +1,5 @@
 # TEMPORARY
 # Alphabetical order
-exceptions				 # JIT does not support calling kfunc bpf_throw				       (exceptions)
 get_stack_raw_tp                         # user_stack corrupted user stack                                             (no backchain userspace)
 stacktrace_build_id                      # compare_map_keys stackid_hmap vs. stackmap err -2 errno 2                   (?)
 verifier_iterating_callbacks
-- 
2.45.2


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

* Re: [PATCH bpf-next 0/3] s390/bpf: Implement exceptions
  2024-07-03  0:48 [PATCH bpf-next 0/3] s390/bpf: Implement exceptions Ilya Leoshkevich
                   ` (2 preceding siblings ...)
  2024-07-03  0:48 ` [PATCH bpf-next 3/3] selftests/bpf: Remove exceptions tests from DENYLIST.s390x Ilya Leoshkevich
@ 2024-07-08 14:40 ` patchwork-bot+netdevbpf
  3 siblings, 0 replies; 5+ messages in thread
From: patchwork-bot+netdevbpf @ 2024-07-08 14:40 UTC (permalink / raw)
  To: Ilya Leoshkevich; +Cc: ast, daniel, andrii, bpf, hca, gor, agordeev

Hello:

This series was applied to bpf/bpf-next.git (master)
by Daniel Borkmann <daniel@iogearbox.net>:

On Wed,  3 Jul 2024 02:48:46 +0200 you wrote:
> Hi,
> 
> this series implements exceptions in the s390x JIT. Patch 1 is a small
> refactoring, patch 2 is the implementation, and patch 3 enables the
> tests in the CI.
> 
> Best regards,
> Ilya
> 
> [...]

Here is the summary with links:
  - [bpf-next,1/3] s390/bpf: Change seen_reg to a mask
    https://git.kernel.org/bpf/bpf-next/c/7ba4f43e16de
  - [bpf-next,2/3] s390/bpf: Implement exceptions
    https://git.kernel.org/bpf/bpf-next/c/fa7bd4b000a7
  - [bpf-next,3/3] selftests/bpf: Remove exceptions tests from DENYLIST.s390x
    https://git.kernel.org/bpf/bpf-next/c/02480fe8a6a6

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



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

end of thread, other threads:[~2024-07-08 14:40 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-07-03  0:48 [PATCH bpf-next 0/3] s390/bpf: Implement exceptions Ilya Leoshkevich
2024-07-03  0:48 ` [PATCH bpf-next 1/3] s390/bpf: Change seen_reg to a mask Ilya Leoshkevich
2024-07-03  0:48 ` [PATCH bpf-next 2/3] s390/bpf: Implement exceptions Ilya Leoshkevich
2024-07-03  0:48 ` [PATCH bpf-next 3/3] selftests/bpf: Remove exceptions tests from DENYLIST.s390x Ilya Leoshkevich
2024-07-08 14:40 ` [PATCH bpf-next 0/3] s390/bpf: Implement exceptions patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox