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 */
110135static 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
126156static 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+
141192void 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