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