| 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 | ;; 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) |
| 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 | ;; |
| 54 | ;; code:8 regs:8 offset:16 imm:32 unused:32 imm:32 |
| 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) |
| 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))) |
| 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 | (insn-endian big) |
| 125 | (word-bitsize 64)) |
| 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. |
| 160 | (r0 0) (r1 1) (r2 2) (r3 3) (r4 4) (r5 5) (r6 6) |
| 161 | (r7 7) (r8 8) (r9 9) (fp 10) |
| 162 | ;; Additional names recognized when assembling. |
| 163 | (r0 0) (r6 6) (r10 10)))) |
| 164 | |
| 165 | ;; The program counter. CGEN requires it, even if it is not visible |
| 166 | ;; to eBPF programs. |
| 167 | |
| 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 | |
| 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) |
| 232 | (ALU #b100) (JMP #b101) (JMP32 #b110) (ALU64 #b111))) |
| 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 | |
| 276 | (dwf f-offset16 "eBPF offset field" (all-isas) 16 16 15 16 INT) |
| 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) |
| 298 | (or (sll UDI (zext UDI (ifield f-imm64-c)) (const 32)) |
| 299 | (zext UDI (ifield f-imm64-a))))))) |
| 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 | ;; |
| 371 | ;; The `i' variants perform `dst OP imm32 -> dst' operations. |
| 372 | ;; The `r' variants perform `dst OP src -> dst' operations. |
| 373 | ;; |
| 374 | ;; The variants with 32 in their name are of ALU class. Otherwise |
| 375 | ;; they are ALU64 class. |
| 376 | |
| 377 | (define-pmacro (define-alu-insn-un x-basename x-suffix x-op-class x-op-code |
| 378 | x-endian x-mode x-semop) |
| 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) |
| 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 | ())) |
| 387 | |
| 388 | (define-pmacro (define-alu-insn-bin x-basename x-suffix x-op-class x-op-code |
| 389 | x-endian x-mode x-semop) |
| 390 | (begin |
| 391 | ;; dst = dst OP immediate |
| 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) |
| 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 |
| 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) |
| 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 | |
| 431 | |
| 432 | ;; Unary ALU instructions (neg) |
| 433 | (define-pmacro (daiu x-basename x-op-code x-endian x-semop) |
| 434 | (begin |
| 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))) |
| 437 | |
| 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) |
| 441 | (begin |
| 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))) |
| 450 | |
| 451 | (define-pmacro (define-alu-instructions x-endian) |
| 452 | (begin |
| 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))) |
| 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 |
| 489 | OP_CLASS_ALU x-op-src OP_CODE_END) |
| 490 | (set (.sym dst x-endian) |
| 491 | (c-call DI "bpfbf_end" (.sym dst x-endian) endsize)) |
| 492 | ())) |
| 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) |
| 515 | OP_CLASS_LD OP_SIZE_DW OP_MODE_IMM) |
| 516 | (set DI (.sym dst x-endian) imm64) |
| 517 | ())) |
| 518 | |
| 519 | (define-lddw le) |
| 520 | (define-lddw be) |
| 521 | |
| 522 | ;; The absolute load instructions are non-generic loads designed to be |
| 523 | ;; used in socket filters. They come in several variants: |
| 524 | ;; |
| 525 | ;; LDABS{w,h,b,dw} |
| 526 | |
| 527 | (define-pmacro (dlabs x-suffix x-size x-smode) |
| 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)) |
| 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 |
| 541 | (const DI 0))) ;; XXX offsetof |
| 542 | ;; (struct sk_buff, data) XXX but the offset |
| 543 | ;; depends on CONFIG_* options, so this should |
| 544 | ;; be configured in the simulator and driven by |
| 545 | ;; command-line options. Handle with a c-call. |
| 546 | imm32))) |
| 547 | ;; XXX this clobbers R1-R5 |
| 548 | ())) |
| 549 | |
| 550 | (dlabs "w" W SI) |
| 551 | (dlabs "h" H HI) |
| 552 | (dlabs "b" B QI) |
| 553 | (dlabs "dw" DW DI) |
| 554 | |
| 555 | ;; The indirect load instructions are non-generic loads designed to be |
| 556 | ;; used in socket filters. They come in several variants: |
| 557 | ;; |
| 558 | ;; LDIND{w,h,b,dw}le for the little-endian ISA |
| 559 | ;; LDIND[w,h,b,dw}be for the big-endian ISA |
| 560 | |
| 561 | (define-pmacro (dlind x-suffix x-size x-endian x-smode) |
| 562 | (dni (.sym "ldind" x-suffix x-endian) |
| 563 | (.str "ldind" x-suffix) |
| 564 | ((ISA (.sym ebpf x-endian))) |
| 565 | (.str "ldind" x-suffix " $src" x-endian ",$imm32") |
| 566 | (+ imm32 (f-offset16 0) ((.sym f-dst x-endian) 0) (.sym src x-endian) |
| 567 | OP_CLASS_LD OP_MODE_IND (.sym OP_SIZE_ x-size)) |
| 568 | (set x-smode |
| 569 | (reg x-smode h-gpr 0) |
| 570 | (mem x-smode |
| 571 | (add DI |
| 572 | (mem DI |
| 573 | (add DI |
| 574 | (reg DI h-gpr 6) ;; Pointer to struct sk_buff |
| 575 | (const DI 0))) ;; XXX offsetof |
| 576 | ;; (struct sk_buff, data) XXX but the offset |
| 577 | ;; depends on CONFIG_* options, so this should |
| 578 | ;; be configured in the simulator and driven by |
| 579 | ;; command-line options. Handle with a c-call. |
| 580 | (add DI |
| 581 | (.sym src x-endian) |
| 582 | imm32)))) |
| 583 | ;; XXX this clobbers R1-R5 |
| 584 | ())) |
| 585 | |
| 586 | (define-pmacro (define-ldind x-endian) |
| 587 | (begin |
| 588 | (dlind "w" W x-endian SI) |
| 589 | (dlind "h" H x-endian HI) |
| 590 | (dlind "b" B x-endian QI) |
| 591 | (dlind "dw" DW x-endian DI))) |
| 592 | |
| 593 | (define-ldind le) |
| 594 | (define-ldind be) |
| 595 | |
| 596 | ;; Generic load and store instructions are provided for several word |
| 597 | ;; sizes. They come in several variants: |
| 598 | ;; |
| 599 | ;; LDX{b,h,w,dw}le, STX{b,h,w,dw}le for the little-endian ISA |
| 600 | ;; |
| 601 | ;; LDX{b,h,w,dw}be, STX{b,h,w,dw}be for the big-endian ISA |
| 602 | ;; |
| 603 | ;; Loads operate on [$SRC+-OFFSET] -> $DST |
| 604 | ;; Stores operate on $SRC -> [$DST+-OFFSET] |
| 605 | |
| 606 | (define-pmacro (dxli x-basename x-suffix x-size x-endian x-mode) |
| 607 | (dni (.sym x-basename x-suffix x-endian) |
| 608 | (.str x-basename x-suffix) |
| 609 | ((ISA (.sym ebpf x-endian))) |
| 610 | (.str x-basename x-suffix " $dst" x-endian ",[$src" x-endian "+$offset16]") |
| 611 | (+ (f-imm32 0) offset16 (.sym src x-endian) (.sym dst x-endian) |
| 612 | OP_CLASS_LDX (.sym OP_SIZE_ x-size) OP_MODE_MEM) |
| 613 | (set x-mode |
| 614 | (.sym dst x-endian) |
| 615 | (mem x-mode (add DI (.sym src x-endian) (ext DI (trunc HI offset16))))) |
| 616 | ())) |
| 617 | |
| 618 | (define-pmacro (dxsi x-basename x-suffix x-size x-endian x-mode) |
| 619 | (dni (.sym x-basename x-suffix x-endian) |
| 620 | (.str x-basename x-suffix) |
| 621 | ((ISA (.sym ebpf x-endian))) |
| 622 | (.str x-basename x-suffix " [$dst" x-endian "+$offset16],$src" x-endian) |
| 623 | (+ (f-imm32 0) offset16 (.sym src x-endian) (.sym dst x-endian) |
| 624 | OP_CLASS_STX (.sym OP_SIZE_ x-size) OP_MODE_MEM) |
| 625 | (set x-mode |
| 626 | (mem x-mode (add DI (.sym dst x-endian) (ext DI (trunc HI offset16)))) |
| 627 | (.sym src x-endian)) ;; XXX address is section-relative |
| 628 | ())) |
| 629 | |
| 630 | (define-pmacro (define-ldstx-insns x-endian) |
| 631 | (begin |
| 632 | (dxli "ldx" "w" W x-endian SI) |
| 633 | (dxli "ldx" "h" H x-endian HI) |
| 634 | (dxli "ldx" "b" B x-endian QI) |
| 635 | (dxli "ldx" "dw" DW x-endian DI) |
| 636 | |
| 637 | (dxsi "stx" "w" W x-endian SI) |
| 638 | (dxsi "stx" "h" H x-endian HI) |
| 639 | (dxsi "stx" "b" B x-endian QI) |
| 640 | (dxsi "stx" "dw" DW x-endian DI))) |
| 641 | |
| 642 | (define-ldstx-insns le) |
| 643 | (define-ldstx-insns be) |
| 644 | |
| 645 | ;; Generic store instructions of the form IMM32 -> [$DST+OFFSET] are |
| 646 | ;; provided in several variants: |
| 647 | ;; |
| 648 | ;; ST{b,h,w,dw}le for the little-endian ISA |
| 649 | ;; ST{b,h,w,dw}be for the big-endian ISA |
| 650 | |
| 651 | (define-pmacro (dsti x-suffix x-size x-endian x-mode) |
| 652 | (dni (.sym "st" x-suffix x-endian) |
| 653 | (.str "st" x-suffix) |
| 654 | ((ISA (.sym ebpf x-endian))) |
| 655 | (.str "st" x-suffix " [$dst" x-endian "+$offset16],$imm32") |
| 656 | (+ imm32 offset16 ((.sym f-src x-endian) 0) (.sym dst x-endian) |
| 657 | OP_CLASS_ST (.sym OP_SIZE_ x-size) OP_MODE_MEM) |
| 658 | (set x-mode |
| 659 | (mem x-mode (add DI (.sym dst x-endian) offset16)) |
| 660 | imm32) ;; XXX address is section-relative |
| 661 | ())) |
| 662 | |
| 663 | (define-pmacro (define-st-insns x-endian) |
| 664 | (begin |
| 665 | (dsti "b" B x-endian QI) |
| 666 | (dsti "h" H x-endian HI) |
| 667 | (dsti "w" W x-endian SI) |
| 668 | (dsti "dw" DW x-endian DI))) |
| 669 | |
| 670 | (define-st-insns le) |
| 671 | (define-st-insns be) |
| 672 | |
| 673 | ;;; Jump instructions |
| 674 | |
| 675 | ;; Compare-and-jump instructions, on the other hand, make use of |
| 676 | ;; registers. Therefore, we need to define several variants in both |
| 677 | ;; ISAs: |
| 678 | ;; |
| 679 | ;; J{eq,gt,ge,lt,le,set,ne,sgt,sge,slt,sle}[32]{i,r}le for the |
| 680 | ;; little-endian ISA. |
| 681 | ;; J{eq,gt,ge,lt,le,set,ne.sgt,sge,slt,sle}[32]{i,r}be for the |
| 682 | ;; big-endian ISA. |
| 683 | |
| 684 | (define-pmacro (define-cond-jump-insn x-cond x-suffix x-op-class x-op-code x-endian x-mode x-semop) |
| 685 | (begin |
| 686 | (dni (.sym j x-cond x-suffix i x-endian) |
| 687 | (.str j x-cond x-suffix " i") |
| 688 | ((ISA (.sym ebpf x-endian))) |
| 689 | (.str "j" x-cond x-suffix " $dst" x-endian ",$imm32,$disp16") |
| 690 | (+ imm32 disp16 ((.sym f-src x-endian) 0) (.sym dst x-endian) |
| 691 | x-op-class OP_SRC_K (.sym OP_CODE_ x-op-code)) |
| 692 | (if VOID (x-semop x-mode (.sym dst x-endian) imm32) |
| 693 | (set DI |
| 694 | (reg DI h-pc) (add DI (reg DI h-pc) |
| 695 | (mul DI (add HI disp16 1) 8)))) |
| 696 | ()) |
| 697 | (dni (.sym j x-cond x-suffix r x-endian) |
| 698 | (.str j x-cond x-suffix " r") |
| 699 | ((ISA (.sym ebpf x-endian))) |
| 700 | (.str "j" x-cond x-suffix " $dst" x-endian ",$src" x-endian ",$disp16") |
| 701 | (+ (f-imm32 0) disp16 (.sym src x-endian) (.sym dst x-endian) |
| 702 | x-op-class OP_SRC_X (.sym OP_CODE_ x-op-code)) |
| 703 | (if VOID (x-semop x-mode (.sym dst x-endian) (.sym src x-endian)) |
| 704 | (set DI |
| 705 | (reg DI h-pc) (add DI (reg DI h-pc) |
| 706 | (mul DI (add HI disp16 1) 8)))) |
| 707 | ()))) |
| 708 | |
| 709 | (define-pmacro (dcji x-cond x-op-code x-endian x-semop) |
| 710 | (begin |
| 711 | (define-cond-jump-insn x-cond "" OP_CLASS_JMP x-op-code x-endian DI x-semop) |
| 712 | (define-cond-jump-insn x-cond "32" OP_CLASS_JMP32 x-op-code x-endian SI x-semop ))) |
| 713 | |
| 714 | (define-pmacro (define-condjump-insns x-endian) |
| 715 | (begin |
| 716 | (dcji "eq" JEQ x-endian eq) |
| 717 | (dcji "gt" JGT x-endian gtu) |
| 718 | (dcji "ge" JGE x-endian geu) |
| 719 | (dcji "lt" JLT x-endian ltu) |
| 720 | (dcji "le" JLE x-endian leu) |
| 721 | (dcji "set" JSET x-endian and) |
| 722 | (dcji "ne" JNE x-endian ne) |
| 723 | (dcji "sgt" JSGT x-endian gt) |
| 724 | (dcji "sge" JSGE x-endian ge) |
| 725 | (dcji "slt" JSLT x-endian lt) |
| 726 | (dcji "sle" JSLE x-endian le))) |
| 727 | |
| 728 | (define-condjump-insns le) |
| 729 | (define-condjump-insns be) |
| 730 | |
| 731 | ;; The `call' instruction doesn't make use of registers, but the |
| 732 | ;; semantic routine should have access to the src register in order to |
| 733 | ;; properly interpret the meaning of disp32. Therefore we need one |
| 734 | ;; version per ISA. |
| 735 | |
| 736 | (define-pmacro (define-call-insn x-endian) |
| 737 | (dni (.sym call x-endian) |
| 738 | "call" |
| 739 | ((ISA (.sym ebpf x-endian))) |
| 740 | "call $disp32" |
| 741 | (+ disp32 (f-offset16 0) (f-regs 0) |
| 742 | OP_CLASS_JMP OP_SRC_K OP_CODE_CALL) |
| 743 | (c-call VOID |
| 744 | "bpfbf_call" disp32 (ifield (.sym f-src x-endian))) |
| 745 | ())) |
| 746 | |
| 747 | (define-call-insn le) |
| 748 | (define-call-insn be) |
| 749 | |
| 750 | ;; The jump-always and `exit' instructions dont make use of either |
| 751 | ;; source nor destination registers, so only one variant per |
| 752 | ;; instruction is defined. |
| 753 | |
| 754 | (dni ja "ja" (all-isas) "ja $disp16" |
| 755 | (+ (f-imm32 0) disp16 (f-regs 0) |
| 756 | OP_CLASS_JMP OP_SRC_K OP_CODE_JA) |
| 757 | (set DI (reg DI h-pc) (add DI (reg DI h-pc) |
| 758 | (mul DI (add HI disp16 1) 8))) |
| 759 | ()) |
| 760 | |
| 761 | (dni "exit" "exit" (all-isas) "exit" |
| 762 | (+ (f-imm32 0) (f-offset16 0) (f-regs 0) |
| 763 | OP_CLASS_JMP (f-op-src 0) OP_CODE_EXIT) |
| 764 | (c-call VOID "bpfbf_exit") |
| 765 | ()) |
| 766 | |
| 767 | ;;; Atomic instructions |
| 768 | |
| 769 | ;; The atomic exchange-and-add instructions come in two flavors: one |
| 770 | ;; for swapping 64-bit quantities and another for 32-bit quantities. |
| 771 | |
| 772 | (define-pmacro (sem-exchange-and-add x-endian x-mode) |
| 773 | (sequence VOID ((x-mode tmp)) |
| 774 | ;; XXX acquire lock in simulator... as a hardware element? |
| 775 | (set x-mode tmp (mem x-mode (add DI (.sym dst x-endian) offset16))) |
| 776 | (set x-mode |
| 777 | (mem x-mode (add DI (.sym dst x-endian) offset16)) |
| 778 | (add x-mode tmp (.sym src x-endian))))) |
| 779 | |
| 780 | (define-pmacro (define-atomic-insns x-endian) |
| 781 | (begin |
| 782 | (dni (.str "xadddw" x-endian) |
| 783 | "xadddw" |
| 784 | ((ISA (.sym ebpf x-endian))) |
| 785 | (.str "xadddw [$dst" x-endian "+$offset16],$src" x-endian) |
| 786 | (+ (f-imm32 0) (.sym src x-endian) (.sym dst x-endian) |
| 787 | offset16 OP_MODE_XADD OP_SIZE_DW OP_CLASS_STX) |
| 788 | (sem-exchange-and-add x-endian DI) |
| 789 | ()) |
| 790 | (dni (.str "xaddw" x-endian) |
| 791 | "xaddw" |
| 792 | ((ISA (.sym ebpf x-endian))) |
| 793 | (.str "xaddw [$dst" x-endian "+$offset16],$src" x-endian) |
| 794 | (+ (f-imm32 0) (.sym src x-endian) (.sym dst x-endian) |
| 795 | offset16 OP_MODE_XADD OP_SIZE_W OP_CLASS_STX) |
| 796 | (sem-exchange-and-add x-endian SI) |
| 797 | ()))) |
| 798 | |
| 799 | (define-atomic-insns le) |
| 800 | (define-atomic-insns be) |
| 801 | |
| 802 | ;;; Breakpoint instruction |
| 803 | |
| 804 | ;; The brkpt instruction is used by the BPF simulator and it doesn't |
| 805 | ;; really belong to the eBPF instruction set. |
| 806 | |
| 807 | (dni "brkpt" "brkpt" (all-isas) "brkpt" |
| 808 | (+ (f-imm32 0) (f-offset16 0) (f-regs 0) |
| 809 | OP_CLASS_ALU OP_SRC_X OP_CODE_NEG) |
| 810 | (c-call VOID "bpfbf_breakpoint") |
| 811 | ()) |