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) | |
35 | (machs bpf) | |
36 | (isas ebpfle ebpfbe)) | |
37 | ||
38 | ;;;; The ISAs | |
39 | ||
40 | ;; Logically, eBPF comforms a single instruction set featuring two | |
41 | ;; kind of instructions: 64-bit instructions and 128-bit instructions. | |
42 | ;; | |
43 | ;; The 64-bit instructions have the form: | |
44 | ;; | |
45 | ;; code:8 regs:8 offset:16 imm:32 | |
46 | ;; | |
47 | ;; Whereas the 128-bit instructions (at the moment there is only one | |
48 | ;; of such instructions, lddw) have the form: | |
49 | ;; | |
e042e6c3 | 50 | ;; code:8 regs:8 offset:16 imm:32 unused:32 imm:32 |
ea195bb0 JM |
51 | ;; |
52 | ;; In both formats `regs' is itself composed by two fields: | |
53 | ;; | |
54 | ;; dst:4 src:4 | |
55 | ;; | |
56 | ;; The ISA is supposed to be orthogonal to endianness: the endianness | |
57 | ;; of the instruction fields follow the endianness of the host running | |
58 | ;; the eBPF program, and that's all. However, this is not entirely | |
59 | ;; true. The definition of an eBPF code in the Linux kernel is: | |
60 | ;; | |
61 | ;; struct bpf_insn { | |
62 | ;; __u8 code; /* opcode */ | |
63 | ;; __u8 dst_reg:4; /* dest register */ | |
64 | ;; __u8 src_reg:4; /* source register */ | |
65 | ;; __s16 off; /* signed offset */ | |
66 | ;; __s32 imm; /* signed immediate constant */ | |
67 | ;; }; | |
68 | ;; | |
69 | ;; Since the ordering of fields in C bitmaps is defined by the | |
70 | ;; implementation, the impact of endianness in the encoding of eBPF | |
71 | ;; instructions is effectively defined by GCC. In particular, GCC | |
72 | ;; places dst_reg before src_reg in little-endian code, and the other | |
73 | ;; way around in big-endian code. | |
74 | ;; | |
75 | ;; So, in reality, eBPF comprises two instruction sets: one for | |
76 | ;; little-endian with instructions like: | |
77 | ;; | |
78 | ;; code:8 src:4 dst:4 offset:16 imm:32 [unused:32 imm:32] | |
79 | ;; | |
80 | ;; and another for big-endian with instructions like: | |
81 | ;; | |
82 | ;; code:8 dst:4 src:4 offset:16 imm:32 [unused:32 imm:32] | |
83 | ;; | |
84 | ;; where `offset' and the immediate fields are encoded in | |
85 | ;; little-endian and big-endian byte-order, respectively. | |
86 | ||
87 | (define-pmacro (define-bpf-isa x-endian) | |
88 | (define-isa | |
89 | (name (.sym ebpf x-endian)) | |
90 | (comment "The eBPF instruction set") | |
91 | ;; Default length to record in ifields. This is used in | |
92 | ;; calculations involving bit numbers. | |
93 | (default-insn-word-bitsize 64) | |
94 | ;; Length of an unknown instruction. Used by disassembly and by the | |
95 | ;; simulator's invalid insn handler. | |
96 | (default-insn-bitsize 64) | |
97 | ;; Number of bits of insn that can be initially fetched. XXX this | |
98 | ;; should be 64 (the size of the smallest insn) but until CGEN | |
99 | ;; gets fixed to place constant fields in their own words, we have | |
100 | ;; to use this workaround to avoid the opcode byte to be placed at | |
101 | ;; the wrong side of the instruction when assembling in | |
102 | ;; big-endian. | |
103 | (base-insn-bitsize 8))) | |
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") | |
124 | (word-bitsize 32)) | |
125 | ||
126 | (define-mach | |
127 | (name bpf) | |
128 | (comment "Linux eBPF") | |
129 | (cpu bpfbf) | |
130 | (isas ebpfle ebpfbe)) | |
131 | ||
132 | (define-model | |
133 | (name bpf-def) | |
134 | (comment "Linux eBPF default model") | |
135 | (mach bpf) | |
136 | (unit u-exec "execution unit" () | |
137 | 1 ; issue | |
138 | 1 ; done | |
139 | () ; state | |
140 | () ; inputs | |
141 | () ; outputs | |
142 | () ; profile action (default) | |
143 | )) | |
144 | ||
145 | ;;;; Hardware Elements | |
146 | ||
147 | ;; eBPF programs can access 10 general-purpose registers which are | |
148 | ;; 64-bit. | |
149 | ||
150 | (define-hardware | |
151 | (name h-gpr) | |
152 | (comment "General Purpose Registers") | |
153 | (attrs all-isas (MACH bpf)) | |
154 | (type register DI (16)) | |
155 | (indices keyword "%" | |
156 | ;; XXX the frame pointer fp is read-only, so it should | |
157 | ;; go in a different hardware. | |
158 | (;; ABI names. Take priority when disassembling. | |
231097b0 | 159 | (r0 0) (r1 1) (r2 2) (r3 3) (r4 4) (r5 5) (r6 6) |
ea195bb0 JM |
160 | (r7 7) (r8 8) (r9 9) (fp 10) |
161 | ;; Additional names recognized when assembling. | |
231097b0 | 162 | (a 0) (ctx 6) (r10 10)))) |
ea195bb0 JM |
163 | |
164 | ;; The program counter. CGEN requires it, even if it is not visible | |
165 | ;; to eBPF programs. | |
166 | ||
167 | (dnh h-pc "program counter" (PC PROFILE) (pc) () () ()) | |
168 | ||
169 | ;; A 64-bit h-sint to be used by the imm64 operand below. XXX this | |
170 | ;; shouldn't be needed, as h-sint is supposed to be able to hold | |
171 | ;; 64-bit values. However, in practice CGEN limits h-sint to 32 bits | |
172 | ;; in 32-bit hosts. To be fixed in CGEN. | |
173 | ||
174 | (dnh h-sint64 "signed 64-bit integer" (all-isas) (immediate DI) | |
175 | () () ()) | |
176 | ||
177 | ;;;; The Instruction Sets | |
178 | ||
179 | ;;; Fields and Opcodes | |
180 | ||
181 | ;; Convenience macro to shorten the definition of the fields below. | |
182 | (define-pmacro (dwf x-name x-comment x-attrs | |
183 | x-word-offset x-word-length x-start x-length | |
184 | x-mode) | |
185 | "Define a field including its containing word." | |
186 | (define-ifield | |
187 | (name x-name) | |
188 | (comment x-comment) | |
189 | (.splice attrs (.unsplice x-attrs)) | |
190 | (word-offset x-word-offset) | |
191 | (word-length x-word-length) | |
192 | (start x-start) | |
193 | (length x-length) | |
194 | (mode x-mode))) | |
195 | ||
196 | ;; For arithmetic and jump instructions the 8-bit code field is | |
197 | ;; subdivided in: | |
198 | ;; | |
199 | ;; op-code:4 op-src:1 op-class:3 | |
200 | ||
201 | (dwf f-op-code "eBPF opcode code" (all-isas) 0 8 7 4 UINT) | |
202 | (dwf f-op-src "eBPF opcode source" (all-isas) 0 8 3 1 UINT) | |
203 | (dwf f-op-class "eBPF opcode instruction class" (all-isas) 0 8 2 3 UINT) | |
204 | ||
205 | (define-normal-insn-enum insn-op-code-alu "eBPF instruction codes" | |
206 | (all-isas) OP_CODE_ f-op-code | |
207 | (;; Codes for OP_CLASS_ALU and OP_CLASS_ALU64 | |
208 | (ADD #x0) (SUB #x1) (MUL #x2) (DIV #x3) (OR #x4) (AND #x5) | |
209 | (LSH #x6) (RSH #x7) (NEG #x8) (MOD #x9) (XOR #xa) (MOV #xb) | |
210 | (ARSH #xc) (END #xd) | |
211 | ;; Codes for OP_CLASS_JMP | |
212 | (JA #x0) (JEQ #x1) (JGT #x2) (JGE #x3) (JSET #x4) | |
213 | (JNE #x5) (JSGT #x6) (JSGE #x7) (CALL #x8) (EXIT #x9) | |
214 | (JLT #xa) (JLE #xb) (JSLT #xc) (JSLE #xd))) | |
215 | ||
216 | (define-normal-insn-enum insn-op-src "eBPF instruction source" | |
217 | (all-isas) OP_SRC_ f-op-src | |
218 | ;; X => use `src' as source operand. | |
219 | ;; K => use `imm32' as source operand. | |
220 | ((K #b0) (X #b1))) | |
221 | ||
222 | (define-normal-insn-enum insn-op-class "eBPF instruction class" | |
223 | (all-isas) OP_CLASS_ f-op-class | |
224 | ((LD #b000) (LDX #b001) (ST #b010) (STX #b011) | |
225 | (ALU #b100) (JMP #b101) (ALU64 #b111))) | |
226 | ||
227 | ;; For load/store instructions, the 8-bit code field is subdivided in: | |
228 | ;; | |
229 | ;; op-mode:3 op-size:2 op-class:3 | |
230 | ||
231 | (dwf f-op-mode "eBPF opcode mode" (all-isas) 0 8 7 3 UINT) | |
232 | (dwf f-op-size "eBPF opcode size" (all-isas) 0 8 4 2 UINT) | |
233 | ||
234 | (define-normal-insn-enum insn-op-mode "eBPF load/store instruction modes" | |
235 | (all-isas) OP_MODE_ f-op-mode | |
236 | ((IMM #b000) (ABS #b001) (IND #b010) (MEM #b011) | |
237 | ;; #b100 and #b101 are used in classic BPF only, reserved in eBPF. | |
238 | (XADD #b110))) | |
239 | ||
240 | (define-normal-insn-enum insn-op-size "eBPF load/store instruction sizes" | |
241 | (all-isas) OP_SIZE_ f-op-size | |
242 | ((W #b00) ;; Word: 4 byte | |
243 | (H #b01) ;; Half-word: 2 byte | |
244 | (B #b10) ;; Byte: 1 byte | |
245 | (DW #b11))) ;; Double-word: 8 byte | |
246 | ||
247 | ;; The fields for the source and destination registers are a bit | |
248 | ;; tricky. Due to the bizarre nibble swap between little-endian and | |
249 | ;; big-endian ISAs we need to keep different variants of the fields. | |
250 | ;; | |
251 | ;; Note that f-regs is used in the format spec of instructions that do | |
252 | ;; NOT use registers, where endianness is irrelevant i.e. f-regs is a | |
253 | ;; constant 0 opcode. | |
254 | ||
255 | (dwf f-dstle "eBPF dst register field" ((ISA ebpfle)) 8 8 3 4 UINT) | |
256 | (dwf f-srcle "eBPF source register field" ((ISA ebpfle)) 8 8 7 4 UINT) | |
257 | ||
258 | (dwf f-dstbe "eBPF dst register field" ((ISA ebpfbe)) 8 8 7 4 UINT) | |
259 | (dwf f-srcbe "eBPF source register field" ((ISA ebpfbe)) 8 8 3 4 UINT) | |
260 | ||
261 | (dwf f-regs "eBPF registers field" (all-isas) 8 8 7 8 UINT) | |
262 | ||
263 | ;; Finally, the fields for the immediates. | |
264 | ;; | |
265 | ;; The 16-bit offsets and 32-bit immediates do not present any special | |
266 | ;; difficulty: we put them in their own instruction word so the | |
267 | ;; byte-endianness will be properly applied. | |
268 | ||
269 | (dwf f-offset16 "eBPF offset field" (all-isas) 16 16 15 16 INT) | |
270 | (dwf f-imm32 "eBPF 32-bit immediate field" (all-isas) 32 32 31 32 INT) | |
271 | ||
272 | ;; For the disjoint 64-bit signed immediate, however, we need to use a | |
273 | ;; multi-ifield. | |
274 | ||
275 | (dwf f-imm64-a "eBPF 64-bit immediate a" (all-isas) 32 32 31 32 UINT) | |
276 | (dwf f-imm64-b "eBPF 64-bit immediate b" (all-isas) 64 32 31 32 UINT) | |
277 | (dwf f-imm64-c "eBPF 64-bit immediate c" (all-isas) 96 32 31 32 UINT) | |
278 | ||
279 | (define-multi-ifield | |
280 | (name f-imm64) | |
281 | (comment "eBPF 64-bit immediate field") | |
282 | (attrs all-isas) | |
283 | (mode DI) | |
284 | (subfields f-imm64-a f-imm64-b f-imm64-c) | |
285 | (insert (sequence () | |
286 | (set (ifield f-imm64-b) (const 0)) | |
287 | (set (ifield f-imm64-c) (srl (ifield f-imm64) (const 32))) | |
288 | (set (ifield f-imm64-a) (and (ifield f-imm64) (const #xffffffff))))) | |
289 | (extract (sequence () | |
290 | (set (ifield f-imm64) | |
62e65990 AM |
291 | (or (sll UDI (zext UDI (ifield f-imm64-c)) (const 32)) |
292 | (zext UDI (ifield f-imm64-a))))))) | |
ea195bb0 JM |
293 | |
294 | ;;; Operands | |
295 | ||
296 | ;; A couple of source and destination register operands are defined | |
297 | ;; for each ISA: ebpfle and ebpfbe. | |
298 | ||
299 | (dno dstle "destination register" ((ISA ebpfle)) h-gpr f-dstle) | |
300 | (dno srcle "source register" ((ISA ebpfle)) h-gpr f-srcle) | |
301 | ||
302 | (dno dstbe "destination register" ((ISA ebpfbe)) h-gpr f-dstbe) | |
303 | (dno srcbe "source register" ((ISA ebpfbe)) h-gpr f-srcbe) | |
304 | ||
305 | ;; Jump instructions have a 16-bit PC-relative address. | |
306 | ;; CALL instructions have a 32-bit PC-relative address. | |
307 | ||
308 | (dno disp16 "16-bit PC-relative address" (all-isas PCREL-ADDR) h-sint | |
309 | f-offset16) | |
310 | (dno disp32 "32-bit PC-relative address" (all-isas PCREL-ADDR) h-sint | |
311 | f-imm32) | |
312 | ||
313 | ;; Immediate operands in eBPF are signed, and we want the disassembler | |
314 | ;; to print negative values in a sane way. Therefore we use the macro | |
315 | ;; below to register a printer, which is itself defined as a C | |
316 | ;; function in bpf.opc. | |
317 | ||
318 | ;; define-normal-signed-immediate-operand | |
319 | (define-pmacro (dnsio x-name x-comment x-attrs x-type x-index) | |
320 | (define-operand | |
321 | (name x-name) | |
322 | (comment x-comment) | |
323 | (.splice attrs (.unsplice x-attrs)) | |
324 | (type x-type) | |
325 | (index x-index) | |
326 | (handlers (print "immediate")))) | |
327 | ||
328 | (dnsio imm32 "32-bit immediate" (all-isas) h-sint f-imm32) | |
329 | (dnsio offset16 "16-bit offset" (all-isas) h-sint f-offset16) | |
330 | ||
331 | ;; The 64-bit immediate cannot use the default | |
332 | ;; cgen_parse_signed_integer, because it assumes operands are at much | |
333 | ;; 32-bit wide. Use our own. | |
334 | ||
335 | (define-operand | |
336 | (name imm64) | |
337 | (comment "64-bit immediate") | |
338 | (attrs all-isas) | |
339 | (type h-sint64) | |
340 | (index f-imm64) | |
341 | (handlers (parse "imm64") (print "immediate"))) | |
342 | ||
343 | ;; The endle/endbe instructions take an operand to specify the word | |
344 | ;; width in endianness conversions. We use both a parser and printer, | |
345 | ;; which are defined as C functions in bpf.opc. | |
346 | ||
347 | (define-operand | |
348 | (name endsize) | |
349 | (comment "endianness size immediate: 16, 32 or 64") | |
350 | (attrs all-isas) | |
351 | (type h-uint) | |
352 | (index f-imm32) | |
353 | (handlers (parse "endsize") (print "endsize"))) | |
354 | ||
355 | ;;; ALU instructions | |
356 | ||
357 | ;; For each opcode in insn-op-code-alu representing and integer | |
358 | ;; arithmetic instruction (ADD, SUB, etc) we define a bunch of | |
359 | ;; instruction variants: | |
360 | ;; | |
361 | ;; ADD[32]{i,r}le for the little-endian ISA | |
362 | ;; ADD[32]{i,r}be for the big-endian ISA | |
363 | ;; | |
364 | ;; The `i' variants perform `src OP dst -> dst' operations. | |
365 | ;; The `r' variants perform `dst OP imm32 -> dst' operations. | |
366 | ;; | |
367 | ;; The variants with 32 in their name are of ALU class. Otherwise | |
368 | ;; they are ALU64 class. | |
369 | ||
370 | (define-pmacro (define-alu-insn-un x-basename x-suffix x-op-class x-op-code x-endian) | |
371 | (dni (.sym x-basename x-suffix x-endian) | |
372 | (.str x-basename x-suffix) | |
373 | ((ISA (.sym ebpf x-endian))) | |
374 | (.str x-basename x-suffix " $dst" x-endian) | |
375 | (+ (f-imm32 0) (f-offset16 0) ((.sym f-src x-endian) 0) (.sym dst x-endian) | |
bd434cc4 | 376 | x-op-class OP_SRC_K x-op-code) () ())) |
ea195bb0 JM |
377 | |
378 | (define-pmacro (define-alu-insn-bin x-basename x-suffix x-op-class x-op-code x-endian) | |
379 | (begin | |
380 | (dni (.sym x-basename x-suffix "i" x-endian) | |
381 | (.str x-basename x-suffix " immediate") | |
382 | ((ISA (.sym ebpf x-endian))) | |
383 | (.str x-basename x-suffix " $dst" x-endian ",$imm32") | |
384 | (+ imm32 (f-offset16 0) ((.sym f-src x-endian) 0) (.sym dst x-endian) | |
385 | x-op-class OP_SRC_K x-op-code) () ()) | |
386 | (dni (.sym x-basename x-suffix "r" x-endian) | |
387 | (.str x-basename x-suffix " register") | |
388 | ((ISA (.sym ebpf x-endian))) | |
389 | (.str x-basename x-suffix " $dst" x-endian ",$src" x-endian) | |
390 | (+ (f-imm32 0) (f-offset16 0) (.sym src x-endian) (.sym dst x-endian) | |
391 | x-op-class OP_SRC_X x-op-code) () ()))) | |
392 | ||
393 | (define-pmacro (daiu x-basename x-op-code x-endian) | |
394 | (begin | |
395 | (define-alu-insn-un x-basename "" OP_CLASS_ALU64 x-op-code x-endian) | |
396 | (define-alu-insn-un x-basename "32" OP_CLASS_ALU x-op-code x-endian))) | |
397 | ||
398 | (define-pmacro (daib x-basename x-op-code x-endian) | |
399 | (begin | |
400 | (define-alu-insn-bin x-basename "" OP_CLASS_ALU64 x-op-code x-endian) | |
401 | (define-alu-insn-bin x-basename "32" OP_CLASS_ALU x-op-code x-endian))) | |
402 | ||
403 | (define-pmacro (define-alu-instructions x-endian) | |
404 | (begin | |
405 | (daib add OP_CODE_ADD x-endian) | |
406 | (daib sub OP_CODE_SUB x-endian) | |
407 | (daib mul OP_CODE_MUL x-endian) | |
408 | (daib div OP_CODE_DIV x-endian) | |
409 | (daib or OP_CODE_OR x-endian) | |
410 | (daib and OP_CODE_AND x-endian) | |
411 | (daib lsh OP_CODE_LSH x-endian) | |
412 | (daib rsh OP_CODE_RSH x-endian) | |
413 | (daib mod OP_CODE_MOD x-endian) | |
414 | (daib xor OP_CODE_XOR x-endian) | |
415 | (daib mov OP_CODE_MOV x-endian) | |
416 | (daib arsh OP_CODE_ARSH x-endian) | |
417 | (daiu neg OP_CODE_NEG x-endian))) | |
418 | ||
419 | (define-alu-instructions le) | |
420 | (define-alu-instructions be) | |
421 | ||
422 | ;;; Endianness conversion instructions | |
423 | ||
424 | ;; The endianness conversion instructions come in several variants: | |
425 | ;; | |
426 | ;; END{le,be}le for the little-endian ISA | |
427 | ;; END{le,be}be for the big-endian ISA | |
428 | ;; | |
429 | ;; Please do not be confused by the repeated `be' and `le' here. Each | |
430 | ;; ISA has both endle and endbe instructions. It is the disposition | |
431 | ;; of the source and destination register fields that change between | |
432 | ;; ISAs, not the semantics of the instructions themselves (see section | |
433 | ;; "The ISAs" above in this very file.) | |
434 | ||
435 | (define-pmacro (define-endian-insn x-suffix x-op-src x-endian) | |
436 | (dni (.sym "end" x-suffix x-endian) | |
437 | (.str "end" x-suffix " register") | |
438 | ((ISA (.sym ebpf x-endian))) | |
439 | (.str "end" x-suffix " $dst" x-endian ",$endsize") | |
440 | (+ (f-offset16 0) ((.sym f-src x-endian) 0) (.sym dst x-endian) endsize | |
441 | OP_CLASS_ALU x-op-src OP_CODE_END) () ())) | |
442 | ||
443 | (define-endian-insn "le" OP_SRC_K le) | |
444 | (define-endian-insn "be" OP_SRC_X le) | |
445 | (define-endian-insn "le" OP_SRC_K be) | |
446 | (define-endian-insn "be" OP_SRC_X be) | |
447 | ||
448 | ;;; Load/Store instructions | |
449 | ||
450 | ;; The lddw instruction takes a 64-bit immediate as an operand. Since | |
451 | ;; this instruction also takes a `dst' operand, we need to define a | |
452 | ;; variant for each ISA: | |
453 | ;; | |
454 | ;; LDDWle for the little-endian ISA | |
455 | ;; LDDWbe for the big-endian ISA | |
456 | ||
457 | (define-pmacro (define-lddw x-endian) | |
458 | (dni (.sym lddw x-endian) | |
459 | (.str "lddw" x-endian) | |
460 | ((ISA (.sym ebpf x-endian))) | |
461 | (.str "lddw $dst" x-endian ",$imm64") | |
462 | (+ imm64 (f-offset16 0) ((.sym f-src x-endian) 0) | |
463 | (.sym dst x-endian) | |
464 | OP_CLASS_LD OP_SIZE_DW OP_MODE_IMM) () ())) | |
465 | ||
466 | (define-lddw le) | |
467 | (define-lddw be) | |
468 | ||
3719fd55 JM |
469 | ;; The absolute load instructions are non-generic loads designed to be |
470 | ;; used in socket filters. They come in several variants: | |
ea195bb0 | 471 | ;; |
3719fd55 JM |
472 | ;; LDABS{w,h,b,dw} |
473 | ||
474 | (define-pmacro (dlabs x-suffix x-size) | |
475 | (dni (.sym "ldabs" x-suffix) | |
476 | (.str "ldabs" x-suffix) | |
477 | (all-isas) | |
478 | (.str "ldabs" x-suffix " $imm32") | |
479 | (+ imm32 (f-offset16 0) (f-regs 0) | |
480 | OP_CLASS_LD OP_MODE_ABS (.sym OP_SIZE_ x-size)) | |
481 | () ())) | |
482 | ||
483 | (dlabs "w" W) | |
484 | (dlabs "h" H) | |
485 | (dlabs "b" B) | |
486 | (dlabs "dw" DW) | |
487 | ||
488 | ;; The indirect load instructions are non-generic loads designed to be | |
489 | ;; used in socket filters. They come in several variants: | |
490 | ;; | |
491 | ;; LDIND{w,h,b,dw}le for the little-endian ISA | |
492 | ;; LDIND[w,h,b,dw}be for the big-endian ISA | |
ea195bb0 | 493 | |
3719fd55 JM |
494 | (define-pmacro (dlind x-suffix x-size x-endian) |
495 | (dni (.sym "ldind" x-suffix x-endian) | |
496 | (.str "ldind" x-suffix) | |
ea195bb0 | 497 | ((ISA (.sym ebpf x-endian))) |
3719fd55 | 498 | (.str "ldind" x-suffix " $src" x-endian ",$imm32") |
92434a14 | 499 | (+ imm32 (f-offset16 0) ((.sym f-dst x-endian) 0) (.sym src x-endian) |
3719fd55 JM |
500 | OP_CLASS_LD OP_MODE_IND (.sym OP_SIZE_ x-size)) |
501 | () ())) | |
502 | ||
503 | (define-pmacro (define-ldind x-endian) | |
504 | (begin | |
505 | (dlind "w" W x-endian) | |
506 | (dlind "h" H x-endian) | |
507 | (dlind "b" B x-endian) | |
508 | (dlind "dw" DW x-endian))) | |
509 | ||
510 | (define-ldind le) | |
511 | (define-ldind be) | |
ea195bb0 JM |
512 | |
513 | ;; Generic load and store instructions are provided for several word | |
514 | ;; sizes. They come in several variants: | |
515 | ;; | |
516 | ;; LDX{b,h,w,dw}le, STX{b,h,w,dw}le for the little-endian ISA | |
517 | ;; | |
518 | ;; LDX{b,h,w,dw}be, STX{b,h,w,dw}be for the big-endian ISA | |
519 | ;; | |
520 | ;; Loads operate on [$SRC+-OFFSET] -> $DST | |
521 | ;; Stores operate on $SRC -> [$DST+-OFFSET] | |
522 | ||
523 | (define-pmacro (dxli x-basename x-suffix x-size x-endian) | |
524 | (dni (.sym x-basename x-suffix x-endian) | |
525 | (.str x-basename x-suffix) | |
526 | ((ISA (.sym ebpf x-endian))) | |
527 | (.str x-basename x-suffix " $dst" x-endian ",[$src" x-endian "+$offset16]") | |
528 | (+ (f-imm32 0) offset16 (.sym src x-endian) (.sym dst x-endian) | |
529 | OP_CLASS_LDX (.sym OP_SIZE_ x-size) OP_MODE_MEM) | |
530 | () ())) | |
531 | ||
532 | (define-pmacro (dxsi x-basename x-suffix x-size x-endian) | |
533 | (dni (.sym x-basename x-suffix x-endian) | |
534 | (.str x-basename x-suffix) | |
535 | ((ISA (.sym ebpf x-endian))) | |
536 | (.str x-basename x-suffix " [$dst" x-endian "+$offset16],$src" x-endian) | |
537 | (+ (f-imm32 0) offset16 (.sym src x-endian) (.sym dst x-endian) | |
538 | OP_CLASS_STX (.sym OP_SIZE_ x-size) OP_MODE_MEM) | |
539 | () ())) | |
540 | ||
541 | (define-pmacro (define-ldstx-insns x-endian) | |
542 | (begin | |
543 | (dxli "ldx" "w" W x-endian) | |
544 | (dxli "ldx" "h" H x-endian) | |
545 | (dxli "ldx" "b" B x-endian) | |
546 | (dxli "ldx" "dw" DW x-endian) | |
547 | ||
548 | (dxsi "stx" "w" W x-endian) | |
549 | (dxsi "stx" "h" H x-endian) | |
550 | (dxsi "stx" "b" B x-endian) | |
551 | (dxsi "stx" "dw" DW x-endian))) | |
552 | ||
553 | (define-ldstx-insns le) | |
554 | (define-ldstx-insns be) | |
555 | ||
556 | ;; Generic store instructions of the form IMM32 -> [$DST+OFFSET] are | |
557 | ;; provided in several variants: | |
558 | ;; | |
559 | ;; ST{b,h,w,dw}le for the little-endian ISA | |
560 | ;; ST{b,h,w,dw}be for the big-endian ISA | |
561 | ||
562 | (define-pmacro (dsti x-suffix x-size x-endian) | |
563 | (dni (.sym "st" x-suffix x-endian) | |
564 | (.str "st" x-suffix) | |
565 | ((ISA (.sym ebpf x-endian))) | |
566 | (.str "st" x-suffix " [$dst" x-endian "+$offset16],$imm32") | |
567 | (+ imm32 offset16 ((.sym f-src x-endian) 0) (.sym dst x-endian) | |
568 | OP_CLASS_ST (.sym OP_SIZE_ x-size) OP_MODE_MEM) () ())) | |
569 | ||
570 | (define-pmacro (define-st-insns x-endian) | |
571 | (begin | |
572 | (dsti "b" B x-endian) | |
573 | (dsti "h" H x-endian) | |
574 | (dsti "w" W x-endian) | |
575 | (dsti "dw" DW x-endian))) | |
576 | ||
577 | (define-st-insns le) | |
578 | (define-st-insns be) | |
579 | ||
580 | ;;; Jump instructions | |
581 | ||
582 | ;; Compare-and-jump instructions, on the other hand, make use of | |
583 | ;; registers. Therefore, we need to define several variants in both | |
584 | ;; ISAs: | |
585 | ;; | |
586 | ;; J{eq,gt,ge,lt,le,set,ne,sgt,sge,slt,sle}{i,r}le for the | |
587 | ;; little-endian ISA. | |
588 | ;; J{eq,gt,ge,lt,le,set,ne.sgt,sge,slt,sle}{i,r}be for the | |
589 | ;; big-endian ISA. | |
590 | ||
591 | (define-pmacro (dcji x-cond x-op-code x-endian) | |
592 | (begin | |
593 | (dni (.sym j x-cond i x-endian) | |
594 | (.str j x-cond "i") | |
595 | ((ISA (.sym ebpf x-endian))) | |
596 | (.str "j" x-cond " $dst" x-endian ",$imm32,$disp16") | |
597 | (+ imm32 disp16 ((.sym f-src x-endian) 0) (.sym dst x-endian) | |
598 | OP_CLASS_JMP OP_SRC_K (.sym OP_CODE_ x-op-code)) () ()) | |
599 | (dni (.sym j x-cond r x-endian) | |
600 | (.str j x-cond "r") | |
601 | ((ISA (.sym ebpf x-endian))) | |
602 | (.str "j" x-cond " $dst" x-endian ",$src" x-endian ",$disp16") | |
603 | (+ (f-imm32 0) disp16 (.sym src x-endian) (.sym dst x-endian) | |
604 | OP_CLASS_JMP OP_SRC_X (.sym OP_CODE_ x-op-code)) () ()))) | |
605 | ||
606 | (define-pmacro (define-condjump-insns x-endian) | |
607 | (begin | |
608 | (dcji "eq" JEQ x-endian) | |
609 | (dcji "gt" JGT x-endian) | |
610 | (dcji "ge" JGE x-endian) | |
611 | (dcji "lt" JLT x-endian) | |
612 | (dcji "le" JLE x-endian) | |
613 | (dcji "set" JSET x-endian) | |
614 | (dcji "ne" JNE x-endian) | |
615 | (dcji "sgt" JSGT x-endian) | |
616 | (dcji "sge" JSGE x-endian) | |
617 | (dcji "slt" JSLT x-endian) | |
618 | (dcji "sle" JSLE x-endian))) | |
619 | ||
620 | (define-condjump-insns le) | |
621 | (define-condjump-insns be) | |
622 | ||
623 | ;; The jump-always, `call' and `exit' instructions dont make use of | |
624 | ;; either source nor destination registers, so only one variant per | |
625 | ;; instruction is defined. | |
626 | ||
627 | (dni ja "ja" (all-isas) "ja $disp16" | |
628 | (+ (f-imm32 0) disp16 (f-regs 0) | |
629 | OP_CLASS_JMP OP_SRC_K OP_CODE_JA) () ()) | |
630 | ||
631 | (dni call "call" (all-isas) "call $disp32" | |
632 | (+ disp32 (f-offset16 0) (f-regs 0) | |
633 | OP_CLASS_JMP OP_SRC_K OP_CODE_CALL) () ()) | |
634 | ||
635 | (dni "exit" "exit" (all-isas) "exit" | |
636 | (+ (f-imm32 0) (f-offset16 0) (f-regs 0) | |
637 | OP_CLASS_JMP (f-op-src 0) OP_CODE_EXIT) () ()) | |
638 | ||
639 | ;;; Atomic instructions | |
640 | ||
641 | ;; The atomic exchange-and-add instructions come in two flavors: one | |
642 | ;; for swapping 64-bit quantities and another for 32-bit quantities. | |
643 | ||
644 | (define-pmacro (define-atomic-insns x-endian) | |
645 | (begin | |
646 | (dni (.str "xadddw" x-endian) | |
647 | "xadddw" | |
648 | ((ISA (.sym ebpf x-endian))) | |
649 | (.str "xadddw [$dst" x-endian "+$offset16],$src" x-endian) | |
650 | (+ (f-imm32 0) (.sym src x-endian) (.sym dst x-endian) | |
651 | offset16 OP_MODE_XADD OP_SIZE_DW OP_CLASS_STX) () ()) | |
652 | (dni (.str "xaddw" x-endian) | |
653 | "xaddw" | |
654 | ((ISA (.sym ebpf x-endian))) | |
655 | (.str "xaddw [$dst" x-endian "+$offset16],$src" x-endian) | |
656 | (+ (f-imm32 0) (.sym src x-endian) (.sym dst x-endian) | |
657 | offset16 OP_MODE_XADD OP_SIZE_W OP_CLASS_STX) () ()))) | |
658 | ||
659 | (define-atomic-insns le) | |
660 | (define-atomic-insns be) |