Skip to content

Commit 11d45ee

Browse files
Abhishek Dubeymaddy-kerneldev
authored andcommitted
powerpc64/bpf: Additional NVR handling for bpf_throw
The bpf_throw() function never returns, if it has clobbered any callee-saved register, those will remain clobbered. The prologue must take care of saving all callee-saved registers in the frame of exception boundary program. Later these additional non volatile registers R14-R25 along with other NVRs are restored back in the epilogue of exception callback. To achieve above objective, the frame size is determined dynamically to accommodate additional non volatile registers in exception boundary's frame. For non-exception boundary program, the frame size remains optimal. The additional instructions to save & restore r14-r25 registers are emitted only during exception boundary and exception callback program respectively. Signed-off-by: Abhishek Dubey <adubey@linux.ibm.com> Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com> Link: https://patch.msgid.link/20260124075223.6033-7-adubey@linux.ibm.com
1 parent c169930 commit 11d45ee

1 file changed

Lines changed: 81 additions & 8 deletions

File tree

arch/powerpc/net/bpf_jit_comp64.c

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,37 @@
3232
*
3333
* [ prev sp ] <-------------
3434
* [ tail_call_info ] 8 |
35-
* [ nv gpr save area ] 6*8 |
35+
* [ nv gpr save area ] 6*8 + (12*8) |
3636
* [ local_tmp_var ] 24 |
3737
* fp (r31) --> [ ebpf stack space ] upto 512 |
3838
* [ frame header ] 32/112 |
3939
* sp (r1) ---> [ stack pointer ] --------------
40+
*
41+
* Additional (12*8) in 'nv gpr save area' only in case of
42+
* exception boundary.
4043
*/
4144

4245
/* for bpf JIT code internal usage */
4346
#define BPF_PPC_STACK_LOCALS 24
47+
/*
48+
* for additional non volatile registers(r14-r25) to be saved
49+
* at exception boundary
50+
*/
51+
#define BPF_PPC_EXC_STACK_SAVE (12*8)
52+
4453
/* stack frame excluding BPF stack, ensure this is quadword aligned */
4554
#define BPF_PPC_STACKFRAME (STACK_FRAME_MIN_SIZE + \
4655
BPF_PPC_STACK_LOCALS + \
4756
BPF_PPC_STACK_SAVE + \
4857
BPF_PPC_TAILCALL)
4958

59+
/*
60+
* same as BPF_PPC_STACKFRAME with save area for additional
61+
* non volatile registers saved at exception boundary.
62+
* This is quad-word aligned.
63+
*/
64+
#define BPF_PPC_EXC_STACKFRAME (BPF_PPC_STACKFRAME + BPF_PPC_EXC_STACK_SAVE)
65+
5066
/* BPF register usage */
5167
#define TMP_REG_1 (MAX_BPF_JIT_REG + 0)
5268
#define TMP_REG_2 (MAX_BPF_JIT_REG + 1)
@@ -88,10 +104,16 @@ static inline bool bpf_has_stack_frame(struct codegen_context *ctx)
88104
* - we call other functions (kernel helpers), or
89105
* - the bpf program uses its stack area
90106
* The latter condition is deduced from the usage of BPF_REG_FP
107+
*
108+
* bpf_throw() leads to exception callback from a BPF (sub)program.
109+
* The (sub)program is always marked as SEEN_FUNC, creating a stack
110+
* frame. The exception callback uses the frame of the exception
111+
* boundary, so the exception boundary program must have a frame.
91112
*/
92113
return ctx->seen & SEEN_FUNC ||
93114
bpf_is_seen_register(ctx, bpf_to_ppc(BPF_REG_FP)) ||
94-
ctx->exception_cb;
115+
ctx->exception_cb ||
116+
ctx->exception_boundary;
95117
}
96118

97119
/*
@@ -103,9 +125,12 @@ static inline bool bpf_has_stack_frame(struct codegen_context *ctx)
103125
* [ ... ] |
104126
* sp (r1) ---> [ stack pointer ] --------------
105127
* [ tail_call_info ] 8
106-
* [ nv gpr save area ] 6*8
128+
* [ nv gpr save area ] 6*8 + (12*8)
107129
* [ local_tmp_var ] 24
108130
* [ unused red zone ] 224
131+
*
132+
* Additional (12*8) in 'nv gpr save area' only in case of
133+
* exception boundary.
109134
*/
110135
static int bpf_jit_stack_local(struct codegen_context *ctx)
111136
{
@@ -114,7 +139,12 @@ static int bpf_jit_stack_local(struct codegen_context *ctx)
114139
return STACK_FRAME_MIN_SIZE + ctx->stack_size;
115140
} else {
116141
/* Stack layout with redzone */
117-
return -(BPF_PPC_TAILCALL + BPF_PPC_STACK_SAVE + BPF_PPC_STACK_LOCALS);
142+
return -(BPF_PPC_TAILCALL
143+
+BPF_PPC_STACK_SAVE
144+
+(ctx->exception_boundary || ctx->exception_cb ?
145+
BPF_PPC_EXC_STACK_SAVE : 0)
146+
+BPF_PPC_STACK_LOCALS
147+
);
118148
}
119149
}
120150

@@ -125,9 +155,19 @@ int bpf_jit_stack_tailcallinfo_offset(struct codegen_context *ctx)
125155

126156
static int bpf_jit_stack_offsetof(struct codegen_context *ctx, int reg)
127157
{
128-
if (reg >= BPF_PPC_NVR_MIN && reg < 32)
158+
int min_valid_nvreg = BPF_PPC_NVR_MIN;
159+
/* Default frame size for all cases except exception boundary */
160+
int frame_nvr_size = BPF_PPC_STACKFRAME;
161+
162+
/* Consider all nv regs for handling exceptions */
163+
if (ctx->exception_boundary || ctx->exception_cb) {
164+
min_valid_nvreg = _R14;
165+
frame_nvr_size = BPF_PPC_EXC_STACKFRAME;
166+
}
167+
168+
if (reg >= min_valid_nvreg && reg < 32)
129169
return (bpf_has_stack_frame(ctx) ?
130-
(BPF_PPC_STACKFRAME + ctx->stack_size) : 0)
170+
(frame_nvr_size + ctx->stack_size) : 0)
131171
- (8 * (32 - reg)) - BPF_PPC_TAILCALL;
132172

133173
pr_err("BPF JIT is asking about unknown registers");
@@ -138,6 +178,17 @@ void bpf_jit_realloc_regs(struct codegen_context *ctx)
138178
{
139179
}
140180

181+
/*
182+
* For exception boundary & exception_cb progs:
183+
* return increased size to accommodate additional NVRs.
184+
*/
185+
static int bpf_jit_stack_size(struct codegen_context *ctx)
186+
{
187+
return ctx->exception_boundary || ctx->exception_cb ?
188+
BPF_PPC_EXC_STACKFRAME :
189+
BPF_PPC_STACKFRAME;
190+
}
191+
141192
void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx)
142193
{
143194
int i;
@@ -198,7 +249,19 @@ void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx)
198249
EMIT(PPC_RAW_STD(_R0, _R1, PPC_LR_STKOFF));
199250
}
200251

201-
EMIT(PPC_RAW_STDU(_R1, _R1, -(BPF_PPC_STACKFRAME + ctx->stack_size)));
252+
EMIT(PPC_RAW_STDU(_R1, _R1,
253+
-(bpf_jit_stack_size(ctx) + ctx->stack_size)));
254+
}
255+
256+
/*
257+
* Program acting as exception boundary pushes R14..R25 in addition to
258+
* BPF callee-saved non volatile registers. Exception callback uses
259+
* the boundary program's stack frame, recover additionally saved
260+
* registers in epilogue of exception callback.
261+
*/
262+
if (ctx->exception_boundary) {
263+
for (i = _R14; i <= _R25; i++)
264+
EMIT(PPC_RAW_STD(i, _R1, bpf_jit_stack_offsetof(ctx, i)));
202265
}
203266

204267
if (!ctx->exception_cb) {
@@ -248,9 +311,19 @@ static void bpf_jit_emit_common_epilogue(u32 *image, struct codegen_context *ctx
248311
EMIT(PPC_RAW_LD(bpf_to_ppc(ARENA_VM_START), _R1,
249312
bpf_jit_stack_offsetof(ctx, bpf_to_ppc(ARENA_VM_START))));
250313

314+
if (ctx->exception_cb) {
315+
/*
316+
* Recover additionally saved non volatile registers from stack
317+
* frame of exception boundary program.
318+
*/
319+
for (i = _R14; i <= _R25; i++)
320+
EMIT(PPC_RAW_LD(i, _R1, bpf_jit_stack_offsetof(ctx, i)));
321+
}
322+
251323
/* Tear down our stack frame */
252324
if (bpf_has_stack_frame(ctx)) {
253-
EMIT(PPC_RAW_ADDI(_R1, _R1, BPF_PPC_STACKFRAME + ctx->stack_size));
325+
EMIT(PPC_RAW_ADDI(_R1, _R1, bpf_jit_stack_size(ctx) + ctx->stack_size));
326+
254327
if (ctx->seen & SEEN_FUNC || ctx->exception_cb) {
255328
EMIT(PPC_RAW_LD(_R0, _R1, PPC_LR_STKOFF));
256329
EMIT(PPC_RAW_MTLR(_R0));

0 commit comments

Comments
 (0)