]>
Commit | Line | Data |
---|---|---|
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. */ | |
39 | extern void bpfbf_ebpfle_init_idesc_table (SIM_CPU *); | |
40 | extern void bpfbf_ebpfbe_init_idesc_table (SIM_CPU *); | |
41 | ||
42 | uint64_t skb_data_offset; | |
43 | ||
44 | IDESC *bpf_idesc_le; | |
45 | IDESC *bpf_idesc_be; | |
46 | ||
47 | ||
48 | int | |
49 | bpfbf_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 | ||
64 | int | |
65 | bpfbf_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 | ||
80 | void | |
81 | bpfbf_model_insn_before (SIM_CPU *current_cpu, int first_p) | |
82 | { | |
83 | /* XXX */ | |
84 | } | |
85 | ||
86 | void | |
87 | bpfbf_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 | ||
106 | DI | |
107 | bpfbf_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 | ||
119 | DI | |
120 | bpfbf_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 | ||
132 | DI | |
133 | bpfbf_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 | ||
141 | VOID | |
142 | bpfbf_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 | ||
184 | VOID | |
185 | bpfbf_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 | ||
198 | VOID | |
199 | bpfbf_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 | ||
211 | static void | |
81e6e8ae | 212 | bpf_def_model_init (void) |
b26e2ae7 JM |
213 | { |
214 | /* Do nothing. */ | |
215 | } | |
216 | ||
217 | static void | |
218 | bpfbf_prepare_run (SIM_CPU *cpu) | |
219 | { | |
220 | /* Nothing. */ | |
221 | } | |
222 | ||
223 | void | |
224 | bpf_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 | ||
254 | void | |
255 | bpf_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 | ||
285 | static const CGEN_INSN * | |
286 | bpfbf_get_idata (SIM_CPU *cpu, int inum) | |
287 | { | |
288 | return CPU_IDESC (cpu) [inum].idata; | |
289 | } | |
290 | ||
291 | static void | |
292 | bpf_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 | ||
310 | static const SIM_MODEL bpf_models[] = | |
311 | { | |
312 | { "bpf-def", & bpf_mach, MODEL_BPF_DEF, NULL, bpf_def_model_init }, | |
313 | { 0 } | |
314 | }; | |
315 | ||
316 | static 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 | ||
326 | const 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 | }; |