Commit | Line | Data |
---|---|---|
ea195bb0 JM |
1 | ;; Linux BPF CPU description -*- Scheme -*- |
2 | ;; Copyright (C) 2019 Free Software Foundation, Inc. | |
3 | ;; | |
4 | ;; Contributed by Oracle Inc. | |
5 | ;; | |
6 | ;; This file is part of the GNU Binutils and of GDB. | |
7 | ;; | |
8 | ;; This program is free software; you can redistribute it and/or | |
9 | ;; modify it under the terms of the GNU General Public License as | |
10 | ;; published by the Free Software Foundation; either version 3 of the | |
11 | ;; License, or (at your option) any later version. | |
12 | ;; | |
13 | ;; This program is distributed in the hope that it will be useful, but | |
14 | ;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | ;; General Public License for more details. | |
17 | ;; | |
18 | ;; You should have received a copy of the GNU General Public License | |
19 | ;; along with this program; if not, write to the Free Software | |
20 | ;; Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA | |
21 | ;; 02110-1301, USA. | |
22 | ||
23 | ;; This file contains a CGEN CPU description for the Linux kernel eBPF | |
24 | ;; instruction set. eBPF is documented in the linux kernel source | |
25 | ;; tree. See linux/Documentation/networking/filter.txt, and also the | |
26 | ;; sources in the networking subsystem, notably | |
27 | ;; linux/net/core/filter.c. | |
28 | ||
29 | (include "simplify.inc") | |
30 | ||
31 | (define-arch | |
32 | (name bpf) | |
33 | (comment "Linux kernel BPF") | |
34 | (insn-lsb0? #t) | |
78c1c354 JM |
35 | ;; XXX explain the default-alignment setting is for the simulator. |
36 | ;; It is confusing that the simulator follows the emulated memory | |
37 | ;; access conventions for fetching instructions by pieces... | |
38 | (default-alignment unaligned) | |
ea195bb0 JM |
39 | (machs bpf) |
40 | (isas ebpfle ebpfbe)) | |
41 | ||
42 | ;;;; The ISAs | |
43 | ||
44 | ;; Logically, eBPF comforms a single instruction set featuring two | |
45 | ;; kind of instructions: 64-bit instructions and 128-bit instructions. | |
46 | ;; | |
47 | ;; The 64-bit instructions have the form: | |
48 | ;; | |
49 | ;; code:8 regs:8 offset:16 imm:32 | |
50 | ;; | |
51 | ;; Whereas the 128-bit instructions (at the moment there is only one | |
52 | ;; of such instructions, lddw) have the form: | |
53 | ;; | |
e042e6c3 | 54 | ;; code:8 regs:8 offset:16 imm:32 unused:32 imm:32 |
ea195bb0 JM |
55 | ;; |
56 | ;; In both formats `regs' is itself composed by two fields: | |
57 | ;; | |
58 | ;; dst:4 src:4 | |
59 | ;; | |
60 | ;; The ISA is supposed to be orthogonal to endianness: the endianness | |
61 | ;; of the instruction fields follow the endianness of the host running | |
62 | ;; the eBPF program, and that's all. However, this is not entirely | |
63 | ;; true. The definition of an eBPF code in the Linux kernel is: | |
64 | ;; | |
65 | ;; struct bpf_insn { | |
66 | ;; __u8 code; /* opcode */ | |
67 | ;; __u8 dst_reg:4; /* dest register */ | |
68 | ;; __u8 src_reg:4; /* source register */ | |
69 | ;; __s16 off; /* signed offset */ | |
70 | ;; __s32 imm; /* signed immediate constant */ | |
71 | ;; }; | |
72 | ;; | |
73 | ;; Since the ordering of fields in C bitmaps is defined by the | |
74 | ;; implementation, the impact of endianness in the encoding of eBPF | |
75 | ;; instructions is effectively defined by GCC. In particular, GCC | |
76 | ;; places dst_reg before src_reg in little-endian code, and the other | |
77 | ;; way around in big-endian code. | |
78 | ;; | |
79 | ;; So, in reality, eBPF comprises two instruction sets: one for | |
80 | ;; little-endian with instructions like: | |
81 | ;; | |
82 | ;; code:8 src:4 dst:4 offset:16 imm:32 [unused:32 imm:32] | |
83 | ;; | |
84 | ;; and another for big-endian with instructions like: | |
85 | ;; | |
86 | ;; code:8 dst:4 src:4 offset:16 imm:32 [unused:32 imm:32] | |
87 | ;; | |
88 | ;; where `offset' and the immediate fields are encoded in | |
89 | ;; little-endian and big-endian byte-order, respectively. | |
90 | ||
91 | (define-pmacro (define-bpf-isa x-endian) | |
92 | (define-isa | |
93 | (name (.sym ebpf x-endian)) | |
94 | (comment "The eBPF instruction set") | |
95 | ;; Default length to record in ifields. This is used in | |
96 | ;; calculations involving bit numbers. | |
97 | (default-insn-word-bitsize 64) | |
98 | ;; Length of an unknown instruction. Used by disassembly and by the | |
99 | ;; simulator's invalid insn handler. | |
100 | (default-insn-bitsize 64) | |
d8740be1 JM |
101 | ;; Number of bits of insn that can be initially fetched. This is |
102 | ;; the size of the smallest insn. | |
103 | (base-insn-bitsize 64))) | |
ea195bb0 JM |
104 | |
105 | (define-bpf-isa le) | |
106 | (define-bpf-isa be) | |
107 | ||
108 | (define-pmacro all-isas () (ISA ebpfle,ebpfbe)) | |
109 | ||
110 | ;;;; Hardware Hierarchy | |
111 | ||
112 | ;; | |
113 | ;; bpf architecture | |
114 | ;; | | |
115 | ;; bpfbf cpu-family | |
116 | ;; | | |
117 | ;; bpf machine | |
118 | ;; | | |
119 | ;; bpf-def model | |
120 | ||
121 | (define-cpu | |
122 | (name bpfbf) | |
123 | (comment "Linux kernel eBPF virtual CPU") | |
78c1c354 JM |
124 | (insn-endian big) |
125 | (word-bitsize 64)) | |
ea195bb0 JM |
126 | |
127 | (define-mach | |
128 | (name bpf) | |
129 | (comment "Linux eBPF") | |
130 | (cpu bpfbf) | |
131 | (isas ebpfle ebpfbe)) | |
132 | ||
133 | (define-model | |
134 | (name bpf-def) | |
135 | (comment "Linux eBPF default model") | |
136 | (mach bpf) | |
137 | (unit u-exec "execution unit" () | |
138 | 1 ; issue | |
139 | 1 ; done | |
140 | () ; state | |
141 | () ; inputs | |
142 | () ; outputs | |
143 | () ; profile action (default) | |
144 | )) | |
145 | ||
146 | ;;;; Hardware Elements | |
147 | ||
148 | ;; eBPF programs can access 10 general-purpose registers which are | |
149 | ;; 64-bit. | |
150 | ||
151 | (define-hardware | |
152 | (name h-gpr) | |
153 | (comment "General Purpose Registers") | |
154 | (attrs all-isas (MACH bpf)) | |
155 | (type register DI (16)) | |
156 | (indices keyword "%" | |
157 | ;; XXX the frame pointer fp is read-only, so it should | |
158 | ;; go in a different hardware. | |
159 | (;; ABI names. Take priority when disassembling. | |
231097b0 | 160 | (r0 0) (r1 1) (r2 2) (r3 3) (r4 4) (r5 5) (r6 6) |
ea195bb0 JM |
161 | (r7 7) (r8 8) (r9 9) (fp 10) |
162 | ;; Additional names recognized when assembling. | |
78c1c354 | 163 | (r0 0) (r6 6) (r10 10)))) |
ea195bb0 JM |
164 | |
165 | ;; The program counter. CGEN requires it, even if it is not visible | |
166 | ;; to eBPF programs. | |
167 | ||
78c1c354 JM |
168 | (define-hardware |
169 | (name h-pc) | |
170 | (comment "program counter") | |
171 | (attrs PC PROFILE all-isas) | |
172 | (type pc UDI) | |
173 | (get () (raw-reg h-pc)) | |
174 | (set (newval) (set (raw-reg h-pc) newval))) | |
175 | ||
ea195bb0 JM |
176 | ;; A 64-bit h-sint to be used by the imm64 operand below. XXX this |
177 | ;; shouldn't be needed, as h-sint is supposed to be able to hold | |
178 | ;; 64-bit values. However, in practice CGEN limits h-sint to 32 bits | |
179 | ;; in 32-bit hosts. To be fixed in CGEN. | |
180 | ||
181 | (dnh h-sint64 "signed 64-bit integer" (all-isas) (immediate DI) | |
182 | () () ()) | |
183 | ||
184 | ;;;; The Instruction Sets | |
185 | ||
186 | ;;; Fields and Opcodes | |
187 | ||
188 | ;; Convenience macro to shorten the definition of the fields below. | |
189 | (define-pmacro (dwf x-name x-comment x-attrs | |
190 | x-word-offset x-word-length x-start x-length | |
191 | x-mode) | |
192 | "Define a field including its containing word." | |
193 | (define-ifield | |
194 | (name x-name) | |
195 | (comment x-comment) | |
196 | (.splice attrs (.unsplice x-attrs)) | |
197 | (word-offset x-word-offset) | |
198 | (word-length x-word-length) | |
199 | (start x-start) | |
200 | (length x-length) | |
201 | (mode x-mode))) | |
202 | ||
203 | ;; For arithmetic and jump instructions the 8-bit code field is | |
204 | ;; subdivided in: | |
205 | ;; | |
206 | ;; op-code:4 op-src:1 op-class:3 | |
207 | ||
208 | (dwf f-op-code "eBPF opcode code" (all-isas) 0 8 7 4 UINT) | |
209 | (dwf f-op-src "eBPF opcode source" (all-isas) 0 8 3 1 UINT) | |
210 | (dwf f-op-class "eBPF opcode instruction class" (all-isas) 0 8 2 3 UINT) | |
211 | ||
212 | (define-normal-insn-enum insn-op-code-alu "eBPF instruction codes" | |
213 | (all-isas) OP_CODE_ f-op-code | |
214 | (;; Codes for OP_CLASS_ALU and OP_CLASS_ALU64 | |
215 | (ADD #x0) (SUB #x1) (MUL #x2) (DIV #x3) (OR #x4) (AND #x5) | |
216 | (LSH #x6) (RSH #x7) (NEG #x8) (MOD #x9) (XOR #xa) (MOV #xb) | |
217 | (ARSH #xc) (END #xd) | |
218 | ;; Codes for OP_CLASS_JMP | |
219 | (JA #x0) (JEQ #x1) (JGT #x2) (JGE #x3) (JSET #x4) | |
220 | (JNE #x5) (JSGT #x6) (JSGE #x7) (CALL #x8) (EXIT #x9) | |
221 | (JLT #xa) (JLE #xb) (JSLT #xc) (JSLE #xd))) | |
222 | ||
223 | (define-normal-insn-enum insn-op-src "eBPF instruction source" | |
224 | (all-isas) OP_SRC_ f-op-src | |
225 | ;; X => use `src' as source operand. | |
226 | ;; K => use `imm32' as source operand. | |
227 | ((K #b0) (X #b1))) | |
228 | ||
229 | (define-normal-insn-enum insn-op-class "eBPF instruction class" | |
230 | (all-isas) OP_CLASS_ f-op-class | |
231 | ((LD #b000) (LDX #b001) (ST #b010) (STX #b011) | |
c54a9b56 | 232 | (ALU #b100) (JMP #b101) (JMP32 #b110) (ALU64 #b111))) |
ea195bb0 JM |
233 | |
234 | ;; For load/store instructions, the 8-bit code field is subdivided in: | |
235 | ;; | |
236 | ;; op-mode:3 op-size:2 op-class:3 | |
237 | ||
238 | (dwf f-op-mode "eBPF opcode mode" (all-isas) 0 8 7 3 UINT) | |
239 | (dwf f-op-size "eBPF opcode size" (all-isas) 0 8 4 2 UINT) | |
240 | ||
241 | (define-normal-insn-enum insn-op-mode "eBPF load/store instruction modes" | |
242 | (all-isas) OP_MODE_ f-op-mode | |
243 | ((IMM #b000) (ABS #b001) (IND #b010) (MEM #b011) | |
244 | ;; #b100 and #b101 are used in classic BPF only, reserved in eBPF. | |
245 | (XADD #b110))) | |
246 | ||
247 | (define-normal-insn-enum insn-op-size "eBPF load/store instruction sizes" | |
248 | (all-isas) OP_SIZE_ f-op-size | |
249 | ((W #b00) ;; Word: 4 byte | |
250 | (H #b01) ;; Half-word: 2 byte | |
251 | (B #b10) ;; Byte: 1 byte | |
252 | (DW #b11))) ;; Double-word: 8 byte | |
253 | ||
254 | ;; The fields for the source and destination registers are a bit | |
255 | ;; tricky. Due to the bizarre nibble swap between little-endian and | |
256 | ;; big-endian ISAs we need to keep different variants of the fields. | |
257 | ;; | |
258 | ;; Note that f-regs is used in the format spec of instructions that do | |
259 | ;; NOT use registers, where endianness is irrelevant i.e. f-regs is a | |
260 | ;; constant 0 opcode. | |
261 | ||
262 | (dwf f-dstle "eBPF dst register field" ((ISA ebpfle)) 8 8 3 4 UINT) | |
263 | (dwf f-srcle "eBPF source register field" ((ISA ebpfle)) 8 8 7 4 UINT) | |
264 | ||
265 | (dwf f-dstbe "eBPF dst register field" ((ISA ebpfbe)) 8 8 7 4 UINT) | |
266 | (dwf f-srcbe "eBPF source register field" ((ISA ebpfbe)) 8 8 3 4 UINT) | |
267 | ||
268 | (dwf f-regs "eBPF registers field" (all-isas) 8 8 7 8 UINT) | |
269 | ||
270 | ;; Finally, the fields for the immediates. | |
271 | ;; | |
272 | ;; The 16-bit offsets and 32-bit immediates do not present any special | |
273 | ;; difficulty: we put them in their own instruction word so the | |
274 | ;; byte-endianness will be properly applied. | |
275 | ||
d73be611 | 276 | (dwf f-offset16 "eBPF offset field" (all-isas) 16 16 15 16 HI) |
ea195bb0 JM |
277 | (dwf f-imm32 "eBPF 32-bit immediate field" (all-isas) 32 32 31 32 INT) |
278 | ||
279 | ;; For the disjoint 64-bit signed immediate, however, we need to use a | |
280 | ;; multi-ifield. | |
281 | ||
282 | (dwf f-imm64-a "eBPF 64-bit immediate a" (all-isas) 32 32 31 32 UINT) | |
283 | (dwf f-imm64-b "eBPF 64-bit immediate b" (all-isas) 64 32 31 32 UINT) | |
284 | (dwf f-imm64-c "eBPF 64-bit immediate c" (all-isas) 96 32 31 32 UINT) | |
285 | ||
286 | (define-multi-ifield | |
287 | (name f-imm64) | |
288 | (comment "eBPF 64-bit immediate field") | |
289 | (attrs all-isas) | |
290 | (mode DI) | |
291 | (subfields f-imm64-a f-imm64-b f-imm64-c) | |
292 | (insert (sequence () | |
293 | (set (ifield f-imm64-b) (const 0)) | |
294 | (set (ifield f-imm64-c) (srl (ifield f-imm64) (const 32))) | |
295 | (set (ifield f-imm64-a) (and (ifield f-imm64) (const #xffffffff))))) | |
296 | (extract (sequence () | |
297 | (set (ifield f-imm64) | |
62e65990 AM |
298 | (or (sll UDI (zext UDI (ifield f-imm64-c)) (const 32)) |
299 | (zext UDI (ifield f-imm64-a))))))) | |
ea195bb0 JM |
300 | |
301 | ;;; Operands | |
302 | ||
303 | ;; A couple of source and destination register operands are defined | |
304 | ;; for each ISA: ebpfle and ebpfbe. | |
305 | ||
306 | (dno dstle "destination register" ((ISA ebpfle)) h-gpr f-dstle) | |
307 | (dno srcle "source register" ((ISA ebpfle)) h-gpr f-srcle) | |
308 | ||
309 | (dno dstbe "destination register" ((ISA ebpfbe)) h-gpr f-dstbe) | |
310 | (dno srcbe "source register" ((ISA ebpfbe)) h-gpr f-srcbe) | |
311 | ||
312 | ;; Jump instructions have a 16-bit PC-relative address. | |
313 | ;; CALL instructions have a 32-bit PC-relative address. | |
314 | ||
315 | (dno disp16 "16-bit PC-relative address" (all-isas PCREL-ADDR) h-sint | |
316 | f-offset16) | |
317 | (dno disp32 "32-bit PC-relative address" (all-isas PCREL-ADDR) h-sint | |
318 | f-imm32) | |
319 | ||
320 | ;; Immediate operands in eBPF are signed, and we want the disassembler | |
321 | ;; to print negative values in a sane way. Therefore we use the macro | |
322 | ;; below to register a printer, which is itself defined as a C | |
323 | ;; function in bpf.opc. | |
324 | ||
325 | ;; define-normal-signed-immediate-operand | |
326 | (define-pmacro (dnsio x-name x-comment x-attrs x-type x-index) | |
327 | (define-operand | |
328 | (name x-name) | |
329 | (comment x-comment) | |
330 | (.splice attrs (.unsplice x-attrs)) | |
331 | (type x-type) | |
332 | (index x-index) | |
333 | (handlers (print "immediate")))) | |
334 | ||
335 | (dnsio imm32 "32-bit immediate" (all-isas) h-sint f-imm32) | |
336 | (dnsio offset16 "16-bit offset" (all-isas) h-sint f-offset16) | |
337 | ||
338 | ;; The 64-bit immediate cannot use the default | |
339 | ;; cgen_parse_signed_integer, because it assumes operands are at much | |
340 | ;; 32-bit wide. Use our own. | |
341 | ||
342 | (define-operand | |
343 | (name imm64) | |
344 | (comment "64-bit immediate") | |
345 | (attrs all-isas) | |
346 | (type h-sint64) | |
347 | (index f-imm64) | |
348 | (handlers (parse "imm64") (print "immediate"))) | |
349 | ||
350 | ;; The endle/endbe instructions take an operand to specify the word | |
351 | ;; width in endianness conversions. We use both a parser and printer, | |
352 | ;; which are defined as C functions in bpf.opc. | |
353 | ||
354 | (define-operand | |
355 | (name endsize) | |
356 | (comment "endianness size immediate: 16, 32 or 64") | |
357 | (attrs all-isas) | |
358 | (type h-uint) | |
359 | (index f-imm32) | |
360 | (handlers (parse "endsize") (print "endsize"))) | |
361 | ||
362 | ;;; ALU instructions | |
363 | ||
364 | ;; For each opcode in insn-op-code-alu representing and integer | |
365 | ;; arithmetic instruction (ADD, SUB, etc) we define a bunch of | |
366 | ;; instruction variants: | |
367 | ;; | |
368 | ;; ADD[32]{i,r}le for the little-endian ISA | |
369 | ;; ADD[32]{i,r}be for the big-endian ISA | |
370 | ;; | |
78c1c354 JM |
371 | ;; The `i' variants perform `dst OP imm32 -> dst' operations. |
372 | ;; The `r' variants perform `dst OP src -> dst' operations. | |
ea195bb0 JM |
373 | ;; |
374 | ;; The variants with 32 in their name are of ALU class. Otherwise | |
375 | ;; they are ALU64 class. | |
376 | ||
78c1c354 JM |
377 | (define-pmacro (define-alu-insn-un x-basename x-suffix x-op-class x-op-code |
378 | x-endian x-mode x-semop) | |
ea195bb0 JM |
379 | (dni (.sym x-basename x-suffix x-endian) |
380 | (.str x-basename x-suffix) | |
381 | ((ISA (.sym ebpf x-endian))) | |
382 | (.str x-basename x-suffix " $dst" x-endian) | |
383 | (+ (f-imm32 0) (f-offset16 0) ((.sym f-src x-endian) 0) (.sym dst x-endian) | |
78c1c354 JM |
384 | x-op-class OP_SRC_K x-op-code) |
385 | (set x-mode (.sym dst x-endian) (x-semop x-mode (.sym dst x-endian))) | |
386 | ())) | |
ea195bb0 | 387 | |
78c1c354 JM |
388 | (define-pmacro (define-alu-insn-bin x-basename x-suffix x-op-class x-op-code |
389 | x-endian x-mode x-semop) | |
ea195bb0 | 390 | (begin |
78c1c354 | 391 | ;; dst = dst OP immediate |
ea195bb0 JM |
392 | (dni (.sym x-basename x-suffix "i" x-endian) |
393 | (.str x-basename x-suffix " immediate") | |
394 | ((ISA (.sym ebpf x-endian))) | |
395 | (.str x-basename x-suffix " $dst" x-endian ",$imm32") | |
396 | (+ imm32 (f-offset16 0) ((.sym f-src x-endian) 0) (.sym dst x-endian) | |
78c1c354 JM |
397 | x-op-class OP_SRC_K x-op-code) |
398 | (set x-mode (.sym dst x-endian) (x-semop x-mode (.sym dst x-endian) imm32)) | |
399 | ()) | |
400 | ;; dst = dst OP src | |
ea195bb0 JM |
401 | (dni (.sym x-basename x-suffix "r" x-endian) |
402 | (.str x-basename x-suffix " register") | |
403 | ((ISA (.sym ebpf x-endian))) | |
404 | (.str x-basename x-suffix " $dst" x-endian ",$src" x-endian) | |
405 | (+ (f-imm32 0) (f-offset16 0) (.sym src x-endian) (.sym dst x-endian) | |
78c1c354 JM |
406 | x-op-class OP_SRC_X x-op-code) |
407 | (set x-mode (.sym dst x-endian) | |
408 | (x-semop x-mode (.sym dst x-endian) (.sym src x-endian))) | |
409 | ()))) | |
410 | ||
411 | (define-pmacro (define-alu-insn-mov x-basename x-suffix x-op-class x-op-code | |
412 | x-endian x-mode) | |
413 | (begin | |
414 | (dni (.sym mov x-suffix "i" x-endian) | |
415 | (.str mov x-suffix " immediate") | |
416 | ((ISA (.sym ebpf x-endian))) | |
417 | (.str x-basename x-suffix " $dst" x-endian ",$imm32") | |
418 | (+ imm32 (f-offset16 0) ((.sym f-src x-endian) 0) (.sym dst x-endian) | |
419 | x-op-class OP_SRC_K x-op-code) | |
420 | (set x-mode (.sym dst x-endian) imm32) | |
421 | ()) | |
422 | (dni (.sym mov x-suffix "r" x-endian) | |
423 | (.str mov x-suffix " register") | |
424 | ((ISA (.sym ebpf x-endian))) | |
425 | (.str x-basename x-suffix " $dst" x-endian ",$src" x-endian) | |
426 | (+ (f-imm32 0) (f-offset16 0) (.sym src x-endian) (.sym dst x-endian) | |
427 | x-op-class OP_SRC_X x-op-code) | |
428 | (set x-mode (.sym dst x-endian) (.sym src x-endian)) | |
429 | ()))) | |
430 | ||
ea195bb0 | 431 | |
78c1c354 JM |
432 | ;; Unary ALU instructions (neg) |
433 | (define-pmacro (daiu x-basename x-op-code x-endian x-semop) | |
ea195bb0 | 434 | (begin |
78c1c354 JM |
435 | (define-alu-insn-un x-basename "" OP_CLASS_ALU64 x-op-code x-endian DI x-semop) |
436 | (define-alu-insn-un x-basename "32" OP_CLASS_ALU x-op-code x-endian USI x-semop))) | |
ea195bb0 | 437 | |
78c1c354 JM |
438 | ;; Binary ALU instructions (all the others) |
439 | ;; For ALU32: DST = (u32) DST OP (u32) SRC is correct semantics | |
440 | (define-pmacro (daib x-basename x-op-code x-endian x-semop) | |
ea195bb0 | 441 | (begin |
78c1c354 JM |
442 | (define-alu-insn-bin x-basename "" OP_CLASS_ALU64 x-op-code x-endian DI x-semop) |
443 | (define-alu-insn-bin x-basename "32" OP_CLASS_ALU x-op-code x-endian USI x-semop))) | |
444 | ||
445 | ;; Move ALU instructions (mov) | |
446 | (define-pmacro (daim x-basename x-op-code x-endian) | |
447 | (begin | |
448 | (define-alu-insn-mov x-basename "" OP_CLASS_ALU64 x-op-code x-endian DI) | |
449 | (define-alu-insn-mov x-basename "32" OP_CLASS_ALU x-op-code x-endian USI))) | |
ea195bb0 JM |
450 | |
451 | (define-pmacro (define-alu-instructions x-endian) | |
452 | (begin | |
78c1c354 JM |
453 | (daib add OP_CODE_ADD x-endian add) |
454 | (daib sub OP_CODE_SUB x-endian sub) | |
455 | (daib mul OP_CODE_MUL x-endian mul) | |
456 | (daib div OP_CODE_DIV x-endian div) | |
457 | (daib or OP_CODE_OR x-endian or) | |
458 | (daib and OP_CODE_AND x-endian and) | |
459 | (daib lsh OP_CODE_LSH x-endian sll) | |
460 | (daib rsh OP_CODE_RSH x-endian srl) | |
461 | (daib mod OP_CODE_MOD x-endian mod) | |
462 | (daib xor OP_CODE_XOR x-endian xor) | |
463 | (daib arsh OP_CODE_ARSH x-endian sra) | |
464 | (daiu neg OP_CODE_NEG x-endian neg) | |
465 | (daim mov OP_CODE_MOV x-endian))) | |
ea195bb0 JM |
466 | |
467 | (define-alu-instructions le) | |
468 | (define-alu-instructions be) | |
469 | ||
470 | ;;; Endianness conversion instructions | |
471 | ||
472 | ;; The endianness conversion instructions come in several variants: | |
473 | ;; | |
474 | ;; END{le,be}le for the little-endian ISA | |
475 | ;; END{le,be}be for the big-endian ISA | |
476 | ;; | |
477 | ;; Please do not be confused by the repeated `be' and `le' here. Each | |
478 | ;; ISA has both endle and endbe instructions. It is the disposition | |
479 | ;; of the source and destination register fields that change between | |
480 | ;; ISAs, not the semantics of the instructions themselves (see section | |
481 | ;; "The ISAs" above in this very file.) | |
482 | ||
483 | (define-pmacro (define-endian-insn x-suffix x-op-src x-endian) | |
484 | (dni (.sym "end" x-suffix x-endian) | |
485 | (.str "end" x-suffix " register") | |
486 | ((ISA (.sym ebpf x-endian))) | |
487 | (.str "end" x-suffix " $dst" x-endian ",$endsize") | |
488 | (+ (f-offset16 0) ((.sym f-src x-endian) 0) (.sym dst x-endian) endsize | |
78c1c354 JM |
489 | OP_CLASS_ALU x-op-src OP_CODE_END) |
490 | (set (.sym dst x-endian) | |
d73be611 | 491 | (c-call DI (.str "bpfbf_end" x-suffix) (.sym dst x-endian) endsize)) |
78c1c354 | 492 | ())) |
ea195bb0 JM |
493 | |
494 | (define-endian-insn "le" OP_SRC_K le) | |
495 | (define-endian-insn "be" OP_SRC_X le) | |
496 | (define-endian-insn "le" OP_SRC_K be) | |
497 | (define-endian-insn "be" OP_SRC_X be) | |
498 | ||
499 | ;;; Load/Store instructions | |
500 | ||
501 | ;; The lddw instruction takes a 64-bit immediate as an operand. Since | |
502 | ;; this instruction also takes a `dst' operand, we need to define a | |
503 | ;; variant for each ISA: | |
504 | ;; | |
505 | ;; LDDWle for the little-endian ISA | |
506 | ;; LDDWbe for the big-endian ISA | |
507 | ||
508 | (define-pmacro (define-lddw x-endian) | |
509 | (dni (.sym lddw x-endian) | |
510 | (.str "lddw" x-endian) | |
511 | ((ISA (.sym ebpf x-endian))) | |
512 | (.str "lddw $dst" x-endian ",$imm64") | |
513 | (+ imm64 (f-offset16 0) ((.sym f-src x-endian) 0) | |
514 | (.sym dst x-endian) | |
78c1c354 JM |
515 | OP_CLASS_LD OP_SIZE_DW OP_MODE_IMM) |
516 | (set DI (.sym dst x-endian) imm64) | |
517 | ())) | |
ea195bb0 JM |
518 | |
519 | (define-lddw le) | |
520 | (define-lddw be) | |
521 | ||
3719fd55 JM |
522 | ;; The absolute load instructions are non-generic loads designed to be |
523 | ;; used in socket filters. They come in several variants: | |
ea195bb0 | 524 | ;; |
3719fd55 JM |
525 | ;; LDABS{w,h,b,dw} |
526 | ||
78c1c354 | 527 | (define-pmacro (dlabs x-suffix x-size x-smode) |
3719fd55 JM |
528 | (dni (.sym "ldabs" x-suffix) |
529 | (.str "ldabs" x-suffix) | |
530 | (all-isas) | |
531 | (.str "ldabs" x-suffix " $imm32") | |
532 | (+ imm32 (f-offset16 0) (f-regs 0) | |
533 | OP_CLASS_LD OP_MODE_ABS (.sym OP_SIZE_ x-size)) | |
78c1c354 JM |
534 | (set x-smode |
535 | (reg x-smode h-gpr 0) | |
536 | (mem x-smode | |
537 | (add DI | |
538 | (mem DI | |
539 | (add DI | |
540 | (reg DI h-gpr 6) ;; Pointer to struct sk_buff | |
d73be611 | 541 | (c-call "bpfbf_skb_data_offset"))) |
78c1c354 JM |
542 | imm32))) |
543 | ;; XXX this clobbers R1-R5 | |
544 | ())) | |
545 | ||
546 | (dlabs "w" W SI) | |
547 | (dlabs "h" H HI) | |
548 | (dlabs "b" B QI) | |
549 | (dlabs "dw" DW DI) | |
3719fd55 JM |
550 | |
551 | ;; The indirect load instructions are non-generic loads designed to be | |
552 | ;; used in socket filters. They come in several variants: | |
553 | ;; | |
554 | ;; LDIND{w,h,b,dw}le for the little-endian ISA | |
555 | ;; LDIND[w,h,b,dw}be for the big-endian ISA | |
ea195bb0 | 556 | |
78c1c354 | 557 | (define-pmacro (dlind x-suffix x-size x-endian x-smode) |
3719fd55 JM |
558 | (dni (.sym "ldind" x-suffix x-endian) |
559 | (.str "ldind" x-suffix) | |
ea195bb0 | 560 | ((ISA (.sym ebpf x-endian))) |
3719fd55 | 561 | (.str "ldind" x-suffix " $src" x-endian ",$imm32") |
92434a14 | 562 | (+ imm32 (f-offset16 0) ((.sym f-dst x-endian) 0) (.sym src x-endian) |
3719fd55 | 563 | OP_CLASS_LD OP_MODE_IND (.sym OP_SIZE_ x-size)) |
78c1c354 JM |
564 | (set x-smode |
565 | (reg x-smode h-gpr 0) | |
566 | (mem x-smode | |
567 | (add DI | |
568 | (mem DI | |
569 | (add DI | |
570 | (reg DI h-gpr 6) ;; Pointer to struct sk_buff | |
d73be611 | 571 | (c-call "bpfbf_skb_data_offset"))) |
78c1c354 JM |
572 | (add DI |
573 | (.sym src x-endian) | |
574 | imm32)))) | |
575 | ;; XXX this clobbers R1-R5 | |
576 | ())) | |
3719fd55 JM |
577 | |
578 | (define-pmacro (define-ldind x-endian) | |
579 | (begin | |
78c1c354 JM |
580 | (dlind "w" W x-endian SI) |
581 | (dlind "h" H x-endian HI) | |
582 | (dlind "b" B x-endian QI) | |
583 | (dlind "dw" DW x-endian DI))) | |
3719fd55 JM |
584 | |
585 | (define-ldind le) | |
586 | (define-ldind be) | |
ea195bb0 JM |
587 | |
588 | ;; Generic load and store instructions are provided for several word | |
589 | ;; sizes. They come in several variants: | |
590 | ;; | |
591 | ;; LDX{b,h,w,dw}le, STX{b,h,w,dw}le for the little-endian ISA | |
592 | ;; | |
593 | ;; LDX{b,h,w,dw}be, STX{b,h,w,dw}be for the big-endian ISA | |
594 | ;; | |
595 | ;; Loads operate on [$SRC+-OFFSET] -> $DST | |
596 | ;; Stores operate on $SRC -> [$DST+-OFFSET] | |
597 | ||
78c1c354 | 598 | (define-pmacro (dxli x-basename x-suffix x-size x-endian x-mode) |
ea195bb0 JM |
599 | (dni (.sym x-basename x-suffix x-endian) |
600 | (.str x-basename x-suffix) | |
601 | ((ISA (.sym ebpf x-endian))) | |
602 | (.str x-basename x-suffix " $dst" x-endian ",[$src" x-endian "+$offset16]") | |
603 | (+ (f-imm32 0) offset16 (.sym src x-endian) (.sym dst x-endian) | |
604 | OP_CLASS_LDX (.sym OP_SIZE_ x-size) OP_MODE_MEM) | |
78c1c354 JM |
605 | (set x-mode |
606 | (.sym dst x-endian) | |
d73be611 | 607 | (mem x-mode (add DI (.sym src x-endian) offset16))) |
78c1c354 | 608 | ())) |
ea195bb0 | 609 | |
78c1c354 | 610 | (define-pmacro (dxsi x-basename x-suffix x-size x-endian x-mode) |
ea195bb0 JM |
611 | (dni (.sym x-basename x-suffix x-endian) |
612 | (.str x-basename x-suffix) | |
613 | ((ISA (.sym ebpf x-endian))) | |
614 | (.str x-basename x-suffix " [$dst" x-endian "+$offset16],$src" x-endian) | |
615 | (+ (f-imm32 0) offset16 (.sym src x-endian) (.sym dst x-endian) | |
616 | OP_CLASS_STX (.sym OP_SIZE_ x-size) OP_MODE_MEM) | |
78c1c354 | 617 | (set x-mode |
d73be611 | 618 | (mem x-mode (add DI (.sym dst x-endian) offset16)) |
78c1c354 JM |
619 | (.sym src x-endian)) ;; XXX address is section-relative |
620 | ())) | |
ea195bb0 JM |
621 | |
622 | (define-pmacro (define-ldstx-insns x-endian) | |
623 | (begin | |
78c1c354 JM |
624 | (dxli "ldx" "w" W x-endian SI) |
625 | (dxli "ldx" "h" H x-endian HI) | |
626 | (dxli "ldx" "b" B x-endian QI) | |
627 | (dxli "ldx" "dw" DW x-endian DI) | |
ea195bb0 | 628 | |
78c1c354 JM |
629 | (dxsi "stx" "w" W x-endian SI) |
630 | (dxsi "stx" "h" H x-endian HI) | |
631 | (dxsi "stx" "b" B x-endian QI) | |
632 | (dxsi "stx" "dw" DW x-endian DI))) | |
ea195bb0 JM |
633 | |
634 | (define-ldstx-insns le) | |
635 | (define-ldstx-insns be) | |
636 | ||
637 | ;; Generic store instructions of the form IMM32 -> [$DST+OFFSET] are | |
638 | ;; provided in several variants: | |
639 | ;; | |
640 | ;; ST{b,h,w,dw}le for the little-endian ISA | |
641 | ;; ST{b,h,w,dw}be for the big-endian ISA | |
642 | ||
78c1c354 | 643 | (define-pmacro (dsti x-suffix x-size x-endian x-mode) |
ea195bb0 JM |
644 | (dni (.sym "st" x-suffix x-endian) |
645 | (.str "st" x-suffix) | |
646 | ((ISA (.sym ebpf x-endian))) | |
647 | (.str "st" x-suffix " [$dst" x-endian "+$offset16],$imm32") | |
648 | (+ imm32 offset16 ((.sym f-src x-endian) 0) (.sym dst x-endian) | |
78c1c354 JM |
649 | OP_CLASS_ST (.sym OP_SIZE_ x-size) OP_MODE_MEM) |
650 | (set x-mode | |
651 | (mem x-mode (add DI (.sym dst x-endian) offset16)) | |
652 | imm32) ;; XXX address is section-relative | |
653 | ())) | |
ea195bb0 JM |
654 | |
655 | (define-pmacro (define-st-insns x-endian) | |
656 | (begin | |
78c1c354 JM |
657 | (dsti "b" B x-endian QI) |
658 | (dsti "h" H x-endian HI) | |
659 | (dsti "w" W x-endian SI) | |
660 | (dsti "dw" DW x-endian DI))) | |
ea195bb0 JM |
661 | |
662 | (define-st-insns le) | |
663 | (define-st-insns be) | |
664 | ||
665 | ;;; Jump instructions | |
666 | ||
667 | ;; Compare-and-jump instructions, on the other hand, make use of | |
668 | ;; registers. Therefore, we need to define several variants in both | |
669 | ;; ISAs: | |
670 | ;; | |
c54a9b56 | 671 | ;; J{eq,gt,ge,lt,le,set,ne,sgt,sge,slt,sle}[32]{i,r}le for the |
ea195bb0 | 672 | ;; little-endian ISA. |
c54a9b56 | 673 | ;; J{eq,gt,ge,lt,le,set,ne.sgt,sge,slt,sle}[32]{i,r}be for the |
ea195bb0 JM |
674 | ;; big-endian ISA. |
675 | ||
78c1c354 | 676 | (define-pmacro (define-cond-jump-insn x-cond x-suffix x-op-class x-op-code x-endian x-mode x-semop) |
ea195bb0 | 677 | (begin |
c54a9b56 DF |
678 | (dni (.sym j x-cond x-suffix i x-endian) |
679 | (.str j x-cond x-suffix " i") | |
ea195bb0 | 680 | ((ISA (.sym ebpf x-endian))) |
c54a9b56 | 681 | (.str "j" x-cond x-suffix " $dst" x-endian ",$imm32,$disp16") |
ea195bb0 | 682 | (+ imm32 disp16 ((.sym f-src x-endian) 0) (.sym dst x-endian) |
78c1c354 JM |
683 | x-op-class OP_SRC_K (.sym OP_CODE_ x-op-code)) |
684 | (if VOID (x-semop x-mode (.sym dst x-endian) imm32) | |
685 | (set DI | |
686 | (reg DI h-pc) (add DI (reg DI h-pc) | |
687 | (mul DI (add HI disp16 1) 8)))) | |
688 | ()) | |
c54a9b56 DF |
689 | (dni (.sym j x-cond x-suffix r x-endian) |
690 | (.str j x-cond x-suffix " r") | |
ea195bb0 | 691 | ((ISA (.sym ebpf x-endian))) |
c54a9b56 | 692 | (.str "j" x-cond x-suffix " $dst" x-endian ",$src" x-endian ",$disp16") |
ea195bb0 | 693 | (+ (f-imm32 0) disp16 (.sym src x-endian) (.sym dst x-endian) |
78c1c354 JM |
694 | x-op-class OP_SRC_X (.sym OP_CODE_ x-op-code)) |
695 | (if VOID (x-semop x-mode (.sym dst x-endian) (.sym src x-endian)) | |
696 | (set DI | |
697 | (reg DI h-pc) (add DI (reg DI h-pc) | |
698 | (mul DI (add HI disp16 1) 8)))) | |
699 | ()))) | |
700 | ||
701 | (define-pmacro (dcji x-cond x-op-code x-endian x-semop) | |
c54a9b56 | 702 | (begin |
78c1c354 JM |
703 | (define-cond-jump-insn x-cond "" OP_CLASS_JMP x-op-code x-endian DI x-semop) |
704 | (define-cond-jump-insn x-cond "32" OP_CLASS_JMP32 x-op-code x-endian SI x-semop ))) | |
ea195bb0 JM |
705 | |
706 | (define-pmacro (define-condjump-insns x-endian) | |
707 | (begin | |
78c1c354 JM |
708 | (dcji "eq" JEQ x-endian eq) |
709 | (dcji "gt" JGT x-endian gtu) | |
710 | (dcji "ge" JGE x-endian geu) | |
711 | (dcji "lt" JLT x-endian ltu) | |
712 | (dcji "le" JLE x-endian leu) | |
713 | (dcji "set" JSET x-endian and) | |
714 | (dcji "ne" JNE x-endian ne) | |
715 | (dcji "sgt" JSGT x-endian gt) | |
716 | (dcji "sge" JSGE x-endian ge) | |
717 | (dcji "slt" JSLT x-endian lt) | |
718 | (dcji "sle" JSLE x-endian le))) | |
ea195bb0 JM |
719 | |
720 | (define-condjump-insns le) | |
721 | (define-condjump-insns be) | |
722 | ||
78c1c354 JM |
723 | ;; The `call' instruction doesn't make use of registers, but the |
724 | ;; semantic routine should have access to the src register in order to | |
725 | ;; properly interpret the meaning of disp32. Therefore we need one | |
726 | ;; version per ISA. | |
727 | ||
728 | (define-pmacro (define-call-insn x-endian) | |
729 | (dni (.sym call x-endian) | |
730 | "call" | |
731 | ((ISA (.sym ebpf x-endian))) | |
732 | "call $disp32" | |
733 | (+ disp32 (f-offset16 0) (f-regs 0) | |
734 | OP_CLASS_JMP OP_SRC_K OP_CODE_CALL) | |
735 | (c-call VOID | |
736 | "bpfbf_call" disp32 (ifield (.sym f-src x-endian))) | |
737 | ())) | |
738 | ||
739 | (define-call-insn le) | |
740 | (define-call-insn be) | |
741 | ||
742 | ;; The jump-always and `exit' instructions dont make use of either | |
743 | ;; source nor destination registers, so only one variant per | |
ea195bb0 JM |
744 | ;; instruction is defined. |
745 | ||
746 | (dni ja "ja" (all-isas) "ja $disp16" | |
747 | (+ (f-imm32 0) disp16 (f-regs 0) | |
78c1c354 JM |
748 | OP_CLASS_JMP OP_SRC_K OP_CODE_JA) |
749 | (set DI (reg DI h-pc) (add DI (reg DI h-pc) | |
750 | (mul DI (add HI disp16 1) 8))) | |
751 | ()) | |
ea195bb0 JM |
752 | |
753 | (dni "exit" "exit" (all-isas) "exit" | |
754 | (+ (f-imm32 0) (f-offset16 0) (f-regs 0) | |
78c1c354 JM |
755 | OP_CLASS_JMP (f-op-src 0) OP_CODE_EXIT) |
756 | (c-call VOID "bpfbf_exit") | |
757 | ()) | |
ea195bb0 JM |
758 | |
759 | ;;; Atomic instructions | |
760 | ||
761 | ;; The atomic exchange-and-add instructions come in two flavors: one | |
762 | ;; for swapping 64-bit quantities and another for 32-bit quantities. | |
763 | ||
78c1c354 JM |
764 | (define-pmacro (sem-exchange-and-add x-endian x-mode) |
765 | (sequence VOID ((x-mode tmp)) | |
766 | ;; XXX acquire lock in simulator... as a hardware element? | |
767 | (set x-mode tmp (mem x-mode (add DI (.sym dst x-endian) offset16))) | |
768 | (set x-mode | |
769 | (mem x-mode (add DI (.sym dst x-endian) offset16)) | |
770 | (add x-mode tmp (.sym src x-endian))))) | |
771 | ||
ea195bb0 JM |
772 | (define-pmacro (define-atomic-insns x-endian) |
773 | (begin | |
774 | (dni (.str "xadddw" x-endian) | |
775 | "xadddw" | |
776 | ((ISA (.sym ebpf x-endian))) | |
777 | (.str "xadddw [$dst" x-endian "+$offset16],$src" x-endian) | |
778 | (+ (f-imm32 0) (.sym src x-endian) (.sym dst x-endian) | |
78c1c354 JM |
779 | offset16 OP_MODE_XADD OP_SIZE_DW OP_CLASS_STX) |
780 | (sem-exchange-and-add x-endian DI) | |
781 | ()) | |
ea195bb0 JM |
782 | (dni (.str "xaddw" x-endian) |
783 | "xaddw" | |
784 | ((ISA (.sym ebpf x-endian))) | |
785 | (.str "xaddw [$dst" x-endian "+$offset16],$src" x-endian) | |
786 | (+ (f-imm32 0) (.sym src x-endian) (.sym dst x-endian) | |
78c1c354 JM |
787 | offset16 OP_MODE_XADD OP_SIZE_W OP_CLASS_STX) |
788 | (sem-exchange-and-add x-endian SI) | |
789 | ()))) | |
ea195bb0 JM |
790 | |
791 | (define-atomic-insns le) | |
792 | (define-atomic-insns be) | |
78c1c354 JM |
793 | |
794 | ;;; Breakpoint instruction | |
795 | ||
796 | ;; The brkpt instruction is used by the BPF simulator and it doesn't | |
797 | ;; really belong to the eBPF instruction set. | |
798 | ||
799 | (dni "brkpt" "brkpt" (all-isas) "brkpt" | |
800 | (+ (f-imm32 0) (f-offset16 0) (f-regs 0) | |
801 | OP_CLASS_ALU OP_SRC_X OP_CODE_NEG) | |
802 | (c-call VOID "bpfbf_breakpoint") | |
803 | ()) |