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