]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/bpf/bpf.c
sim: split sim-signal.h include out
[thirdparty/binutils-gdb.git] / sim / bpf / bpf.c
CommitLineData
b26e2ae7 1/* eBPF simulator support code
3666a048 2 Copyright (C) 2020-2021 Free Software Foundation, Inc.
b26e2ae7
JM
3
4 This file is part of GDB, the GNU debugger.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18
6df01ab8
MF
19/* This must come before any other includes. */
20#include "defs.h"
21
b26e2ae7
JM
22#define WANT_CPU_BPFBF
23#define WANT_CPU bpfbf
24
25#include "sim-main.h"
26#include "sim-fpu.h"
1fef66b0 27#include "sim-signal.h"
b26e2ae7
JM
28#include "cgen-mem.h"
29#include "cgen-ops.h"
30#include "cpuall.h"
31#include "decode.h"
32
33#include "defs-le.h" /* For SCACHE */
0316fb52 34#include "bpf-helpers.h"
b26e2ae7
JM
35
36/* It is not possible to include both defs-le.h and defs-be.h due to
37 duplicated definitions, so we need a bunch of forward declarations
38 here. */
39extern void bpfbf_ebpfle_init_idesc_table (SIM_CPU *);
40extern void bpfbf_ebpfbe_init_idesc_table (SIM_CPU *);
41
42uint64_t skb_data_offset;
43
44IDESC *bpf_idesc_le;
45IDESC *bpf_idesc_be;
46
47
48int
49bpfbf_fetch_register (SIM_CPU *current_cpu,
50 int rn,
51 unsigned char *buf,
52 int len)
53{
54 if (rn == 11)
55 SETTDI (buf, CPU_PC_GET (current_cpu));
56 else if (0 <= rn && rn < 10)
57 SETTDI (buf, GET_H_GPR (rn));
58 else
59 return 0;
60
61 return len;
62}
63
64int
65bpfbf_store_register (SIM_CPU *current_cpu,
66 int rn,
67 unsigned char *buf,
68 int len)
69{
70 if (rn == 11)
71 CPU_PC_SET (current_cpu, GETTDI (buf));
72 else if (0 <= rn && rn < 10)
73 SET_H_GPR (rn, GETTDI (buf));
74 else
75 return 0;
76
77 return len;
78}
79
80void
81bpfbf_model_insn_before (SIM_CPU *current_cpu, int first_p)
82{
83 /* XXX */
84}
85
86void
87bpfbf_model_insn_after (SIM_CPU *current_cpu, int first_p)
88{
89 /* XXX */
90}
91
92\f
93/***** Instruction helpers. *****/
94
95/* The semantic routines for most instructions are expressed in RTL in
96 the cpu/bpf.cpu file, and automatically translated to C in the
97 sem-*.c files in this directory.
98
99 However, some of the semantic routines make use of helper C
100 functions. This happens when the semantics of the instructions
101 can't be expressed in RTL alone in a satisfactory way, or not at
102 all.
103
104 The following functions implement these C helpers. */
105
106DI
107bpfbf_endle (SIM_CPU *current_cpu, DI value, UINT bitsize)
108{
109 switch (bitsize)
110 {
111 case 16: return endian_h2le_2(endian_t2h_2(value));
112 case 32: return endian_h2le_4(endian_t2h_4(value));
113 case 64: return endian_h2le_8(endian_t2h_8(value));
114 default: assert(0);
115 }
116 return value;
117}
118
119DI
120bpfbf_endbe (SIM_CPU *current_cpu, DI value, UINT bitsize)
121{
122 switch (bitsize)
123 {
124 case 16: return endian_h2be_2(endian_t2h_2(value));
125 case 32: return endian_h2be_4(endian_t2h_4(value));
126 case 64: return endian_h2be_8(endian_t2h_8(value));
127 default: assert(0);
128 }
129 return value;
130}
131
132DI
133bpfbf_skb_data_offset (SIM_CPU *current_cpu)
134{
135 /* Simply return the user-configured value.
136 This will be 0 if it has not been set. */
137 return skb_data_offset;
138}
139
140
141VOID
142bpfbf_call (SIM_CPU *current_cpu, INT disp32, UINT src)
143{
144 /* eBPF supports two kind of CALL instructions: the so called pseudo
145 calls ("bpf to bpf") and external calls ("bpf to helper").
146
147 Both kind of calls use the same instruction (CALL). However,
148 external calls are constructed by passing a constant argument to
149 the instruction, that identifies the helper, whereas pseudo calls
150 result from expressions involving symbols.
151
152 We distinguish calls from pseudo-calls with the later having a 1
153 stored in the SRC field of the instruction. */
154
155 if (src == 1)
156 {
157 /* This is a pseudo-call. */
158
159 /* XXX allocate a new stack frame and transfer control. For
160 that we need to analyze the target function, like the kernel
161 verifier does. We better populate a cache
162 (function_start_address -> frame_size) so we avoid
163 calculating this more than once. */
164 /* XXX note that disp32 is PC-relative in number of 64-bit
165 words, _minus one_. */
166 }
167 else
168 {
169 /* This is a call to a helper.
170
171 DISP32 contains the helper number. Dispatch to the
172 corresponding helper emulator in bpf-helpers.c. */
173
174 switch (disp32) {
175 /* case TRACE_PRINTK: */
176 case 7:
177 bpf_trace_printk (current_cpu);
178 break;
179 default:;
180 }
181 }
182}
183
184VOID
185bpfbf_exit (SIM_CPU *current_cpu)
186{
187 SIM_DESC sd = CPU_STATE (current_cpu);
188
189 /* r0 holds "return code" */
190 DI r0 = GET_H_GPR (0);
191
192 printf ("exit %ld (0x%lx)\n", r0, r0);
193
194 sim_engine_halt (sd, current_cpu, NULL, CPU_PC_GET (current_cpu),
195 sim_exited, 0 /* sigrc */);
196}
197
198VOID
199bpfbf_breakpoint (SIM_CPU *current_cpu)
200{
201 SIM_DESC sd = CPU_STATE (current_cpu);
202
203 sim_engine_halt (sd, current_cpu, NULL, CPU_PC_GET (current_cpu),
204 sim_stopped, SIM_SIGTRAP);
205}
206
207/* We use the definitions below instead of the cgen-generated model.c,
208 because the later is not really able to work with cpus featuring
209 several ISAs. This should be fixed in CGEN. */
210
211static void
81e6e8ae 212bpf_def_model_init (void)
b26e2ae7
JM
213{
214 /* Do nothing. */
215}
216
217static void
218bpfbf_prepare_run (SIM_CPU *cpu)
219{
220 /* Nothing. */
221}
222
223void
224bpf_engine_run_full (SIM_CPU *cpu)
225{
eee64992 226 if (CURRENT_TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
b26e2ae7
JM
227 {
228 if (!bpf_idesc_le)
229 {
230 bpfbf_ebpfle_init_idesc_table (cpu);
231 bpf_idesc_le = CPU_IDESC (cpu);
232 }
233 else
234 CPU_IDESC (cpu) = bpf_idesc_le;
235
236 bpfbf_ebpfle_engine_run_full (cpu);
237 }
238 else
239 {
240 if (!bpf_idesc_be)
241 {
242 bpfbf_ebpfbe_init_idesc_table (cpu);
243 bpf_idesc_be = CPU_IDESC (cpu);
244 }
245 else
246 CPU_IDESC (cpu) = bpf_idesc_be;
247
248 bpfbf_ebpfbe_engine_run_full (cpu);
249 }
250}
251
252#if WITH_FAST
253
254void
255bpf_engine_run_fast (SIM_CPU *cpu)
256{
eee64992 257 if (CURRENT_TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
b26e2ae7
JM
258 {
259 if (!bpf_idesc_le)
260 {
261 bpfbf_ebpfle_init_idesc_table (cpu);
262 bpf_idesc_le = CPU_IDESC (cpu);
263 }
264 else
265 CPU_IDESC (cpu) = bpf_idesc_le;
266
267 bpfbf_ebpfle_engine_run_fast (cpu);
268 }
269 else
270 {
271 if (!bpf_idesc_be)
272 {
273 bpfbf_ebpfbe_init_idesc_table (cpu);
274 bpf_idesc_be = CPU_IDESC (cpu);
275 }
276 else
277 CPU_IDESC (cpu) = bpf_idesc_be;
278
279 bpfbf_ebpfbe_engine_run_fast (cpu);
280 }
281}
282
283#endif /* WITH_FAST */
284
285static const CGEN_INSN *
286bpfbf_get_idata (SIM_CPU *cpu, int inum)
287{
288 return CPU_IDESC (cpu) [inum].idata;
289}
290
291static void
292bpf_init_cpu (SIM_CPU *cpu)
293{
294 CPU_REG_FETCH (cpu) = bpfbf_fetch_register;
295 CPU_REG_STORE (cpu) = bpfbf_store_register;
296 CPU_PC_FETCH (cpu) = bpfbf_h_pc_get;
297 CPU_PC_STORE (cpu) = bpfbf_h_pc_set;
298 CPU_GET_IDATA (cpu) = bpfbf_get_idata;
299 /* Only used by profiling. 0 disables it. */
300 CPU_MAX_INSNS (cpu) = 0;
301 CPU_INSN_NAME (cpu) = cgen_insn_name;
302 CPU_FULL_ENGINE_FN (cpu) = bpf_engine_run_full;
303#if WITH_FAST
304 CPU_FAST_ENGINE_FN (cpu) = bpf_engine_run_fast;
305#else
306 CPU_FAST_ENGINE_FN (cpu) = bpf_engine_run_full;
307#endif
308}
309
310static const SIM_MODEL bpf_models[] =
311{
312 { "bpf-def", & bpf_mach, MODEL_BPF_DEF, NULL, bpf_def_model_init },
313 { 0 }
314};
315
316static const SIM_MACH_IMP_PROPERTIES bpfbf_imp_properties =
317{
318 sizeof (SIM_CPU),
319#if WITH_SCACHE
320 sizeof (SCACHE)
321#else
322 0
323#endif
324};
325
326const SIM_MACH bpf_mach =
327{
328 "bpf", "bpf", MACH_BPF,
329 32, 32, & bpf_models[0], & bpfbf_imp_properties,
330 bpf_init_cpu,
331 bpfbf_prepare_run
332};