1 // SPDX-License-Identifier: GPL-2.0
3 * Common functionality for HPPA32 and HPPA64 BPF JIT compilers
5 * Copyright (c) 2023 Helge Deller <deller@gmx.de>
10 #include <linux/filter.h>
13 /* Number of iterations to try until offsets converge. */
14 #define NR_JIT_ITERATIONS 35
16 static int build_body(struct hppa_jit_context
*ctx
, bool extra_pass
, int *offset
)
18 const struct bpf_prog
*prog
= ctx
->prog
;
21 ctx
->reg_seen_collect
= true;
22 for (i
= 0; i
< prog
->len
; i
++) {
23 const struct bpf_insn
*insn
= &prog
->insnsi
[i
];
26 ret
= bpf_jit_emit_insn(insn
, ctx
, extra_pass
);
27 /* BPF_LD | BPF_IMM | BPF_DW: skip the next instruction. */
31 offset
[i
] = ctx
->ninsns
;
35 ctx
->reg_seen_collect
= false;
39 bool bpf_jit_needs_zext(void)
44 struct bpf_prog
*bpf_int_jit_compile(struct bpf_prog
*prog
)
46 unsigned int prog_size
= 0, extable_size
= 0;
47 bool tmp_blinded
= false, extra_pass
= false;
48 struct bpf_prog
*tmp
, *orig_prog
= prog
;
49 int pass
= 0, prev_ninsns
= 0, prologue_len
, i
;
50 struct hppa_jit_data
*jit_data
;
51 struct hppa_jit_context
*ctx
;
53 if (!prog
->jit_requested
)
56 tmp
= bpf_jit_blind_constants(prog
);
64 jit_data
= prog
->aux
->jit_data
;
66 jit_data
= kzalloc(sizeof(*jit_data
), GFP_KERNEL
);
71 prog
->aux
->jit_data
= jit_data
;
78 prog_size
= sizeof(*ctx
->insns
) * ctx
->ninsns
;
83 ctx
->offset
= kcalloc(prog
->len
, sizeof(int), GFP_KERNEL
);
88 for (i
= 0; i
< prog
->len
; i
++) {
90 ctx
->offset
[i
] = prev_ninsns
;
93 for (i
= 0; i
< NR_JIT_ITERATIONS
; i
++) {
96 if (build_body(ctx
, extra_pass
, ctx
->offset
)) {
100 ctx
->body_len
= ctx
->ninsns
;
101 bpf_jit_build_prologue(ctx
);
102 ctx
->prologue_len
= ctx
->ninsns
- ctx
->body_len
;
103 ctx
->epilogue_offset
= ctx
->ninsns
;
104 bpf_jit_build_epilogue(ctx
);
106 if (ctx
->ninsns
== prev_ninsns
) {
107 if (jit_data
->header
)
109 /* obtain the actual image size */
110 extable_size
= prog
->aux
->num_exentries
*
111 sizeof(struct exception_table_entry
);
112 prog_size
= sizeof(*ctx
->insns
) * ctx
->ninsns
;
115 bpf_jit_binary_alloc(prog_size
+ extable_size
,
119 if (!jit_data
->header
) {
124 ctx
->insns
= (u32
*)jit_data
->image
;
126 * Now, when the image is allocated, the image can
127 * potentially shrink more (auipc/jalr -> jal).
130 prev_ninsns
= ctx
->ninsns
;
133 if (i
== NR_JIT_ITERATIONS
) {
134 pr_err("bpf-jit: image did not converge in <%d passes!\n", i
);
135 if (jit_data
->header
)
136 bpf_jit_binary_free(jit_data
->header
);
142 prog
->aux
->extable
= (void *)ctx
->insns
+ prog_size
;
148 bpf_jit_build_prologue(ctx
);
149 if (build_body(ctx
, extra_pass
, NULL
)) {
150 bpf_jit_binary_free(jit_data
->header
);
154 bpf_jit_build_epilogue(ctx
);
156 if (HPPA_JIT_DEBUG
|| bpf_jit_enable
> 1) {
158 bpf_jit_dump(prog
->len
, prog_size
, pass
, ctx
->insns
);
160 { extern int machine_restart(char *); machine_restart(""); }
163 prog
->bpf_func
= (void *)ctx
->insns
;
165 prog
->jited_len
= prog_size
;
167 bpf_flush_icache(jit_data
->header
, ctx
->insns
+ ctx
->ninsns
);
169 if (!prog
->is_func
|| extra_pass
) {
170 if (bpf_jit_binary_lock_ro(jit_data
->header
)) {
171 bpf_jit_binary_free(jit_data
->header
);
172 prog
->bpf_func
= NULL
;
177 prologue_len
= ctx
->epilogue_offset
- ctx
->body_len
;
178 for (i
= 0; i
< prog
->len
; i
++)
179 ctx
->offset
[i
] += prologue_len
;
180 bpf_prog_fill_jited_linfo(prog
, ctx
->offset
);
184 prog
->aux
->jit_data
= NULL
;
188 { extern int machine_restart(char *); machine_restart(""); }
191 bpf_jit_prog_release_other(prog
, prog
== orig_prog
?
196 u64
hppa_div64(u64 div
, u64 divisor
)
198 div
= div64_u64(div
, divisor
);
202 u64
hppa_div64_rem(u64 div
, u64 divisor
)
205 div64_u64_rem(div
, divisor
, &rem
);