├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.zig ├── build.zig.zon ├── docs └── rfc9669.txt └── src ├── Instruction.zig ├── VM.zig ├── insn.zig ├── insn └── examples.bpf.zig ├── insn_test.zig ├── kern.zig ├── main.zig ├── root.zig └── user.zig /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | build_and_test: 11 | name: Build and Test 12 | continue-on-error: true 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v4 17 | 18 | - name: Setup Zig 19 | uses: goto-bus-stop/setup-zig@v2 20 | with: 21 | version: 0.14.0 22 | 23 | - name: Build 24 | run: zig build 25 | 26 | - name: Unit Test 27 | run: zig build test 28 | 29 | test_vm: 30 | name: Test VM 31 | continue-on-error: true 32 | runs-on: ${{ matrix.os }} 33 | strategy: 34 | matrix: 35 | os: [ 36 | ubuntu-latest, 37 | windows-latest, 38 | macos-latest, 39 | ] 40 | steps: 41 | - name: Checkout 42 | uses: actions/checkout@v4 43 | 44 | - name: Setup Zig 45 | uses: goto-bus-stop/setup-zig@v2 46 | with: 47 | version: 0.14.0 48 | 49 | - name: Unit Test 50 | run: zig build test-vm 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | zig-out 2 | .zig-cache 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Matthew Knight 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WIP eBPF Package for Zig 2 | -------------------------------------------------------------------------------- /build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | pub fn build(b: *std.Build) void { 4 | const target = b.standardTargetOptions(.{}); 5 | const optimize = b.standardOptimizeOption(.{}); 6 | 7 | _ = b.addModule("user", .{ 8 | .root_source_file = b.path("src/user.zig"), 9 | }); 10 | 11 | _ = b.addModule("kern", .{ 12 | .root_source_file = b.path("src/kern.zig"), 13 | }); 14 | 15 | const emulator_mod = b.addModule("VM", .{ 16 | .root_source_file = b.path("src/VM.zig"), 17 | .target = target, 18 | .optimize = optimize, 19 | }); 20 | 21 | const vm_unit_tests = b.addTest(.{ 22 | .root_module = emulator_mod, 23 | }); 24 | 25 | add_bpf_files(b, vm_unit_tests, .{ 26 | .name = "examples", 27 | .path = b.path("src/insn/examples.bpf.zig"), 28 | .sections = &.{ 29 | "load", 30 | "return_one", 31 | }, 32 | }); 33 | 34 | const run_vm_unit_tests = b.addRunArtifact(vm_unit_tests); 35 | const test_vm_step = b.step("test-vm", "Run unit tests"); 36 | test_vm_step.dependOn(&run_vm_unit_tests.step); 37 | 38 | const test_step = b.step("test", "Run all tests"); 39 | test_step.dependOn(test_vm_step); 40 | } 41 | 42 | const Add_BPF_FileOptions = struct { 43 | name: []const u8, 44 | path: std.Build.LazyPath, 45 | sections: []const []const u8, 46 | }; 47 | 48 | fn add_bpf_files( 49 | b: *std.Build, 50 | compile: *std.Build.Step.Compile, 51 | opts: Add_BPF_FileOptions, 52 | ) void { 53 | add_bpf_file(b, compile, .little, opts); 54 | add_bpf_file(b, compile, .big, opts); 55 | } 56 | 57 | fn add_bpf_file( 58 | b: *std.Build, 59 | compile: *std.Build.Step.Compile, 60 | endian: std.builtin.Endian, 61 | opts: Add_BPF_FileOptions, 62 | ) void { 63 | const module_name = b.fmt("{s}-{s}", .{ opts.name, switch (endian) { 64 | .little => "el", 65 | .big => "eb", 66 | } }); 67 | 68 | const obj = b.addObject(.{ 69 | .name = module_name, 70 | .target = b.resolveTargetQuery(.{ 71 | .cpu_arch = switch (endian) { 72 | .little => .bpfel, 73 | .big => .bpfeb, 74 | }, 75 | .os_tag = .freestanding, 76 | }), 77 | .optimize = .ReleaseSmall, 78 | .root_source_file = opts.path, 79 | }); 80 | obj.link_function_sections = true; 81 | 82 | const install = b.addInstallFile(obj.getEmittedBin(), b.fmt("{s}.elf", .{module_name})); 83 | b.getInstallStep().dependOn(&install.step); 84 | 85 | const options = b.addOptions(); 86 | for (opts.sections) |section| { 87 | const objcopy = b.addObjCopy( 88 | obj.getEmittedBin(), 89 | .{ 90 | .format = .bin, 91 | .only_section = switch (@import("builtin").os.tag) { 92 | .macos => b.fmt(".text.{s}", .{section}), 93 | else => b.fmt(".text.{s}", .{section}), 94 | }, 95 | }, 96 | ); 97 | options.addOptionPath(section, objcopy.getOutput()); 98 | } 99 | 100 | compile.root_module.addOptions(module_name, options); 101 | } 102 | -------------------------------------------------------------------------------- /build.zig.zon: -------------------------------------------------------------------------------- 1 | .{ 2 | .name = .bpf, 3 | .version = "0.0.0", 4 | .fingerprint = 0x3ffc7bc7c8582a78, 5 | .paths = .{ 6 | "LICENSE", 7 | "README.md", 8 | "build.zig", 9 | "build.zig.zon", 10 | "src", 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /docs/rfc9669.txt: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Internet Engineering Task Force (IETF) D. Thaler, Ed. 6 | Request for Comments: 9669 October 2024 7 | Category: Standards Track 8 | ISSN: 2070-1721 9 | 10 | 11 | BPF Instruction Set Architecture (ISA) 12 | 13 | Abstract 14 | 15 | eBPF (which is no longer an acronym for anything), also commonly 16 | referred to as BPF, is a technology with origins in the Linux kernel 17 | that can run untrusted programs in a privileged context such as an 18 | operating system kernel. This document specifies the BPF instruction 19 | set architecture (ISA). 20 | 21 | Status of This Memo 22 | 23 | This is an Internet Standards Track document. 24 | 25 | This document is a product of the Internet Engineering Task Force 26 | (IETF). It represents the consensus of the IETF community. It has 27 | received public review and has been approved for publication by the 28 | Internet Engineering Steering Group (IESG). Further information on 29 | Internet Standards is available in Section 2 of RFC 7841. 30 | 31 | Information about the current status of this document, any errata, 32 | and how to provide feedback on it may be obtained at 33 | https://www.rfc-editor.org/info/rfc9669. 34 | 35 | Copyright Notice 36 | 37 | Copyright (c) 2024 IETF Trust and the persons identified as the 38 | document authors. All rights reserved. 39 | 40 | This document is subject to BCP 78 and the IETF Trust's Legal 41 | Provisions Relating to IETF Documents 42 | (https://trustee.ietf.org/license-info) in effect on the date of 43 | publication of this document. Please review these documents 44 | carefully, as they describe your rights and restrictions with respect 45 | to this document. Code Components extracted from this document must 46 | include Revised BSD License text as described in Section 4.e of the 47 | Trust Legal Provisions and are provided without warranty as described 48 | in the Revised BSD License. 49 | 50 | Table of Contents 51 | 52 | 1. Introduction 53 | 2. Documentation Conventions 54 | 2.1. Types 55 | 2.2. Functions 56 | 2.3. Definitions 57 | 2.4. Conformance Groups 58 | 3. Instruction Encoding 59 | 3.1. Basic Instruction Encoding 60 | 3.2. Wide Instruction Encoding 61 | 3.3. Instruction Classes 62 | 4. Arithmetic and Jump Instructions 63 | 4.1. Arithmetic Instructions 64 | 4.2. Byte Swap Instructions 65 | 4.3. Jump Instructions 66 | 4.3.1. Helper Functions 67 | 4.3.2. Program-Local Functions 68 | 5. Load and Store Instructions 69 | 5.1. Regular Load and Store Operations 70 | 5.2. Sign-Extension Load Operations 71 | 5.3. Atomic Operations 72 | 5.4. 64-bit Immediate Instructions 73 | 5.4.1. Maps 74 | 5.4.2. Platform Variables 75 | 5.5. Legacy BPF Packet Access Instructions 76 | 6. Security Considerations 77 | 7. IANA Considerations 78 | 7.1. BPF Instruction Conformance Groups Registry 79 | 7.1.1. BPF Instruction Conformance Groups Registration 80 | Template 81 | 7.2. BPF Instruction Set Registry 82 | 7.2.1. BPF Instruction Registration Template 83 | 7.3. Adding Instructions 84 | 7.4. Deprecating Instructions 85 | 7.5. Change Control 86 | 7.6. Expert Review Instructions 87 | 8. References 88 | 8.1. Normative References 89 | 8.2. Informative References 90 | Appendix A. Initial BPF Instruction Set Values 91 | Acknowledgements 92 | Author's Address 93 | 94 | 1. Introduction 95 | 96 | eBPF, also commonly referred to as BPF, is a technology with origins 97 | in the Linux kernel that can run untrusted programs in a privileged 98 | context such as an operating system kernel. This document specifies 99 | the BPF instruction set architecture (ISA). 100 | 101 | As a historical note, BPF originally stood for Berkeley Packet 102 | Filter, but now that it can do so much more than packet filtering, 103 | the acronym no longer makes sense. BPF is now considered a 104 | standalone term that does not stand for anything. The original BPF 105 | is sometimes referred to as cBPF (classic BPF) to distinguish it from 106 | the now widely deployed eBPF (extended BPF). 107 | 108 | 2. Documentation Conventions 109 | 110 | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 111 | "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and 112 | "OPTIONAL" in this document are to be interpreted as described in 113 | BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all 114 | capitals, as shown here. 115 | 116 | For brevity and consistency, this document refers to families of 117 | types using a shorthand syntax and refers to several expository, 118 | mnemonic functions when describing the semantics of instructions. 119 | The range of valid values for those types and the semantics of those 120 | functions are defined in the following subsections. 121 | 122 | 2.1. Types 123 | 124 | This document refers to integer types with the notation SN to specify 125 | a type's signedness (S) and bit width (N), respectively. 126 | 127 | +===+==========+ 128 | | S | Meaning | 129 | +===+==========+ 130 | | u | unsigned | 131 | +---+----------+ 132 | | s | signed | 133 | +---+----------+ 134 | 135 | Table 1: Meaning of 136 | Signedness Notation 137 | 138 | +=====+===========+ 139 | | N | Bit Width | 140 | +=====+===========+ 141 | | 8 | 8 bits | 142 | +-----+-----------+ 143 | | 16 | 16 bits | 144 | +-----+-----------+ 145 | | 32 | 32 bits | 146 | +-----+-----------+ 147 | | 64 | 64 bits | 148 | +-----+-----------+ 149 | | 128 | 128 bits | 150 | +-----+-----------+ 151 | 152 | Table 2: Meaning of 153 | Bit-Width Notation 154 | 155 | For example, _u32_ is a type whose valid values are all the 32-bit 156 | unsigned numbers and _s16_ is a type whose valid values are all the 157 | 16-bit signed numbers. 158 | 159 | 2.2. Functions 160 | 161 | The following byte swap functions are direction agnostic. That is, 162 | the same function is used for conversion in either direction 163 | discussed below. 164 | 165 | * be16: Takes an unsigned 16-bit number and converts it between host 166 | byte order and big-endian byte order [IEN137]. 167 | 168 | * be32: Takes an unsigned 32-bit number and converts it between host 169 | byte order and big-endian byte order. 170 | 171 | * be64: Takes an unsigned 64-bit number and converts it between host 172 | byte order and big-endian byte order. 173 | 174 | * bswap16: Takes an unsigned 16-bit number in either big- or little- 175 | endian format and returns the equivalent number with the same bit 176 | width but opposite endianness. 177 | 178 | * bswap32: Takes an unsigned 32-bit number in either big- or little- 179 | endian format and returns the equivalent number with the same bit 180 | width but opposite endianness. 181 | 182 | * bswap64: Takes an unsigned 64-bit number in either big- or little- 183 | endian format and returns the equivalent number with the same bit 184 | width but opposite endianness. 185 | 186 | * le16: Takes an unsigned 16-bit number and converts it between host 187 | byte order and little-endian byte order. 188 | 189 | * le32: Takes an unsigned 32-bit number and converts it between host 190 | byte order and little-endian byte order. 191 | 192 | * le64: Takes an unsigned 64-bit number and converts it between host 193 | byte order and little-endian byte order. 194 | 195 | 2.3. Definitions 196 | 197 | Sign Extend: To sign extend an X-bit number, A, to a Y-bit number, 198 | B, means to 199 | 200 | 1. Copy all X bits from A to the lower X bits of B. 201 | 202 | 2. Set the value of the remaining Y - X bits of B to the value of 203 | the most significant bit of A. 204 | 205 | | *Example* 206 | | 207 | | Sign extend an 8-bit number A to a 16-bit number B on a big- 208 | | endian platform: 209 | | 210 | | A: 10000110 211 | | B: 11111111 10000110 212 | 213 | 2.4. Conformance Groups 214 | 215 | An implementation does not need to support all instructions specified 216 | in this document (e.g., deprecated instructions). Instead, a number 217 | of conformance groups are specified. An implementation MUST support 218 | the base32 conformance group and MAY support additional conformance 219 | groups, where supporting a conformance group means it MUST support 220 | all instructions in that conformance group. 221 | 222 | The use of named conformance groups enables interoperability between 223 | a runtime that executes instructions, and tools such as compilers 224 | that generate instructions for the runtime. Thus, capability 225 | discovery in terms of conformance groups might be done manually by 226 | users or automatically by tools. 227 | 228 | Each conformance group has a short ASCII label (e.g., "base32") that 229 | corresponds to a set of instructions that are mandatory. That is, 230 | each instruction has one or more conformance groups of which it is a 231 | member. 232 | 233 | This document defines the following conformance groups: 234 | 235 | base32: includes all instructions defined in this specification 236 | unless otherwise noted. 237 | 238 | base64: includes base32, plus instructions explicitly noted as being 239 | in the base64 conformance group. 240 | 241 | atomic32: includes 32-bit atomic operation instructions (see 242 | Section 5.3). 243 | 244 | atomic64: includes atomic32, plus 64-bit atomic operation 245 | instructions. 246 | 247 | divmul32: includes 32-bit division, multiplication, and modulo 248 | instructions. 249 | 250 | divmul64: includes divmul32, plus 64-bit division, multiplication, 251 | and modulo instructions. 252 | 253 | packet: deprecated packet access instructions. 254 | 255 | 3. Instruction Encoding 256 | 257 | BPF has two instruction encodings: 258 | 259 | * the basic instruction encoding, which uses 64 bits to encode an 260 | instruction 261 | 262 | * the wide instruction encoding, which appends a second 64 bits 263 | after the basic instruction for a total of 128 bits. 264 | 265 | 3.1. Basic Instruction Encoding 266 | 267 | A basic instruction is encoded as follows: 268 | 269 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 270 | | opcode | regs | offset | 271 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 272 | | imm | 273 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 274 | 275 | *opcode:* operation to perform, encoded as follows: 276 | 277 | +-+-+-+-+-+-+-+-+ 278 | |specific |class| 279 | +-+-+-+-+-+-+-+-+ 280 | 281 | *specific:* The format of these bits varies by instruction class 282 | 283 | *class:* the instruction class (see Section 3.3) 284 | 285 | *regs:* the source and destination register numbers, encoded as 286 | follows on a little-endian host: 287 | 288 | +-+-+-+-+-+-+-+-+ 289 | |src_reg|dst_reg| 290 | +-+-+-+-+-+-+-+-+ 291 | 292 | and as follows on a big-endian host: 293 | 294 | +-+-+-+-+-+-+-+-+ 295 | |dst_reg|src_reg| 296 | +-+-+-+-+-+-+-+-+ 297 | 298 | *src_reg:* the source register number (0-10), except where 299 | otherwise specified (64-bit immediate instructions (see 300 | Section 5.4) reuse this field for other purposes) 301 | 302 | *dst_reg:* the destination register number (0-10), unless 303 | otherwise specified (future instructions might reuse this field 304 | for other purposes) 305 | 306 | *offset:* signed integer offset used with pointer arithmetic, except 307 | where otherwise specified (some arithmetic instructions reuse this 308 | field for other purposes) 309 | 310 | *imm:* signed integer immediate value 311 | 312 | Note that the contents of multi-byte fields ('offset' and 'imm') are 313 | stored using big-endian byte ordering on big-endian hosts and little- 314 | endian byte ordering on little-endian hosts. 315 | 316 | For example: 317 | 318 | opcode offset imm assembly 319 | src_reg dst_reg 320 | 07 0 1 00 00 44 33 22 11 r1 += 0x11223344 // little 321 | dst_reg src_reg 322 | 07 1 0 00 00 11 22 33 44 r1 += 0x11223344 // big 323 | 324 | Note that most instructions do not use all of the fields. Unused 325 | fields SHALL be cleared to zero. 326 | 327 | 3.2. Wide Instruction Encoding 328 | 329 | Some instructions are defined to use the wide instruction encoding, 330 | which uses two 32-bit immediate values. The 64 bits following the 331 | basic instruction format contain a pseudo instruction with 'opcode', 332 | 'dst_reg', 'src_reg', and 'offset' all set to zero. 333 | 334 | This is depicted in the following figure: 335 | 336 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 337 | | opcode | regs | offset | 338 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 339 | | imm | 340 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 341 | | reserved | 342 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 343 | | next_imm | 344 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 345 | 346 | *opcode:* operation to perform, encoded as explained above 347 | 348 | *regs:* the source and destination register numbers (unless 349 | otherwise specified), encoded as explained above 350 | 351 | *offset:* signed integer offset used with pointer arithmetic, unless 352 | otherwise specified 353 | 354 | *imm:* signed integer immediate value 355 | 356 | *reserved:* unused, set to zero 357 | 358 | *next_imm:* second signed integer immediate value 359 | 360 | 3.3. Instruction Classes 361 | 362 | The three least significant bits of the 'opcode' field store the 363 | instruction class: 364 | 365 | +=======+=======+=================================+===========+ 366 | | class | Value | Description | Reference | 367 | +=======+=======+=================================+===========+ 368 | | LD | 0x0 | non-standard load operations | Section 5 | 369 | +-------+-------+---------------------------------+-----------+ 370 | | LDX | 0x1 | load into register operations | Section 5 | 371 | +-------+-------+---------------------------------+-----------+ 372 | | ST | 0x2 | store from immediate operations | Section 5 | 373 | +-------+-------+---------------------------------+-----------+ 374 | | STX | 0x3 | store from register operations | Section 5 | 375 | +-------+-------+---------------------------------+-----------+ 376 | | ALU | 0x4 | 32-bit arithmetic operations | Section 4 | 377 | +-------+-------+---------------------------------+-----------+ 378 | | JMP | 0x5 | 64-bit jump operations | Section 4 | 379 | +-------+-------+---------------------------------+-----------+ 380 | | JMP32 | 0x6 | 32-bit jump operations | Section 4 | 381 | +-------+-------+---------------------------------+-----------+ 382 | | ALU64 | 0x7 | 64-bit arithmetic operations | Section 4 | 383 | +-------+-------+---------------------------------+-----------+ 384 | 385 | Table 3: Instruction Class 386 | 387 | 4. Arithmetic and Jump Instructions 388 | 389 | For arithmetic and jump instructions (ALU, ALU64, JMP, and JMP32), 390 | the 8-bit 'opcode' field is divided into three parts: 391 | 392 | +-+-+-+-+-+-+-+-+ 393 | | code |s|class| 394 | +-+-+-+-+-+-+-+-+ 395 | 396 | *code:* the operation code, whose meaning varies by instruction 397 | class 398 | 399 | *s (source):* the source operand location, which unless otherwise 400 | specified is one of: 401 | 402 | +========+=======+==========================================+ 403 | | source | Value | Description | 404 | +========+=======+==========================================+ 405 | | K | 0 | use 32-bit 'imm' value as source operand | 406 | +--------+-------+------------------------------------------+ 407 | | X | 1 | use 'src_reg' register value as source | 408 | | | | operand | 409 | +--------+-------+------------------------------------------+ 410 | 411 | Table 4: Source Operand Location 412 | 413 | *class:* the instruction class (see Section 3.3) 414 | 415 | 4.1. Arithmetic Instructions 416 | 417 | ALU uses 32-bit wide operands while ALU64 uses 64-bit wide operands 418 | for otherwise identical operations. ALU64 instructions belong to the 419 | base64 conformance group unless noted otherwise. The 'code' field 420 | encodes the operation as below, where 'src' refers to the source 421 | operand and 'dst' refers to the value of the destination register. 422 | 423 | +=======+======+=========+=======================================+ 424 | | Name | code | offset | Description | 425 | +=======+======+=========+=======================================+ 426 | | ADD | 0x0 | 0 | dst += src | 427 | +-------+------+---------+---------------------------------------+ 428 | | SUB | 0x1 | 0 | dst -= src | 429 | +-------+------+---------+---------------------------------------+ 430 | | MUL | 0x2 | 0 | dst *= src | 431 | +-------+------+---------+---------------------------------------+ 432 | | DIV | 0x3 | 0 | dst = (src != 0) ? (dst / src) : 0 | 433 | +-------+------+---------+---------------------------------------+ 434 | | SDIV | 0x3 | 1 | dst = (src != 0) ? (dst s/ src) : 0 | 435 | +-------+------+---------+---------------------------------------+ 436 | | OR | 0x4 | 0 | dst |= src | 437 | +-------+------+---------+---------------------------------------+ 438 | | AND | 0x5 | 0 | dst &= src | 439 | +-------+------+---------+---------------------------------------+ 440 | | LSH | 0x6 | 0 | dst <<= (src & mask) | 441 | +-------+------+---------+---------------------------------------+ 442 | | RSH | 0x7 | 0 | dst >>= (src & mask) | 443 | +-------+------+---------+---------------------------------------+ 444 | | NEG | 0x8 | 0 | dst = -dst | 445 | +-------+------+---------+---------------------------------------+ 446 | | MOD | 0x9 | 0 | dst = (src != 0) ? (dst % src) : dst | 447 | +-------+------+---------+---------------------------------------+ 448 | | SMOD | 0x9 | 1 | dst = (src != 0) ? (dst s% src) : dst | 449 | +-------+------+---------+---------------------------------------+ 450 | | XOR | 0xa | 0 | dst ^= src | 451 | +-------+------+---------+---------------------------------------+ 452 | | MOV | 0xb | 0 | dst = src | 453 | +-------+------+---------+---------------------------------------+ 454 | | MOVSX | 0xb | 8/16/32 | dst = (s8,s16,s32)src | 455 | +-------+------+---------+---------------------------------------+ 456 | | ARSH | 0xc | 0 | sign extending (Section 2.3) dst >>= | 457 | | | | | (src & mask) | 458 | +-------+------+---------+---------------------------------------+ 459 | | END | 0xd | 0 | byte swap operations (see | 460 | | | | | Section 4.2) | 461 | +-------+------+---------+---------------------------------------+ 462 | 463 | Table 5: Arithmetic Instructions 464 | 465 | Underflow and overflow are allowed during arithmetic operations, 466 | meaning the 64-bit or 32-bit value will wrap. If BPF program 467 | execution would result in division by zero, the destination register 468 | is instead set to zero. If execution would result in modulo by zero, 469 | for ALU64 the value of the destination register is unchanged whereas 470 | for ALU the upper 32 bits of the destination register are zeroed. 471 | 472 | {ADD, X, ALU}, where 'code' = ADD, 'source' = X, and 'class' = ALU, 473 | means: 474 | 475 | dst = (u32) ((u32) dst + (u32) src) 476 | 477 | where '(u32)' indicates that the upper 32 bits are zeroed. 478 | 479 | {ADD, X, ALU64} means: 480 | 481 | dst = dst + src 482 | 483 | {XOR, K, ALU} means: 484 | 485 | dst = (u32) dst ^ (u32) imm 486 | 487 | {XOR, K, ALU64} means: 488 | 489 | dst = dst ^ imm 490 | 491 | Note that most arithmetic instructions have 'offset' set to 0. Only 492 | three instructions (SDIV, SMOD, MOVSX) have a non-zero 'offset'. 493 | 494 | Division, multiplication, and modulo operations for ALU are part of 495 | the "divmul32" conformance group, and division, multiplication, and 496 | modulo operations for ALU64 are part of the "divmul64" conformance 497 | group. The division and modulo operations support both unsigned and 498 | signed flavors. 499 | 500 | For unsigned operations (DIV and MOD), for ALU, 'imm' is interpreted 501 | as a 32-bit unsigned value. For ALU64, 'imm' is first sign extended 502 | (Section 2.3) from 32 to 64 bits, and then interpreted as a 64-bit 503 | unsigned value. 504 | 505 | For signed operations (SDIV and SMOD), for ALU, 'imm' is interpreted 506 | as a 32-bit signed value. For ALU64, 'imm' is first sign extended 507 | (Section 2.3) from 32 to 64 bits, and then interpreted as a 64-bit 508 | signed value. 509 | 510 | Note that there are varying definitions of the signed modulo 511 | operation when the dividend or divisor are negative, where 512 | implementations often vary by language such that Python, Ruby, etc. 513 | differ from C, Go, Java, etc. This specification requires that 514 | signed modulo MUST use truncated division (where -13 % 3 == -1) as 515 | implemented in C, Go, etc.: 516 | 517 | a % n = a - n * trunc(a / n) 518 | 519 | The MOVSX instruction does a move operation with sign extension. 520 | {MOVSX, X, ALU} sign extends (Section 2.3) 8-bit and 16-bit operands 521 | into 32-bit operands, and zeroes the remaining upper 32 bits. 522 | {MOVSX, X, ALU64} sign extends (Section 2.3) 8-bit, 16-bit, and 523 | 32-bit operands into 64-bit operands. Unlike other arithmetic 524 | instructions, MOVSX is only defined for register source operands (X). 525 | 526 | {MOV, K, ALU64} means: 527 | 528 | dst = (s64)imm 529 | 530 | {MOV, X, ALU} means: 531 | 532 | dst = (u32)src 533 | 534 | {MOVSX, X, ALU} with 'offset' 8 means: 535 | 536 | dst = (u32)(s32)(s8)src 537 | 538 | The NEG instruction is only defined when the source bit is clear (K). 539 | 540 | Shift operations use a mask of 0x3F (63) for 64-bit operations and 541 | 0x1F (31) for 32-bit operations. 542 | 543 | 4.2. Byte Swap Instructions 544 | 545 | The byte swap instructions use instruction classes of ALU and ALU64 546 | and a 4-bit 'code' field of END. 547 | 548 | The byte swap instructions operate on the destination register only 549 | and do not use a separate source register or immediate value. 550 | 551 | For ALU, the 1-bit source operand field in the opcode is used to 552 | select what byte order the operation converts from or to. For ALU64, 553 | the 1-bit source operand field in the opcode is reserved and MUST be 554 | set to 0. 555 | 556 | +=======+==========+=======+===========================+ 557 | | class | source | Value | Description | 558 | +=======+==========+=======+===========================+ 559 | | ALU | LE | 0 | convert between host byte | 560 | | | | | order and little endian | 561 | +-------+----------+-------+---------------------------+ 562 | | ALU | BE | 1 | convert between host byte | 563 | | | | | order and big endian | 564 | +-------+----------+-------+---------------------------+ 565 | | ALU64 | Reserved | 0 | do byte swap | 566 | | | | | unconditionally | 567 | +-------+----------+-------+---------------------------+ 568 | 569 | Table 6: Byte Swap Instructions 570 | 571 | The 'imm' field encodes the width of the swap operations. The 572 | following widths are supported: 16, 32, and 64. Width 64 operations 573 | belong to the base64 conformance group and other swap operations 574 | belong to the base32 conformance group. 575 | 576 | Examples: 577 | 578 | {END, LE, ALU} with 'imm' = 16/32/64 means: 579 | 580 | dst = le16(dst) 581 | dst = le32(dst) 582 | dst = le64(dst) 583 | 584 | {END, BE, ALU} with 'imm' = 16/32/64 means: 585 | 586 | dst = be16(dst) 587 | dst = be32(dst) 588 | dst = be64(dst) 589 | 590 | {END, TO, ALU64} with 'imm' = 16/32/64 means: 591 | 592 | dst = bswap16(dst) 593 | dst = bswap32(dst) 594 | dst = bswap64(dst) 595 | 596 | 4.3. Jump Instructions 597 | 598 | JMP32 uses 32-bit wide operands and indicates the base32 conformance 599 | group; JMP uses 64-bit wide operands for otherwise identical 600 | operations and indicates the base64 conformance group unless 601 | otherwise specified. The 'code' field encodes the operation as 602 | below: 603 | 604 | +======+=======+=========+======================+================+ 605 | | code | Value | src_reg | Description | Notes | 606 | +======+=======+=========+======================+================+ 607 | | JA | 0x0 | 0x0 | PC += offset | {JA, K, JMP} | 608 | | | | | | only | 609 | +------+-------+---------+----------------------+----------------+ 610 | | JA | 0x0 | 0x0 | PC += imm | {JA, K, JMP32} | 611 | | | | | | only | 612 | +------+-------+---------+----------------------+----------------+ 613 | | JEQ | 0x1 | any | PC += offset if dst | | 614 | | | | | == src | | 615 | +------+-------+---------+----------------------+----------------+ 616 | | JGT | 0x2 | any | PC += offset if dst | unsigned | 617 | | | | | > src | | 618 | +------+-------+---------+----------------------+----------------+ 619 | | JGE | 0x3 | any | PC += offset if dst | unsigned | 620 | | | | | >= src | | 621 | +------+-------+---------+----------------------+----------------+ 622 | | JSET | 0x4 | any | PC += offset if dst | | 623 | | | | | & src | | 624 | +------+-------+---------+----------------------+----------------+ 625 | | JNE | 0x5 | any | PC += offset if dst | | 626 | | | | | != src | | 627 | +------+-------+---------+----------------------+----------------+ 628 | | JSGT | 0x6 | any | PC += offset if dst | signed | 629 | | | | | > src | | 630 | +------+-------+---------+----------------------+----------------+ 631 | | JSGE | 0x7 | any | PC += offset if dst | signed | 632 | | | | | >= src | | 633 | +------+-------+---------+----------------------+----------------+ 634 | | CALL | 0x8 | 0x0 | call helper function | {CALL, K, JMP} | 635 | | | | | by static ID | only, see | 636 | | | | | | Section 4.3.1 | 637 | +------+-------+---------+----------------------+----------------+ 638 | | CALL | 0x8 | 0x1 | call PC += imm | {CALL, K, JMP} | 639 | | | | | | only, see | 640 | | | | | | Section 4.3.2 | 641 | +------+-------+---------+----------------------+----------------+ 642 | | CALL | 0x8 | 0x2 | call helper function | {CALL, K, JMP} | 643 | | | | | by BTF ID | only, see | 644 | | | | | | Section 4.3.1 | 645 | +------+-------+---------+----------------------+----------------+ 646 | | EXIT | 0x9 | 0x0 | return | {CALL, K, JMP} | 647 | | | | | | only | 648 | +------+-------+---------+----------------------+----------------+ 649 | | JLT | 0xa | any | PC += offset if dst | unsigned | 650 | | | | | < src | | 651 | +------+-------+---------+----------------------+----------------+ 652 | | JLE | 0xb | any | PC += offset if dst | unsigned | 653 | | | | | <= src | | 654 | +------+-------+---------+----------------------+----------------+ 655 | | JSLT | 0xc | any | PC += offset if dst | signed | 656 | | | | | < src | | 657 | +------+-------+---------+----------------------+----------------+ 658 | | JSLE | 0xd | any | PC += offset if dst | signed | 659 | | | | | <= src | | 660 | +------+-------+---------+----------------------+----------------+ 661 | 662 | Table 7: Jump Instructions 663 | 664 | where 'PC' denotes the program counter, and the offset to increment 665 | by is in units of 64-bit instructions relative to the instruction 666 | following the jump instruction. Thus 'PC += 1' skips execution of 667 | the next instruction if it's a basic instruction or results in 668 | undefined behavior if the next instruction is a 128-bit wide 669 | instruction. 670 | 671 | Example: 672 | 673 | {JSGE, X, JMP32} means: 674 | 675 | if (s32)dst s>= (s32)src goto +offset 676 | 677 | where 's>=' indicates a signed '>=' comparison. 678 | 679 | {JLE, K, JMP} means: 680 | 681 | if dst <= (u64)(s64)imm goto +offset 682 | 683 | {JA, K, JMP32} means: 684 | 685 | gotol +imm 686 | 687 | where 'imm' means the branch offset comes from the 'imm' field. 688 | 689 | Note that there are two flavors of JA instructions. The JMP class 690 | permits a 16-bit jump offset specified by the 'offset' field, whereas 691 | the JMP32 class permits a 32-bit jump offset specified by the 'imm' 692 | field. A conditional jump greater than 16 bits may be converted to a 693 | conditional jump less than 16 bits plus a 32-bit unconditional jump. 694 | 695 | All CALL and JA instructions belong to the base32 conformance group. 696 | 697 | 4.3.1. Helper Functions 698 | 699 | Helper functions are a concept whereby BPF programs can call into a 700 | set of function calls exposed by the underlying platform. 701 | 702 | Historically, each helper function was identified by a static ID 703 | encoded in the 'imm' field. Further documentation of helper 704 | functions is outside the scope of this document and standardization 705 | is left for future work, but use is widely deployed and more 706 | information can be found in platform-specific documentation (e.g., 707 | Linux kernel documentation). 708 | 709 | Platforms that support the BPF Type Format (BTF) support identifying 710 | a helper function by a BTF ID encoded in the 'imm' field, where the 711 | BTF ID identifies the helper name and type. Further documentation of 712 | BTF is outside the scope of this document and standardization is left 713 | for future work, but use is widely deployed and more information can 714 | be found in platform-specific documentation (e.g., Linux kernel 715 | documentation). 716 | 717 | 4.3.2. Program-Local Functions 718 | 719 | Program-local functions are functions exposed by the same BPF program 720 | as the caller, and are referenced by offset from the instruction 721 | following the call instruction, similar to JA. The offset is encoded 722 | in the 'imm' field of the call instruction. An EXIT within the 723 | program-local function will return to the caller. 724 | 725 | 5. Load and Store Instructions 726 | 727 | For load and store instructions (LD, LDX, ST, and STX), the 8-bit 728 | 'opcode' field is divided as follows: 729 | 730 | +-+-+-+-+-+-+-+-+ 731 | |mode |sz |class| 732 | +-+-+-+-+-+-+-+-+ 733 | 734 | *mode:* The mode modifier is one of: 735 | 736 | +========+=======+===============================+=============+ 737 | | mode | Value | Description | Reference | 738 | +========+=======+===============================+=============+ 739 | | IMM | 0 | 64-bit immediate instructions | Section 5.4 | 740 | +--------+-------+-------------------------------+-------------+ 741 | | ABS | 1 | legacy BPF packet access | Section 5.5 | 742 | | | | (absolute) | | 743 | +--------+-------+-------------------------------+-------------+ 744 | | IND | 2 | legacy BPF packet access | Section 5.5 | 745 | | | | (indirect) | | 746 | +--------+-------+-------------------------------+-------------+ 747 | | MEM | 3 | regular load and store | Section 5.1 | 748 | | | | operations | | 749 | +--------+-------+-------------------------------+-------------+ 750 | | MEMSX | 4 | sign-extension load | Section 5.2 | 751 | | | | operations | | 752 | +--------+-------+-------------------------------+-------------+ 753 | | ATOMIC | 6 | atomic operations | Section 5.3 | 754 | +--------+-------+-------------------------------+-------------+ 755 | 756 | Table 8: Mode Modifier 757 | 758 | *sz (size):* The size modifier is one of: 759 | 760 | +======+=======+=======================+ 761 | | size | Value | Description | 762 | +======+=======+=======================+ 763 | | W | 0 | word (4 bytes) | 764 | +------+-------+-----------------------+ 765 | | H | 1 | half word (2 bytes) | 766 | +------+-------+-----------------------+ 767 | | B | 2 | byte | 768 | +------+-------+-----------------------+ 769 | | DW | 3 | double word (8 bytes) | 770 | +------+-------+-----------------------+ 771 | 772 | Table 9: Size Modifier 773 | 774 | Instructions using DW belong to the base64 conformance group. 775 | 776 | *class:* The instruction class (see Section 3.3) 777 | 778 | 5.1. Regular Load and Store Operations 779 | 780 | The MEM mode modifier is used to encode regular load and store 781 | instructions that transfer data between a register and memory. 782 | 783 | {MEM, , STX} means: 784 | 785 | *(size *) (dst + offset) = src 786 | 787 | {MEM, , ST} means: 788 | 789 | *(size *) (dst + offset) = imm 790 | 791 | {MEM, , LDX} means: 792 | 793 | dst = *(unsigned size *) (src + offset) 794 | 795 | Where '' is one of: B, H, W, or DW, and 'unsigned size' is one 796 | of: u8, u16, u32, or u64. 797 | 798 | 5.2. Sign-Extension Load Operations 799 | 800 | The MEMSX mode modifier is used to encode sign-extension load 801 | instructions (Section 2.3) that transfer data between a register and 802 | memory. 803 | 804 | {MEMSX, , LDX} means: 805 | 806 | dst = *(signed size *) (src + offset) 807 | 808 | Where '' is one of: B, H, or W, and 'signed size' is one of: 809 | s8, s16, or s32. 810 | 811 | 5.3. Atomic Operations 812 | 813 | Atomic operations operate on memory and cannot be interrupted or 814 | corrupted by other access to the same memory region by other BPF 815 | programs or means outside of this specification. 816 | 817 | All atomic operations supported by BPF are encoded as store 818 | operations that use the ATOMIC mode modifier as follows: 819 | 820 | * {ATOMIC, W, STX} for 32-bit operations, which are part of the 821 | "atomic32" conformance group. 822 | 823 | * {ATOMIC, DW, STX} for 64-bit operations, which are part of the 824 | "atomic64" conformance group. 825 | 826 | * 8-bit and 16-bit wide atomic operations are not supported. 827 | 828 | The 'imm' field is used to encode the actual atomic operation. 829 | Simple atomic operations use a subset of the values defined to encode 830 | arithmetic operations in the 'imm' field to encode the atomic 831 | operation: 832 | 833 | +=====+=======+=============+ 834 | | imm | Value | Description | 835 | +=====+=======+=============+ 836 | | ADD | 0x00 | atomic add | 837 | +-----+-------+-------------+ 838 | | OR | 0x40 | atomic or | 839 | +-----+-------+-------------+ 840 | | AND | 0x50 | atomic and | 841 | +-----+-------+-------------+ 842 | | XOR | 0xa0 | atomic xor | 843 | +-----+-------+-------------+ 844 | 845 | Table 10: Simple Atomic 846 | Operations 847 | 848 | {ATOMIC, W, STX} with 'imm' = ADD means: 849 | 850 | *(u32 *)(dst + offset) += src 851 | 852 | {ATOMIC, DW, STX} with 'imm' = ADD means: 853 | 854 | *(u64 *)(dst + offset) += src 855 | 856 | In addition to the simple atomic operations, there is also a modifier 857 | and two complex atomic operations: 858 | 859 | +=========+==============+=============================+ 860 | | imm | Value | Description | 861 | +=========+==============+=============================+ 862 | | FETCH | 0x01 | modifier: return old value | 863 | +---------+--------------+-----------------------------+ 864 | | XCHG | 0xe0 | FETCH | atomic exchange | 865 | +---------+--------------+-----------------------------+ 866 | | CMPXCHG | 0xf0 | FETCH | atomic compare and exchange | 867 | +---------+--------------+-----------------------------+ 868 | 869 | Table 11: Complex Atomic Operations and a Modifier 870 | 871 | The FETCH modifier is optional for simple atomic operations and is 872 | always set for the complex atomic operations. If the FETCH flag is 873 | set, then the operation also overwrites src with the value that was 874 | in memory before it was modified. 875 | 876 | The XCHG operation atomically exchanges src with the value addressed 877 | by dst + offset. 878 | 879 | The CMPXCHG operation atomically compares the value addressed by dst 880 | + offset with R0. If they match, the value addressed by dst + offset 881 | is replaced with src. In either case, the value that was at dst + 882 | offset before the operation is zero-extended and loaded back to R0. 883 | 884 | 5.4. 64-bit Immediate Instructions 885 | 886 | Instructions with the IMM 'mode' modifier use the wide instruction 887 | encoding defined in Section 3, and use the 'src_reg' field of the 888 | basic instruction to hold an opcode subtype. 889 | 890 | The following table defines a set of {IMM, DW, LD} instructions with 891 | opcode subtypes in the 'src_reg' field, using new terms such as "map" 892 | defined further below: 893 | 894 | +=========+================================+==========+==========+ 895 | | src_reg | Pseudocode | imm Type | dst Type | 896 | +=========+================================+==========+==========+ 897 | | 0x0 | dst = (next_imm << 32) | imm | integer | integer | 898 | +---------+--------------------------------+----------+----------+ 899 | | 0x1 | dst = map_by_fd(imm) | map fd | map | 900 | +---------+--------------------------------+----------+----------+ 901 | | 0x2 | dst = map_val(map_by_fd(imm)) | map fd | data | 902 | | | + next_imm | | address | 903 | +---------+--------------------------------+----------+----------+ 904 | | 0x3 | dst = var_addr(imm) | variable | data | 905 | | | | id | address | 906 | +---------+--------------------------------+----------+----------+ 907 | | 0x4 | dst = code_addr(imm) | integer | code | 908 | | | | | address | 909 | +---------+--------------------------------+----------+----------+ 910 | | 0x5 | dst = map_by_idx(imm) | map | map | 911 | | | | index | | 912 | +---------+--------------------------------+----------+----------+ 913 | | 0x6 | dst = map_val(map_by_idx(imm)) | map | data | 914 | | | + next_imm | index | address | 915 | +---------+--------------------------------+----------+----------+ 916 | 917 | Table 12: 64-bit Immediate Instructions 918 | 919 | where 920 | 921 | * map_by_fd(imm) means to convert a 32-bit file descriptor into an 922 | address of a map (see Section 5.4.1) 923 | 924 | * map_by_idx(imm) means to convert a 32-bit index into an address of 925 | a map 926 | 927 | * map_val(map) gets the address of the first value in a given map 928 | 929 | * var_addr(imm) gets the address of a platform variable (see 930 | Section 5.4.2) with a given id 931 | 932 | * code_addr(imm) gets the address of the instruction at a specified 933 | relative offset in number of (64-bit) instructions 934 | 935 | * the 'imm type' can be used by disassemblers for display 936 | 937 | * the 'dst type' can be used for verification and just-in-time 938 | compilation purposes 939 | 940 | 5.4.1. Maps 941 | 942 | Maps are shared memory regions accessible by BPF programs on some 943 | platforms. A map can have various semantics as defined in a separate 944 | document, and may or may not have a single contiguous memory region, 945 | but the 'map_val(map)' is currently only defined for maps that do 946 | have a single contiguous memory region. 947 | 948 | Each map can have a file descriptor (fd) if supported by the 949 | platform, where 'map_by_fd(imm)' means to get the map with the 950 | specified file descriptor. Each BPF program can also be defined to 951 | use a set of maps associated with the program at load time, and 952 | 'map_by_idx(imm)' means to get the map with the given index in the 953 | set associated with the BPF program containing the instruction. 954 | 955 | 5.4.2. Platform Variables 956 | 957 | Platform variables are memory regions, identified by integer ids, 958 | exposed by the runtime, and accessible by BPF programs on some 959 | platforms. The 'var_addr(imm)' operation means to get the address of 960 | the memory region identified by the given id. 961 | 962 | 5.5. Legacy BPF Packet Access Instructions 963 | 964 | BPF previously introduced special instructions for access to packet 965 | data that were carried over from classic BPF. These instructions 966 | used an instruction class of LD, a size modifier of W, H, or B, and a 967 | mode modifier of ABS or IND. The 'dst_reg' and 'offset' fields were 968 | set to zero, and 'src_reg' was set to zero for ABS. However, these 969 | instructions are deprecated and SHOULD no longer be used. All legacy 970 | packet access instructions belong to the "packet" conformance group. 971 | 972 | 6. Security Considerations 973 | 974 | BPF programs could use BPF instructions to do malicious things with 975 | memory, CPU, networking, or other system resources. This is not 976 | fundamentally different from any other type of software that may run 977 | on a device. Execution environments should be carefully designed to 978 | only run BPF programs that are trusted and verified, and sandboxing 979 | and privilege level separation are key strategies for limiting 980 | security and abuse impact. For example, BPF verifiers are well-known 981 | and widely deployed and are responsible for ensuring that BPF 982 | programs will terminate within a reasonable time, only interact with 983 | memory in safe ways, adhere to platform-specified API contracts, and 984 | don't use instructions with undefined behavior. This level of 985 | verification can often provide a stronger level of security assurance 986 | than for other software and operating system code. While the details 987 | are out of scope of this document, Linux [LINUX] and PREVAIL 988 | [PREVAIL] provide many details. Future IETF work will document 989 | verifier expectations and building blocks for allowing safe execution 990 | of untrusted BPF programs. 991 | 992 | Executing programs using the BPF instruction set also requires either 993 | an interpreter or a compiler to translate them to built-in hardware 994 | processor instructions. In general, interpreters are considered a 995 | source of insecurity (e.g., gadgets susceptible to side-channel 996 | attacks due to speculative execution) whenever one is used in the 997 | same memory address space as data with confidentiality concerns. As 998 | such, use of a compiler is recommended instead. Compilers should be 999 | audited carefully for vulnerabilities to ensure that compilation of a 1000 | trusted and verified BPF program to built-in processor instructions 1001 | does not introduce vulnerabilities. 1002 | 1003 | Exposing functionality via BPF extends the interface between the 1004 | component executing the BPF program and the component submitting it. 1005 | Careful consideration of what functionality is exposed and how that 1006 | impacts the security properties desired is required. 1007 | 1008 | 7. IANA Considerations 1009 | 1010 | This document defines two registries. 1011 | 1012 | 7.1. BPF Instruction Conformance Groups Registry 1013 | 1014 | This document defines an IANA registry for BPF instruction 1015 | conformance groups, as follows: 1016 | 1017 | * Name of the registry: BPF Instruction Conformance Groups 1018 | 1019 | * Name of the registry group: BPF Instructions 1020 | 1021 | * Required information for registrations: See the BPF Instruction 1022 | Conformance Groups Registration Template (Section 7.1.1) 1023 | 1024 | * Syntax of registry entries: Each entry has the following fields: 1025 | name, description, includes, excludes, status, change controller, 1026 | and reference. See Section 7.1.1 for more details. 1027 | 1028 | * Registration policy (see Section 4 of [RFC8126] for details): 1029 | 1030 | - Permanent: Standards Action or IESG Approval 1031 | 1032 | - Provisional: Specification Required 1033 | 1034 | - Historical: Specification Required 1035 | 1036 | * Contact: BPF Working Group 1037 | 1038 | * Change Controller: IETF 1039 | 1040 | Initial entries in this registry are as follows: 1041 | 1042 | +========+===============+========+========+============+===========+ 1043 | |Name | Description |Includes|Excludes| Status | Reference | 1044 | +========+===============+========+========+============+===========+ 1045 | |atomic32| 32-bit |- |- | Permanent | RFC 9669, | 1046 | | | atomic | | | | Section | 1047 | | | instructions | | | | 5.3 | 1048 | +--------+---------------+--------+--------+------------+-----------+ 1049 | |atomic64| 64-bit |atomic32|- | Permanent | RFC 9669, | 1050 | | | atomic | | | | Section | 1051 | | | instructions | | | | 5.3 | 1052 | +--------+---------------+--------+--------+------------+-----------+ 1053 | |base32 | 32-bit base |- |- | Permanent | RFC 9669 | 1054 | | | instructions | | | | | 1055 | +--------+---------------+--------+--------+------------+-----------+ 1056 | |base64 | 64-bit base |base32 |- | Permanent | RFC 9669 | 1057 | | | instructions | | | | | 1058 | +--------+---------------+--------+--------+------------+-----------+ 1059 | |divmul32| 32-bit |- |- | Permanent | RFC 9669, | 1060 | | | division and | | | | Section | 1061 | | | modulo | | | | 4.1 | 1062 | +--------+---------------+--------+--------+------------+-----------+ 1063 | |divmul64| 64-bit |divmul32|- | Permanent | RFC 9669, | 1064 | | | division and | | | | Section | 1065 | | | modulo | | | | 4.1 | 1066 | +--------+---------------+--------+--------+------------+-----------+ 1067 | |packet | Legacy |- |- | Historical | RFC 9669, | 1068 | | | packet | | | | Section | 1069 | | | instructions | | | | 5.5 | 1070 | +--------+---------------+--------+--------+------------+-----------+ 1071 | 1072 | Table 13: Initial Conformance Groups 1073 | 1074 | 7.1.1. BPF Instruction Conformance Groups Registration Template 1075 | 1076 | This template describes the fields that must be supplied in a 1077 | registration request: 1078 | 1079 | Name: Alphanumeric label indicating the name of the conformance 1080 | group. 1081 | 1082 | Description: Brief description of the conformance group. 1083 | 1084 | Includes: Any other conformance groups that are included by this 1085 | group. 1086 | 1087 | Excludes: Any other conformance groups that are excluded by this 1088 | group. 1089 | 1090 | Status: This reflects the status requested and must be one of 1091 | 'Permanent', 'Provisional', or 'Historical'. 1092 | 1093 | Contact: Person (including contact information) to contact for 1094 | further information. 1095 | 1096 | Change Controller: Organization or person (often the author of the 1097 | defining specification), including contact information, authorized 1098 | to change this. 1099 | 1100 | Reference: A reference to the defining specification. Include full 1101 | citations for all referenced documents. Registration requests for 1102 | 'Provisional' registration can be included in an Internet-Draft; 1103 | when the documents are approved for publication as an RFC, the 1104 | registration will be updated to 'Permanent'. 1105 | 1106 | 7.2. BPF Instruction Set Registry 1107 | 1108 | This document defines an IANA registry for BPF instructions, as 1109 | follows: 1110 | 1111 | * Name of the registry: BPF Instruction Set 1112 | 1113 | * Name of the registry group: BPF Instructions 1114 | 1115 | * Required information for registrations: See the BPF Instruction 1116 | Registration Template (Section 7.2.1) 1117 | 1118 | * Syntax of registry entries: Each entry has the following fields: 1119 | opcode, src, offset, imm, description, groups, change controller, 1120 | and reference. See Section 7.2.1 for more details. 1121 | 1122 | * Registration policy: New instructions require a new entry in the 1123 | conformance group registry and the same registration policies 1124 | apply. 1125 | 1126 | * Contact: BPF Working Group 1127 | 1128 | * Change Controller: IETF 1129 | 1130 | * Initial registrations: See Appendix A. Instructions other than 1131 | those listed as deprecated are Permanent. Any listed as 1132 | deprecated are Historical. 1133 | 1134 | 7.2.1. BPF Instruction Registration Template 1135 | 1136 | This template describes the fields that must be supplied in a 1137 | registration request: 1138 | 1139 | Opcode: A 1-byte value in hex format indicating the value of the 1140 | opcode field. 1141 | 1142 | Src_reg: Either a numeric value indicating the value of the src_reg 1143 | field, or "any". 1144 | 1145 | Offset: Either a numeric value indicating the value of the offset 1146 | field, or "any". 1147 | 1148 | Imm: Either a value indicating the value of the imm field, or "any". 1149 | 1150 | Description: Description of what the instruction does, typically in 1151 | pseudocode. 1152 | 1153 | Groups: A list of one or more comma-separated conformance groups to 1154 | which the instruction belongs. 1155 | 1156 | Contact: Person (including contact information) to contact for 1157 | further information. 1158 | 1159 | Change Controller: Organization or person (often the author), 1160 | including contact information, authorized to change this. 1161 | 1162 | Reference: A reference to the defining specification. Include full 1163 | citations for all referenced documents. Registration requests for 1164 | 'Provisional' registration can be included in an Internet-Draft; 1165 | when the documents are approved for publication as an RFC, the 1166 | registration will be updated to 'Permanent'. 1167 | 1168 | 7.3. Adding Instructions 1169 | 1170 | A specification may add additional instructions to the BPF 1171 | Instruction Set registry. Once a conformance group is registered 1172 | with a set of instructions, no further instructions can be added to 1173 | that conformance group. A specification should instead create a new 1174 | conformance group that includes the original conformance group, plus 1175 | any newly added instructions. Inclusion of the original conformance 1176 | group is done via the "includes" column of the BPF Instruction 1177 | Conformance Groups registry, and inclusion of newly added 1178 | instructions is done via the "groups" column of the BPF Instruction 1179 | Set registry. 1180 | 1181 | For example, consider an existing hypothetical group called "example" 1182 | with two instructions in it. One might add two more instructions by 1183 | first adding an "examplev2" group to the BPF Instruction Conformance 1184 | Groups registry as follows: 1185 | 1186 | +===========+==================+==========+==========+===========+ 1187 | | Name | Description | Includes | Excludes | Status | 1188 | +===========+==================+==========+==========+===========+ 1189 | | example | Original example | - | - | Permanent | 1190 | | | instructions | | | | 1191 | +-----------+------------------+----------+----------+-----------+ 1192 | | examplev2 | Newer set of | example | - | Permanent | 1193 | | | example | | | | 1194 | | | instructions | | | | 1195 | +-----------+------------------+----------+----------+-----------+ 1196 | 1197 | Table 14: Conformance Group Example for Addition 1198 | 1199 | And then adding the new instructions into the BPF Instruction Set 1200 | registry as follows: 1201 | 1202 | +========+=====+================================+===========+ 1203 | | opcode | ... | Description | Groups | 1204 | +========+=====+================================+===========+ 1205 | | aaa | ... | Original example instruction 1 | example | 1206 | +--------+-----+--------------------------------+-----------+ 1207 | | bbb | ... | Original example instruction 2 | example | 1208 | +--------+-----+--------------------------------+-----------+ 1209 | | ccc | ... | Added example instruction 3 | examplev2 | 1210 | +--------+-----+--------------------------------+-----------+ 1211 | | ddd | ... | Added example instruction 4 | examplev2 | 1212 | +--------+-----+--------------------------------+-----------+ 1213 | 1214 | Table 15: Instruction Addition Example 1215 | 1216 | Supporting the "examplev2" group thus requires supporting all four 1217 | example instructions. 1218 | 1219 | 7.4. Deprecating Instructions 1220 | 1221 | Deprecating instructions that are part of an existing conformance 1222 | group can be done by defining a new conformance group for the newly 1223 | deprecated instructions, and defining a new conformance group that 1224 | supersedes the existing conformance group containing the 1225 | instructions, where the new conformance group includes the existing 1226 | one and excludes the deprecated instruction group. 1227 | 1228 | For example, if deprecating an instruction in an existing 1229 | hypothetical group called "example", two new groups ("legacyexample" 1230 | and "examplev2") might be registered in the BPF Instruction 1231 | Conformance Groups registry as follows: 1232 | 1233 | +===============+==============+========+===============+==========+ 1234 | | Name | Description |Includes| Excludes |Status | 1235 | +===============+==============+========+===============+==========+ 1236 | | example | Original |- | - |Permanent | 1237 | | | example | | | | 1238 | | | instructions | | | | 1239 | +---------------+--------------+--------+---------------+----------+ 1240 | | legacyexample | Legacy |- | - |Historical| 1241 | | | example | | | | 1242 | | | instructions | | | | 1243 | +---------------+--------------+--------+---------------+----------+ 1244 | | examplev2 | Example |example | legacyexample |Permanent | 1245 | | | instructions | | | | 1246 | +---------------+--------------+--------+---------------+----------+ 1247 | 1248 | Table 16: Conformance Group Example for Deprecation 1249 | 1250 | The BPF Instruction Set registry entries for the deprecated 1251 | instructions would then be updated to add "legacyexample" to the set 1252 | of groups for those instructions, as follows: 1253 | 1254 | +========+=====+=============================+===============+ 1255 | | opcode | ... | Description | Groups | 1256 | +========+=====+=============================+===============+ 1257 | | aaa | ... | Good original instruction 1 | example | 1258 | +--------+-----+-----------------------------+---------------+ 1259 | | bbb | ... | Good original instruction 2 | example | 1260 | +--------+-----+-----------------------------+---------------+ 1261 | | ccc | ... | Bad original instruction 3 | example, | 1262 | | | | | legacyexample | 1263 | +--------+-----+-----------------------------+---------------+ 1264 | | ddd | ... | Bad original instruction 4 | example, | 1265 | | | | | legacyexample | 1266 | +--------+-----+-----------------------------+---------------+ 1267 | 1268 | Table 17: Instruction Deprecation Example 1269 | 1270 | Finally, updated implementations that dropped support for the 1271 | deprecated instructions would then be able to claim conformance to 1272 | "examplev2" rather than "example". 1273 | 1274 | 7.5. Change Control 1275 | 1276 | Registrations can be updated in a registry by the same mechanism as 1277 | required for an initial registration. In cases where the original 1278 | definition of an entry is contained in an IESG-approved document, in 1279 | which case the IETF would be the change controller, update of the 1280 | specification also requires IESG approval. 1281 | 1282 | 'Provisional' registrations can be updated by the change controller 1283 | designated in the existing registration. In addition, the IESG can 1284 | reassign responsibility for a 'Provisional' registration or can 1285 | request specific changes to an entry. This will enable changes to be 1286 | made to entries where the original registrant is out of contact or 1287 | unwilling or unable to make changes. 1288 | 1289 | Transition from 'Provisional' to 'Permanent' status can be requested 1290 | and approved in the same manner as a new 'Permanent' registration. 1291 | Transition from 'Permanent' to 'Historical' status requires IESG 1292 | approval. Transition from 'Provisional' to 'Historical' can be 1293 | requested by anyone authorized to update the 'Provisional' 1294 | registration. 1295 | 1296 | 7.6. Expert Review Instructions 1297 | 1298 | The IANA registries established by this document are informed by 1299 | written specifications, which themselves are facilitated and approved 1300 | by an Expert Review process (see Section 5.3 of [RFC8126]). 1301 | 1302 | Designated experts are expected to consult with the active BPF 1303 | working group (e.g., via email to the working group's mailing list) 1304 | if it exists, as well as other interested parties (e.g., via email to 1305 | one or more active mailing list(s) for relevant BPF communities and 1306 | platforms). The designated expert is expected to verify that the 1307 | encoding and semantics for any new instructions are properly 1308 | documented in a public-facing specification. In the event of future 1309 | RFC documents for ISA extensions, experts may permit early assignment 1310 | before the RFC document is available, as long as a specification that 1311 | satisfies the above requirements exists. 1312 | 1313 | 8. References 1314 | 1315 | 8.1. Normative References 1316 | 1317 | [IEN137] Cohen, D., "ON HOLY WARS AND A PLEA FOR PEACE", IEN 137, 1 1318 | April 1980, . 1319 | 1320 | [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 1321 | Requirement Levels", BCP 14, RFC 2119, 1322 | DOI 10.17487/RFC2119, March 1997, 1323 | . 1324 | 1325 | [RFC8126] Cotton, M., Leiba, B., and T. Narten, "Guidelines for 1326 | Writing an IANA Considerations Section in RFCs", BCP 26, 1327 | RFC 8126, DOI 10.17487/RFC8126, June 2017, 1328 | . 1329 | 1330 | [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 1331 | 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, 1332 | May 2017, . 1333 | 1334 | 8.2. Informative References 1335 | 1336 | [LINUX] "eBPF verifier", 1337 | . 1339 | 1340 | [PREVAIL] Gershuni, E., Amit, N., Gurfinkel, A., Narodytska, N., 1341 | Navas, J., Rinetzky, N., Ryzhyk, L., and M. Sagiv, "Simple 1342 | and Precise Static Analysis of Untrusted Linux Kernel 1343 | Extensions", DOI 10.1145/3314221.3314590, June 2019, 1344 | . 1345 | 1346 | Appendix A. Initial BPF Instruction Set Values 1347 | 1348 | Initial values for the BPF Instruction Set registry are given below. 1349 | The descriptions in this table are informative. In case of any 1350 | discrepancy, the reference is authoritative. 1351 | 1352 | +======+=======+====+====+========================+========+=======+ 1353 | |opcode|src_reg|off-|imm |Description |Groups |Ref | 1354 | | | |set | | | | | 1355 | +======+=======+====+====+========================+========+=======+ 1356 | |0x00 |0x0 |0 |any |(additional immediate |base64 |RFC | 1357 | | | | | |value) | |9669, | 1358 | | | | | | | |Section| 1359 | | | | | | | |5.4 | 1360 | +------+-------+----+----+------------------------+--------+-------+ 1361 | |0x04 |0x0 |0 |any |dst = (u32)((u32)dst + |base32 |RFC | 1362 | | | | | |(u32)imm) | |9669, | 1363 | | | | | | | |Section| 1364 | | | | | | | |4.1 | 1365 | +------+-------+----+----+------------------------+--------+-------+ 1366 | |0x05 |0x0 |any |0x00|goto +offset |base32 |RFC | 1367 | | | | | | | |9669, | 1368 | | | | | | | |Section| 1369 | | | | | | | |4.3 | 1370 | +------+-------+----+----+------------------------+--------+-------+ 1371 | |0x06 |0x0 |0 |any |goto +imm |base32 |RFC | 1372 | | | | | | | |9669, | 1373 | | | | | | | |Section| 1374 | | | | | | | |4.3 | 1375 | +------+-------+----+----+------------------------+--------+-------+ 1376 | |0x07 |0x0 |0 |any |dst += imm |base64 |RFC | 1377 | | | | | | | |9669, | 1378 | | | | | | | |Section| 1379 | | | | | | | |4.1 | 1380 | +------+-------+----+----+------------------------+--------+-------+ 1381 | |0x0c |any |0 |0x00|dst = (u32)((u32)dst + |base32 |RFC | 1382 | | | | | |(u32)src) | |9669, | 1383 | | | | | | | |Section| 1384 | | | | | | | |4.1 | 1385 | +------+-------+----+----+------------------------+--------+-------+ 1386 | |0x0f |any |0 |0x00|dst += src |base64 |RFC | 1387 | | | | | | | |9669, | 1388 | | | | | | | |Section| 1389 | | | | | | | |4.1 | 1390 | +------+-------+----+----+------------------------+--------+-------+ 1391 | |0x14 |0x0 |0 |any |dst = (u32)((u32)dst - |base32 |RFC | 1392 | | | | | |(u32)imm) | |9669, | 1393 | | | | | | | |Section| 1394 | | | | | | | |4.1 | 1395 | +------+-------+----+----+------------------------+--------+-------+ 1396 | |0x15 |0x0 |any |any |if dst == imm goto |base64 |RFC | 1397 | | | | | |+offset | |9669, | 1398 | | | | | | | |Section| 1399 | | | | | | | |4.3 | 1400 | +------+-------+----+----+------------------------+--------+-------+ 1401 | |0x16 |0x0 |any |any |if (u32)dst == imm goto |base32 |RFC | 1402 | | | | | |+offset | |9669, | 1403 | | | | | | | |Section| 1404 | | | | | | | |4.3 | 1405 | +------+-------+----+----+------------------------+--------+-------+ 1406 | |0x17 |0x0 |0 |any |dst -= imm |base64 |RFC | 1407 | | | | | | | |9669, | 1408 | | | | | | | |Section| 1409 | | | | | | | |4.1 | 1410 | +------+-------+----+----+------------------------+--------+-------+ 1411 | |0x18 |0x0 |0 |any |dst = (next_imm << 32) ||base64 |RFC | 1412 | | | | | |imm | |9669, | 1413 | | | | | | | |Section| 1414 | | | | | | | |5.4 | 1415 | +------+-------+----+----+------------------------+--------+-------+ 1416 | |0x18 |0x1 |0 |any |dst = map_by_fd(imm) |base64 |RFC | 1417 | | | | | | | |9669, | 1418 | | | | | | | |Section| 1419 | | | | | | | |5.4 | 1420 | +------+-------+----+----+------------------------+--------+-------+ 1421 | |0x18 |0x2 |0 |any |dst = |base64 |RFC | 1422 | | | | | |map_val(map_by_fd(imm)) | |9669, | 1423 | | | | | |+ next_imm | |Section| 1424 | | | | | | | |5.4 | 1425 | +------+-------+----+----+------------------------+--------+-------+ 1426 | |0x18 |0x3 |0 |any |dst = var_addr(imm) |base64 |RFC | 1427 | | | | | | | |9669, | 1428 | | | | | | | |Section| 1429 | | | | | | | |5.4 | 1430 | +------+-------+----+----+------------------------+--------+-------+ 1431 | |0x18 |0x4 |0 |any |dst = code_addr(imm) |base64 |RFC | 1432 | | | | | | | |9669, | 1433 | | | | | | | |Section| 1434 | | | | | | | |5.4 | 1435 | +------+-------+----+----+------------------------+--------+-------+ 1436 | |0x18 |0x5 |0 |any |dst = map_by_idx(imm) |base64 |RFC | 1437 | | | | | | | |9669, | 1438 | | | | | | | |Section| 1439 | | | | | | | |5.4 | 1440 | +------+-------+----+----+------------------------+--------+-------+ 1441 | |0x18 |0x6 |0 |any |dst = |base64 |RFC | 1442 | | | | | |map_val(map_by_idx(imm))| |9669, | 1443 | | | | | |+ next_imm | |Section| 1444 | | | | | | | |5.4 | 1445 | +------+-------+----+----+------------------------+--------+-------+ 1446 | |0x1c |any |0 |0x00|dst = (u32)((u32)dst - |base32 |RFC | 1447 | | | | | |(u32)src) | |9669, | 1448 | | | | | | | |Section| 1449 | | | | | | | |4.1 | 1450 | +------+-------+----+----+------------------------+--------+-------+ 1451 | |0x1d |any |any |0x00|if dst == src goto |base64 |RFC | 1452 | | | | | |+offset | |9669, | 1453 | | | | | | | |Section| 1454 | | | | | | | |4.3 | 1455 | +------+-------+----+----+------------------------+--------+-------+ 1456 | |0x1e |any |any |0x00|if (u32)dst == (u32)src |base32 |RFC | 1457 | | | | | |goto +offset | |9669, | 1458 | | | | | | | |Section| 1459 | | | | | | | |4.3 | 1460 | +------+-------+----+----+------------------------+--------+-------+ 1461 | |0x1f |any |0 |0x00|dst -= src |base64 |RFC | 1462 | | | | | | | |9669, | 1463 | | | | | | | |Section| 1464 | | | | | | | |4.1 | 1465 | +------+-------+----+----+------------------------+--------+-------+ 1466 | |0x20 |0x0 |0 |any |(deprecated, |packet |RFC | 1467 | | | | | |implementation-specific)| |9669, | 1468 | | | | | | | |Section| 1469 | | | | | | | |5.5 | 1470 | +------+-------+----+----+------------------------+--------+-------+ 1471 | |0x24 |0x0 |0 |any |dst = (u32)(dst * imm) |divmul32|RFC | 1472 | | | | | | | |9669, | 1473 | | | | | | | |Section| 1474 | | | | | | | |4.1 | 1475 | +------+-------+----+----+------------------------+--------+-------+ 1476 | |0x25 |0x0 |any |any |if dst > imm goto |base64 |RFC | 1477 | | | | | |+offset | |9669, | 1478 | | | | | | | |Section| 1479 | | | | | | | |4.3 | 1480 | +------+-------+----+----+------------------------+--------+-------+ 1481 | |0x26 |0x0 |any |any |if (u32)dst > imm goto |base32 |RFC | 1482 | | | | | |+offset | |9669, | 1483 | | | | | | | |Section| 1484 | | | | | | | |4.3 | 1485 | +------+-------+----+----+------------------------+--------+-------+ 1486 | |0x27 |0x0 |0 |any |dst *= imm |divmul64|RFC | 1487 | | | | | | | |9669, | 1488 | | | | | | | |Section| 1489 | | | | | | | |4.1 | 1490 | +------+-------+----+----+------------------------+--------+-------+ 1491 | |0x28 |0x0 |0 |any |(deprecated, |packet |RFC | 1492 | | | | | |implementation-specific)| |9669, | 1493 | | | | | | | |Section| 1494 | | | | | | | |5.5 | 1495 | +------+-------+----+----+------------------------+--------+-------+ 1496 | |0x2c |any |0 |0x00|dst = (u32)(dst * src) |divmul32|RFC | 1497 | | | | | | | |9669, | 1498 | | | | | | | |Section| 1499 | | | | | | | |4.1 | 1500 | +------+-------+----+----+------------------------+--------+-------+ 1501 | |0x2d |any |any |0x00|if dst > src goto |base64 |RFC | 1502 | | | | | |+offset | |9669, | 1503 | | | | | | | |Section| 1504 | | | | | | | |4.3 | 1505 | +------+-------+----+----+------------------------+--------+-------+ 1506 | |0x2e |any |any |0x00|if (u32)dst > (u32)src |base32 |RFC | 1507 | | | | | |goto +offset | |9669, | 1508 | | | | | | | |Section| 1509 | | | | | | | |4.3 | 1510 | +------+-------+----+----+------------------------+--------+-------+ 1511 | |0x2f |any |0 |0x00|dst *= src |divmul64|RFC | 1512 | | | | | | | |9669, | 1513 | | | | | | | |Section| 1514 | | | | | | | |4.1 | 1515 | +------+-------+----+----+------------------------+--------+-------+ 1516 | |0x30 |0x0 |0 |any |(deprecated, |packet |RFC | 1517 | | | | | |implementation-specific)| |9669, | 1518 | | | | | | | |Section| 1519 | | | | | | | |5.5 | 1520 | +------+-------+----+----+------------------------+--------+-------+ 1521 | |0x34 |0x0 |0 |any |dst = (u32)((imm != 0) ?|divmul32|RFC | 1522 | | | | | |((u32)dst / (u32)imm) : | |9669, | 1523 | | | | | |0) | |Section| 1524 | | | | | | | |4.1 | 1525 | +------+-------+----+----+------------------------+--------+-------+ 1526 | |0x34 |0x0 |1 |any |dst = (u32)((imm != 0) ?|divmul32|RFC | 1527 | | | | | |((s32)dst s/ imm) : 0) | |9669, | 1528 | | | | | | | |Section| 1529 | | | | | | | |4.1 | 1530 | +------+-------+----+----+------------------------+--------+-------+ 1531 | |0x35 |0x0 |any |any |if dst >= imm goto |base64 |RFC | 1532 | | | | | |+offset | |9669, | 1533 | | | | | | | |Section| 1534 | | | | | | | |4.3 | 1535 | +------+-------+----+----+------------------------+--------+-------+ 1536 | |0x36 |0x0 |any |any |if (u32)dst >= imm goto |base32 |RFC | 1537 | | | | | |+offset | |9669, | 1538 | | | | | | | |Section| 1539 | | | | | | | |4.3 | 1540 | +------+-------+----+----+------------------------+--------+-------+ 1541 | |0x37 |0x0 |0 |any |dst = (imm != 0) ? (dst |divmul64|RFC | 1542 | | | | | |/ (u32)imm) : 0 | |9669, | 1543 | | | | | | | |Section| 1544 | | | | | | | |4.1 | 1545 | +------+-------+----+----+------------------------+--------+-------+ 1546 | |0x37 |0x0 |1 |any |dst = (imm != 0) ? (dst |divmul64|RFC | 1547 | | | | | |s/ imm) : 0 | |9669, | 1548 | | | | | | | |Section| 1549 | | | | | | | |4.1 | 1550 | +------+-------+----+----+------------------------+--------+-------+ 1551 | |0x3c |any |0 |0x00|dst = (u32)((src != 0) ?|divmul32|RFC | 1552 | | | | | |((u32)dst / (u32)src) : | |9669, | 1553 | | | | | |0) | |Section| 1554 | | | | | | | |4.1 | 1555 | +------+-------+----+----+------------------------+--------+-------+ 1556 | |0x3c |any |1 |0x00|dst = (u32)((src != 0) ?|divmul32|RFC | 1557 | | | | | |((s32)dst s/(s32)src) : | |9669, | 1558 | | | | | |0) | |Section| 1559 | | | | | | | |4.1 | 1560 | +------+-------+----+----+------------------------+--------+-------+ 1561 | |0x3d |any |any |0x00|if dst >= src goto |base64 |RFC | 1562 | | | | | |+offset | |9669, | 1563 | | | | | | | |Section| 1564 | | | | | | | |4.3 | 1565 | +------+-------+----+----+------------------------+--------+-------+ 1566 | |0x3e |any |any |0x00|if (u32)dst >= (u32)src |base32 |RFC | 1567 | | | | | |goto +offset | |9669, | 1568 | | | | | | | |Section| 1569 | | | | | | | |4.3 | 1570 | +------+-------+----+----+------------------------+--------+-------+ 1571 | |0x3f |any |0 |0x00|dst = (src != 0) ? (dst |divmul64|RFC | 1572 | | | | | |/ src) : 0 | |9669, | 1573 | | | | | | | |Section| 1574 | | | | | | | |4.1 | 1575 | +------+-------+----+----+------------------------+--------+-------+ 1576 | |0x3f |any |1 |0x00|dst = (src != 0) ? (dst |divmul64|RFC | 1577 | | | | | |s/ src) : 0 | |9669, | 1578 | | | | | | | |Section| 1579 | | | | | | | |4.1 | 1580 | +------+-------+----+----+------------------------+--------+-------+ 1581 | |0x40 |any |0 |any |(deprecated, |packet |RFC | 1582 | | | | | |implementation-specific)| |9669, | 1583 | | | | | | | |Section| 1584 | | | | | | | |5.5 | 1585 | +------+-------+----+----+------------------------+--------+-------+ 1586 | |0x44 |0x0 |0 |any |dst = (u32)(dst | imm) |base32 |RFC | 1587 | | | | | | | |9669, | 1588 | | | | | | | |Section| 1589 | | | | | | | |4.1 | 1590 | +------+-------+----+----+------------------------+--------+-------+ 1591 | |0x45 |0x0 |any |any |if dst & imm goto |base64 |RFC | 1592 | | | | | |+offset | |9669, | 1593 | | | | | | | |Section| 1594 | | | | | | | |4.3 | 1595 | +------+-------+----+----+------------------------+--------+-------+ 1596 | |0x46 |0x0 |any |any |if (u32)dst & imm goto |base32 |RFC | 1597 | | | | | |+offset | |9669, | 1598 | | | | | | | |Section| 1599 | | | | | | | |4.3 | 1600 | +------+-------+----+----+------------------------+--------+-------+ 1601 | |0x47 |0x0 |0 |any |dst |= imm |base64 |RFC | 1602 | | | | | | | |9669, | 1603 | | | | | | | |Section| 1604 | | | | | | | |4.1 | 1605 | +------+-------+----+----+------------------------+--------+-------+ 1606 | |0x48 |any |0 |any |(deprecated, |packet |RFC | 1607 | | | | | |implementation-specific)| |9669, | 1608 | | | | | | | |Section| 1609 | | | | | | | |5.5 | 1610 | +------+-------+----+----+------------------------+--------+-------+ 1611 | |0x4c |any |0 |0x00|dst = (u32)(dst | src) |base32 |RFC | 1612 | | | | | | | |9669, | 1613 | | | | | | | |Section| 1614 | | | | | | | |4.1 | 1615 | +------+-------+----+----+------------------------+--------+-------+ 1616 | |0x4d |any |any |0x00|if dst & src goto |base64 |RFC | 1617 | | | | | |+offset | |9669, | 1618 | | | | | | | |Section| 1619 | | | | | | | |4.3 | 1620 | +------+-------+----+----+------------------------+--------+-------+ 1621 | |0x4e |any |any |0x00|if (u32)dst & (u32)src |base32 |RFC | 1622 | | | | | |goto +offset | |9669, | 1623 | | | | | | | |Section| 1624 | | | | | | | |4.3 | 1625 | +------+-------+----+----+------------------------+--------+-------+ 1626 | |0x4f |any |0 |0x00|dst |= src |base64 |RFC | 1627 | | | | | | | |9669, | 1628 | | | | | | | |Section| 1629 | | | | | | | |4.1 | 1630 | +------+-------+----+----+------------------------+--------+-------+ 1631 | |0x50 |any |0 |any |(deprecated, |packet |RFC | 1632 | | | | | |implementation-specific)| |9669, | 1633 | | | | | | | |Section| 1634 | | | | | | | |5.5 | 1635 | +------+-------+----+----+------------------------+--------+-------+ 1636 | |0x54 |0x0 |0 |any |dst = (u32)(dst & imm) |base32 |RFC | 1637 | | | | | | | |9669, | 1638 | | | | | | | |Section| 1639 | | | | | | | |4.1 | 1640 | +------+-------+----+----+------------------------+--------+-------+ 1641 | |0x55 |0x0 |any |any |if dst != imm goto |base64 |RFC | 1642 | | | | | |+offset | |9669, | 1643 | | | | | | | |Section| 1644 | | | | | | | |4.3 | 1645 | +------+-------+----+----+------------------------+--------+-------+ 1646 | |0x56 |0x0 |any |any |if (u32)dst != imm goto |base32 |RFC | 1647 | | | | | |+offset | |9669, | 1648 | | | | | | | |Section| 1649 | | | | | | | |4.3 | 1650 | +------+-------+----+----+------------------------+--------+-------+ 1651 | |0x57 |0x0 |0 |any |dst &= imm |base64 |RFC | 1652 | | | | | | | |9669, | 1653 | | | | | | | |Section| 1654 | | | | | | | |4.1 | 1655 | +------+-------+----+----+------------------------+--------+-------+ 1656 | |0x5c |any |0 |0x00|dst = (u32)(dst & src) |base32 |RFC | 1657 | | | | | | | |9669, | 1658 | | | | | | | |Section| 1659 | | | | | | | |4.1 | 1660 | +------+-------+----+----+------------------------+--------+-------+ 1661 | |0x5d |any |any |0x00|if dst != src goto |base64 |RFC | 1662 | | | | | |+offset | |9669, | 1663 | | | | | | | |Section| 1664 | | | | | | | |4.3 | 1665 | +------+-------+----+----+------------------------+--------+-------+ 1666 | |0x5e |any |any |0x00|if (u32)dst != (u32)src |base32 |RFC | 1667 | | | | | |goto +offset | |9669, | 1668 | | | | | | | |Section| 1669 | | | | | | | |4.3 | 1670 | +------+-------+----+----+------------------------+--------+-------+ 1671 | |0x5f |any |0 |0x00|dst &= src |base64 |RFC | 1672 | | | | | | | |9669, | 1673 | | | | | | | |Section| 1674 | | | | | | | |4.1 | 1675 | +------+-------+----+----+------------------------+--------+-------+ 1676 | |0x61 |any |any |0x00|dst = *(u32 *)(src + |base32 |RFC | 1677 | | | | | |offset) | |9669, | 1678 | | | | | | | |Section| 1679 | | | | | | | |5 | 1680 | +------+-------+----+----+------------------------+--------+-------+ 1681 | |0x62 |0x0 |any |any |*(u32 *)(dst + offset) =|base32 |RFC | 1682 | | | | | |imm | |9669, | 1683 | | | | | | | |Section| 1684 | | | | | | | |5 | 1685 | +------+-------+----+----+------------------------+--------+-------+ 1686 | |0x63 |any |any |0x00|*(u32 *)(dst + offset) =|base32 |RFC | 1687 | | | | | |src | |9669, | 1688 | | | | | | | |Section| 1689 | | | | | | | |5 | 1690 | +------+-------+----+----+------------------------+--------+-------+ 1691 | |0x64 |0x0 |0 |any |dst = (u32)(dst << imm) |base32 |RFC | 1692 | | | | | | | |9669, | 1693 | | | | | | | |Section| 1694 | | | | | | | |4.1 | 1695 | +------+-------+----+----+------------------------+--------+-------+ 1696 | |0x65 |0x0 |any |any |if dst s> imm goto |base64 |RFC | 1697 | | | | | |+offset | |9669, | 1698 | | | | | | | |Section| 1699 | | | | | | | |4.3 | 1700 | +------+-------+----+----+------------------------+--------+-------+ 1701 | |0x66 |0x0 |any |any |if (s32)dst s> (s32)imm |base32 |RFC | 1702 | | | | | |goto +offset | |9669, | 1703 | | | | | | | |Section| 1704 | | | | | | | |4.3 | 1705 | +------+-------+----+----+------------------------+--------+-------+ 1706 | |0x67 |0x0 |0 |any |dst <<= imm |base64 |RFC | 1707 | | | | | | | |9669, | 1708 | | | | | | | |Section| 1709 | | | | | | | |4.1 | 1710 | +------+-------+----+----+------------------------+--------+-------+ 1711 | |0x69 |any |any |0x00|dst = *(u16 *)(src + |base32 |RFC | 1712 | | | | | |offset) | |9669, | 1713 | | | | | | | |Section| 1714 | | | | | | | |5 | 1715 | +------+-------+----+----+------------------------+--------+-------+ 1716 | |0x6a |0x0 |any |any |*(u16 *)(dst + offset) =|base32 |RFC | 1717 | | | | | |imm | |9669, | 1718 | | | | | | | |Section| 1719 | | | | | | | |5 | 1720 | +------+-------+----+----+------------------------+--------+-------+ 1721 | |0x6b |any |any |0x00|*(u16 *)(dst + offset) =|base32 |RFC | 1722 | | | | | |src | |9669, | 1723 | | | | | | | |Section| 1724 | | | | | | | |5 | 1725 | +------+-------+----+----+------------------------+--------+-------+ 1726 | |0x6c |any |0 |0x00|dst = (u32)(dst << src) |base32 |RFC | 1727 | | | | | | | |9669, | 1728 | | | | | | | |Section| 1729 | | | | | | | |4.1 | 1730 | +------+-------+----+----+------------------------+--------+-------+ 1731 | |0x6d |any |any |0x00|if dst s> src goto |base64 |RFC | 1732 | | | | | |+offset | |9669, | 1733 | | | | | | | |Section| 1734 | | | | | | | |4.3 | 1735 | +------+-------+----+----+------------------------+--------+-------+ 1736 | |0x6e |any |any |0x00|if (s32)dst s> (s32)src |base32 |RFC | 1737 | | | | | |goto +offset | |9669, | 1738 | | | | | | | |Section| 1739 | | | | | | | |4.3 | 1740 | +------+-------+----+----+------------------------+--------+-------+ 1741 | |0x6f |any |0 |0x00|dst <<= src |base64 |RFC | 1742 | | | | | | | |9669, | 1743 | | | | | | | |Section| 1744 | | | | | | | |4.1 | 1745 | +------+-------+----+----+------------------------+--------+-------+ 1746 | |0x71 |any |any |0x00|dst = *(u8 *)(src + |base32 |RFC | 1747 | | | | | |offset) | |9669, | 1748 | | | | | | | |Section| 1749 | | | | | | | |5 | 1750 | +------+-------+----+----+------------------------+--------+-------+ 1751 | |0x72 |0x0 |any |any |*(u8 *)(dst + offset) = |base32 |RFC | 1752 | | | | | |imm | |9669, | 1753 | | | | | | | |Section| 1754 | | | | | | | |5 | 1755 | +------+-------+----+----+------------------------+--------+-------+ 1756 | |0x73 |any |any |0x00|*(u8 *)(dst + offset) = |base32 |RFC | 1757 | | | | | |src | |9669, | 1758 | | | | | | | |Section| 1759 | | | | | | | |5 | 1760 | +------+-------+----+----+------------------------+--------+-------+ 1761 | |0x74 |0x0 |0 |any |dst = (u32)(dst >> imm) |base32 |RFC | 1762 | | | | | | | |9669, | 1763 | | | | | | | |Section| 1764 | | | | | | | |4.1 | 1765 | +------+-------+----+----+------------------------+--------+-------+ 1766 | |0x75 |0x0 |any |any |if dst s>= imm goto |base64 |RFC | 1767 | | | | | |+offset | |9669, | 1768 | | | | | | | |Section| 1769 | | | | | | | |4.3 | 1770 | +------+-------+----+----+------------------------+--------+-------+ 1771 | |0x76 |0x0 |any |any |if (s32)dst s>= (s32)imm|base32 |RFC | 1772 | | | | | |goto +offset | |9669, | 1773 | | | | | | | |Section| 1774 | | | | | | | |4.3 | 1775 | +------+-------+----+----+------------------------+--------+-------+ 1776 | |0x77 |0x0 |0 |any |dst >>= imm |base64 |RFC | 1777 | | | | | | | |9669, | 1778 | | | | | | | |Section| 1779 | | | | | | | |4.1 | 1780 | +------+-------+----+----+------------------------+--------+-------+ 1781 | |0x79 |any |any |0x00|dst = *(u64 *)(src + |base64 |RFC | 1782 | | | | | |offset) | |9669, | 1783 | | | | | | | |Section| 1784 | | | | | | | |5 | 1785 | +------+-------+----+----+------------------------+--------+-------+ 1786 | |0x7a |0x0 |any |any |*(u64 *)(dst + offset) =|base64 |RFC | 1787 | | | | | |imm | |9669, | 1788 | | | | | | | |Section| 1789 | | | | | | | |5 | 1790 | +------+-------+----+----+------------------------+--------+-------+ 1791 | |0x7b |any |any |0x00|*(u64 *)(dst + offset) =|base64 |RFC | 1792 | | | | | |src | |9669, | 1793 | | | | | | | |Section| 1794 | | | | | | | |5 | 1795 | +------+-------+----+----+------------------------+--------+-------+ 1796 | |0x7c |any |0 |0x00|dst = (u32)(dst >> src) |base32 |RFC | 1797 | | | | | | | |9669, | 1798 | | | | | | | |Section| 1799 | | | | | | | |4.1 | 1800 | +------+-------+----+----+------------------------+--------+-------+ 1801 | |0x7d |any |any |0x00|if dst s>= src goto |base64 |RFC | 1802 | | | | | |+offset | |9669, | 1803 | | | | | | | |Section| 1804 | | | | | | | |4.3 | 1805 | +------+-------+----+----+------------------------+--------+-------+ 1806 | |0x7e |any |any |0x00|if (s32)dst s>= (s32)src|base32 |RFC | 1807 | | | | | |goto +offset | |9669, | 1808 | | | | | | | |Section| 1809 | | | | | | | |4.3 | 1810 | +------+-------+----+----+------------------------+--------+-------+ 1811 | |0x7f |any |0 |0x00|dst >>= src |base64 |RFC | 1812 | | | | | | | |9669, | 1813 | | | | | | | |Section| 1814 | | | | | | | |4.1 | 1815 | +------+-------+----+----+------------------------+--------+-------+ 1816 | |0x84 |0x0 |0 |0x00|dst = (u32)-dst |base32 |RFC | 1817 | | | | | | | |9669, | 1818 | | | | | | | |Section| 1819 | | | | | | | |4.1 | 1820 | +------+-------+----+----+------------------------+--------+-------+ 1821 | |0x85 |0x0 |0 |any |call helper function by |base32 |RFC | 1822 | | | | | |static ID | |9669, | 1823 | | | | | | | |Section| 1824 | | | | | | | |4.3.1 | 1825 | +------+-------+----+----+------------------------+--------+-------+ 1826 | |0x85 |0x1 |0 |any |call PC += imm |base32 |RFC | 1827 | | | | | | | |9669, | 1828 | | | | | | | |Section| 1829 | | | | | | | |4.3.2 | 1830 | +------+-------+----+----+------------------------+--------+-------+ 1831 | |0x85 |0x2 |0 |any |call helper function by |base32 |RFC | 1832 | | | | | |BTF ID | |9669, | 1833 | | | | | | | |Section| 1834 | | | | | | | |4.3.1 | 1835 | +------+-------+----+----+------------------------+--------+-------+ 1836 | |0x87 |0x0 |0 |0x00|dst = -dst |base64 |RFC | 1837 | | | | | | | |9669, | 1838 | | | | | | | |Section| 1839 | | | | | | | |4.1 | 1840 | +------+-------+----+----+------------------------+--------+-------+ 1841 | |0x94 |0x0 |0 |any |dst = (u32)((imm != |divmul32|RFC | 1842 | | | | | |0)?((u32)dst % (u32)imm)| |9669, | 1843 | | | | | |: dst) | |Section| 1844 | | | | | | | |4.1 | 1845 | +------+-------+----+----+------------------------+--------+-------+ 1846 | |0x94 |0x0 |1 |any |dst = (u32)((imm != 0) ?|divmul32|RFC | 1847 | | | | | |((s32)dst s% imm) : dst)| |9669, | 1848 | | | | | | | |Section| 1849 | | | | | | | |4.1 | 1850 | +------+-------+----+----+------------------------+--------+-------+ 1851 | |0x95 |0x0 |0 |0x00|return |base32 |RFC | 1852 | | | | | | | |9669, | 1853 | | | | | | | |Section| 1854 | | | | | | | |4.3 | 1855 | +------+-------+----+----+------------------------+--------+-------+ 1856 | |0x97 |0x0 |0 |any |dst = (imm != 0) ? (dst |divmul64|RFC | 1857 | | | | | |% (u32)imm) : dst | |9669, | 1858 | | | | | | | |Section| 1859 | | | | | | | |4.1 | 1860 | +------+-------+----+----+------------------------+--------+-------+ 1861 | |0x97 |0x0 |1 |any |dst = (imm != 0) ? (dst |divmul64|RFC | 1862 | | | | | |s% imm) : dst | |9669, | 1863 | | | | | | | |Section| 1864 | | | | | | | |4.1 | 1865 | +------+-------+----+----+------------------------+--------+-------+ 1866 | |0x9c |any |0 |0x00|dst = (u32)((src != |divmul32|RFC | 1867 | | | | | |0)?((u32)dst % (u32)src)| |9669, | 1868 | | | | | |: dst) | |Section| 1869 | | | | | | | |4.1 | 1870 | +------+-------+----+----+------------------------+--------+-------+ 1871 | |0x9c |any |1 |0x00|dst = (u32)((src != |divmul32|RFC | 1872 | | | | | |0)?((s32)dst s% | |9669, | 1873 | | | | | |(s32)src) :dst) | |Section| 1874 | | | | | | | |4.1 | 1875 | +------+-------+----+----+------------------------+--------+-------+ 1876 | |0x9f |any |0 |0x00|dst = (src != 0) ? (dst |divmul64|RFC | 1877 | | | | | |% src) : dst | |9669, | 1878 | | | | | | | |Section| 1879 | | | | | | | |4.1 | 1880 | +------+-------+----+----+------------------------+--------+-------+ 1881 | |0x9f |any |1 |0x00|dst = (src != 0) ? (dst |divmul64|RFC | 1882 | | | | | |s% src) : dst | |9669, | 1883 | | | | | | | |Section| 1884 | | | | | | | |4.1 | 1885 | +------+-------+----+----+------------------------+--------+-------+ 1886 | |0xa4 |0x0 |0 |any |dst = (u32)(dst ^ imm) |base32 |RFC | 1887 | | | | | | | |9669, | 1888 | | | | | | | |Section| 1889 | | | | | | | |4.1 | 1890 | +------+-------+----+----+------------------------+--------+-------+ 1891 | |0xa5 |0x0 |any |any |if dst < imm goto |base64 |RFC | 1892 | | | | | |+offset | |9669, | 1893 | | | | | | | |Section| 1894 | | | | | | | |4.3 | 1895 | +------+-------+----+----+------------------------+--------+-------+ 1896 | |0xa6 |0x0 |any |any |if (u32)dst < imm goto |base32 |RFC | 1897 | | | | | |+offset | |9669, | 1898 | | | | | | | |Section| 1899 | | | | | | | |4.3 | 1900 | +------+-------+----+----+------------------------+--------+-------+ 1901 | |0xa7 |0x0 |0 |any |dst ^= imm |base64 |RFC | 1902 | | | | | | | |9669, | 1903 | | | | | | | |Section| 1904 | | | | | | | |4.1 | 1905 | +------+-------+----+----+------------------------+--------+-------+ 1906 | |0xac |any |0 |0x00|dst = (u32)(dst ^ src) |base32 |RFC | 1907 | | | | | | | |9669, | 1908 | | | | | | | |Section| 1909 | | | | | | | |4.1 | 1910 | +------+-------+----+----+------------------------+--------+-------+ 1911 | |0xad |any |any |0x00|if dst < src goto |base64 |RFC | 1912 | | | | | |+offset | |9669, | 1913 | | | | | | | |Section| 1914 | | | | | | | |4.3 | 1915 | +------+-------+----+----+------------------------+--------+-------+ 1916 | |0xae |any |any |0x00|if (u32)dst < (u32)src |base32 |RFC | 1917 | | | | | |goto +offset | |9669, | 1918 | | | | | | | |Section| 1919 | | | | | | | |4.3 | 1920 | +------+-------+----+----+------------------------+--------+-------+ 1921 | |0xaf |any |0 |0x00|dst ^= src |base64 |RFC | 1922 | | | | | | | |9669, | 1923 | | | | | | | |Section| 1924 | | | | | | | |4.1 | 1925 | +------+-------+----+----+------------------------+--------+-------+ 1926 | |0xb4 |0x0 |0 |any |dst = (u32) imm |base32 |RFC | 1927 | | | | | | | |9669, | 1928 | | | | | | | |Section| 1929 | | | | | | | |4.1 | 1930 | +------+-------+----+----+------------------------+--------+-------+ 1931 | |0xb5 |0x0 |any |any |if dst <= imm goto |base64 |RFC | 1932 | | | | | |+offset | |9669, | 1933 | | | | | | | |Section| 1934 | | | | | | | |4.3 | 1935 | +------+-------+----+----+------------------------+--------+-------+ 1936 | |0xb6 |0x0 |any |any |if (u32)dst <= imm goto |base32 |RFC | 1937 | | | | | |+offset | |9669, | 1938 | | | | | | | |Section| 1939 | | | | | | | |4.3 | 1940 | +------+-------+----+----+------------------------+--------+-------+ 1941 | |0xb7 |0x0 |0 |any |dst = imm |base64 |RFC | 1942 | | | | | | | |9669, | 1943 | | | | | | | |Section| 1944 | | | | | | | |4.1 | 1945 | +------+-------+----+----+------------------------+--------+-------+ 1946 | |0xbc |any |0 |0x00|dst = (u32) src |base32 |RFC | 1947 | | | | | | | |9669, | 1948 | | | | | | | |Section| 1949 | | | | | | | |4.1 | 1950 | +------+-------+----+----+------------------------+--------+-------+ 1951 | |0xbc |any |8 |0x00|dst = (u32) (s32) (s8) |base32 |RFC | 1952 | | | | | |src | |9669, | 1953 | | | | | | | |Section| 1954 | | | | | | | |4.1 | 1955 | +------+-------+----+----+------------------------+--------+-------+ 1956 | |0xbc |any |16 |0x00|dst = (u32) (s32) (s16) |base32 |RFC | 1957 | | | | | |src | |9669, | 1958 | | | | | | | |Section| 1959 | | | | | | | |4.1 | 1960 | +------+-------+----+----+------------------------+--------+-------+ 1961 | |0xbd |any |any |0x00|if dst <= src goto |base64 |RFC | 1962 | | | | | |+offset | |9669, | 1963 | | | | | | | |Section| 1964 | | | | | | | |4.3 | 1965 | +------+-------+----+----+------------------------+--------+-------+ 1966 | |0xbe |any |any |0x00|if (u32)dst <= (u32)src |base32 |RFC | 1967 | | | | | |goto +offset | |9669, | 1968 | | | | | | | |Section| 1969 | | | | | | | |4.3 | 1970 | +------+-------+----+----+------------------------+--------+-------+ 1971 | |0xbf |any |0 |0x00|dst = src |base64 |RFC | 1972 | | | | | | | |9669, | 1973 | | | | | | | |Section| 1974 | | | | | | | |4.1 | 1975 | +------+-------+----+----+------------------------+--------+-------+ 1976 | |0xbf |any |8 |0x00|dst = (s64) (s8) src |base64 |RFC | 1977 | | | | | | | |9669, | 1978 | | | | | | | |Section| 1979 | | | | | | | |4.1 | 1980 | +------+-------+----+----+------------------------+--------+-------+ 1981 | |0xbf |any |16 |0x00|dst = (s64) (s16) src |base64 |RFC | 1982 | | | | | | | |9669, | 1983 | | | | | | | |Section| 1984 | | | | | | | |4.1 | 1985 | +------+-------+----+----+------------------------+--------+-------+ 1986 | |0xbf |any |32 |0x00|dst = (s64) (s32) src |base64 |RFC | 1987 | | | | | | | |9669, | 1988 | | | | | | | |Section| 1989 | | | | | | | |4.1 | 1990 | +------+-------+----+----+------------------------+--------+-------+ 1991 | |0xc3 |any |any |0x00|lock *(u32 *)(dst + |atomic32|RFC | 1992 | | | | | |offset) += src | |9669, | 1993 | | | | | | | |Section| 1994 | | | | | | | |5.3 | 1995 | +------+-------+----+----+------------------------+--------+-------+ 1996 | |0xc3 |any |any |0x01|src = |atomic32|RFC | 1997 | | | | | |atomic_fetch_add_32((u32| |9669, | 1998 | | | | | |*)(dst + offset), src) | |Section| 1999 | | | | | | | |5.3 | 2000 | +------+-------+----+----+------------------------+--------+-------+ 2001 | |0xc3 |any |any |0x40|lock *(u32 *)(dst + |atomic32|RFC | 2002 | | | | | |offset) |= src | |9669, | 2003 | | | | | | | |Section| 2004 | | | | | | | |5.3 | 2005 | +------+-------+----+----+------------------------+--------+-------+ 2006 | |0xc3 |any |any |0x41|src = |atomic32|RFC | 2007 | | | | | |atomic_fetch_or_32((u32 | |9669, | 2008 | | | | | |*)(dst + offset), src) | |Section| 2009 | | | | | | | |5.3 | 2010 | +------+-------+----+----+------------------------+--------+-------+ 2011 | |0xc3 |any |any |0x50|lock *(u32 *)(dst + |atomic32|RFC | 2012 | | | | | |offset) &= src | |9669, | 2013 | | | | | | | |Section| 2014 | | | | | | | |5.3 | 2015 | +------+-------+----+----+------------------------+--------+-------+ 2016 | |0xc3 |any |any |0x51|src = |atomic32|RFC | 2017 | | | | | |atomic_fetch_and_32((u32| |9669, | 2018 | | | | | |*)(dst + offset), src) | |Section| 2019 | | | | | | | |5.3 | 2020 | +------+-------+----+----+------------------------+--------+-------+ 2021 | |0xc3 |any |any |0xa0|lock *(u32 *)(dst + |atomic32|RFC | 2022 | | | | | |offset) ^= src | |9669, | 2023 | | | | | | | |Section| 2024 | | | | | | | |5.3 | 2025 | +------+-------+----+----+------------------------+--------+-------+ 2026 | |0xc3 |any |any |0xa1|src = |atomic32|RFC | 2027 | | | | | |atomic_fetch_xor_32((u32| |9669, | 2028 | | | | | |*)(dst + offset), src) | |Section| 2029 | | | | | | | |5.3 | 2030 | +------+-------+----+----+------------------------+--------+-------+ 2031 | |0xc3 |any |any |0xe1|src = xchg_32((u32 |atomic32|RFC | 2032 | | | | | |*)(dst + offset), src) | |9669, | 2033 | | | | | | | |Section| 2034 | | | | | | | |5.3 | 2035 | +------+-------+----+----+------------------------+--------+-------+ 2036 | |0xc3 |any |any |0xf1|r0 = cmpxchg_32((u32 |atomic32|RFC | 2037 | | | | | |*)(dst + offset), r0, | |9669, | 2038 | | | | | |src) | |Section| 2039 | | | | | | | |5.3 | 2040 | +------+-------+----+----+------------------------+--------+-------+ 2041 | |0xc4 |0x0 |0 |any |dst = (u32)(dst s>> imm)|base32 |RFC | 2042 | | | | | | | |9669, | 2043 | | | | | | | |Section| 2044 | | | | | | | |4.1 | 2045 | +------+-------+----+----+------------------------+--------+-------+ 2046 | |0xc5 |0x0 |any |any |if dst s< imm goto |base64 |RFC | 2047 | | | | | |+offset | |9669, | 2048 | | | | | | | |Section| 2049 | | | | | | | |4.3 | 2050 | +------+-------+----+----+------------------------+--------+-------+ 2051 | |0xc6 |0x0 |any |any |if (s32)dst s< (s32)imm |base32 |RFC | 2052 | | | | | |goto +offset | |9669, | 2053 | | | | | | | |Section| 2054 | | | | | | | |4.3 | 2055 | +------+-------+----+----+------------------------+--------+-------+ 2056 | |0xc7 |0x0 |0 |any |dst s>>= imm |base64 |RFC | 2057 | | | | | | | |9669, | 2058 | | | | | | | |Section| 2059 | | | | | | | |4.1 | 2060 | +------+-------+----+----+------------------------+--------+-------+ 2061 | |0xcc |any |0 |0x00|dst = (u32)(dst s>> src)|base32 |RFC | 2062 | | | | | | | |9669, | 2063 | | | | | | | |Section| 2064 | | | | | | | |4.1 | 2065 | +------+-------+----+----+------------------------+--------+-------+ 2066 | |0xcd |any |any |0x00|if dst s< src goto |base64 |RFC | 2067 | | | | | |+offset | |9669, | 2068 | | | | | | | |Section| 2069 | | | | | | | |4.3 | 2070 | +------+-------+----+----+------------------------+--------+-------+ 2071 | |0xce |any |any |0x00|if (s32)dst s< (s32)src |base32 |RFC | 2072 | | | | | |goto +offset | |9669, | 2073 | | | | | | | |Section| 2074 | | | | | | | |4.3 | 2075 | +------+-------+----+----+------------------------+--------+-------+ 2076 | |0xcf |any |0 |0x00|dst s>>= src |base64 |RFC | 2077 | | | | | | | |9669, | 2078 | | | | | | | |Section| 2079 | | | | | | | |4.1 | 2080 | +------+-------+----+----+------------------------+--------+-------+ 2081 | |0xd4 |0x0 |0 |0x10|dst = htole16(dst) |base32 |RFC | 2082 | | | | | | | |9669, | 2083 | | | | | | | |Section| 2084 | | | | | | | |4.2 | 2085 | +------+-------+----+----+------------------------+--------+-------+ 2086 | |0xd4 |0x0 |0 |0x20|dst = htole32(dst) |base32 |RFC | 2087 | | | | | | | |9669, | 2088 | | | | | | | |Section| 2089 | | | | | | | |4.2 | 2090 | +------+-------+----+----+------------------------+--------+-------+ 2091 | |0xd4 |0x0 |0 |0x40|dst = htole64(dst) |base64 |RFC | 2092 | | | | | | | |9669, | 2093 | | | | | | | |Section| 2094 | | | | | | | |4.2 | 2095 | +------+-------+----+----+------------------------+--------+-------+ 2096 | |0xd5 |0x0 |any |any |if dst s<= imm goto |base64 |RFC | 2097 | | | | | |+offset | |9669, | 2098 | | | | | | | |Section| 2099 | | | | | | | |4.3 | 2100 | +------+-------+----+----+------------------------+--------+-------+ 2101 | |0xd6 |0x0 |any |any |if (s32)dst s<= (s32)imm|base32 |RFC | 2102 | | | | | |goto +offset | |9669, | 2103 | | | | | | | |Section| 2104 | | | | | | | |4.3 | 2105 | +------+-------+----+----+------------------------+--------+-------+ 2106 | |0xd7 |0x0 |0 |0x10|dst = bswap16(dst) |base32 |RFC | 2107 | | | | | | | |9669, | 2108 | | | | | | | |Section| 2109 | | | | | | | |4.2 | 2110 | +------+-------+----+----+------------------------+--------+-------+ 2111 | |0xd7 |0x0 |0 |0x20|dst = bswap32(dst) |base32 |RFC | 2112 | | | | | | | |9669, | 2113 | | | | | | | |Section| 2114 | | | | | | | |4.2 | 2115 | +------+-------+----+----+------------------------+--------+-------+ 2116 | |0xd7 |0x0 |0 |0x40|dst = bswap64(dst) |base64 |RFC | 2117 | | | | | | | |9669, | 2118 | | | | | | | |Section| 2119 | | | | | | | |4.2 | 2120 | +------+-------+----+----+------------------------+--------+-------+ 2121 | |0xdb |any |any |0x00|lock *(u64 *)(dst + |atomic64|RFC | 2122 | | | | | |offset) += src | |9669, | 2123 | | | | | | | |Section| 2124 | | | | | | | |5.3 | 2125 | +------+-------+----+----+------------------------+--------+-------+ 2126 | |0xdb |any |any |0x01|src = |atomic64|RFC | 2127 | | | | | |atomic_fetch_add_64((u64| |9669, | 2128 | | | | | |*)(dst + offset), src) | |Section| 2129 | | | | | | | |5.3 | 2130 | +------+-------+----+----+------------------------+--------+-------+ 2131 | |0xdb |any |any |0x40|lock *(u64 *)(dst + |atomic64|RFC | 2132 | | | | | |offset) |= src | |9669, | 2133 | | | | | | | |Section| 2134 | | | | | | | |5.3 | 2135 | +------+-------+----+----+------------------------+--------+-------+ 2136 | |0xdb |any |any |0x41|src = |atomic64|RFC | 2137 | | | | | |atomic_fetch_or_64((u64 | |9669, | 2138 | | | | | |*)(dst + offset), src) | |Section| 2139 | | | | | | | |5.3 | 2140 | +------+-------+----+----+------------------------+--------+-------+ 2141 | |0xdb |any |any |0x50|lock *(u64 *)(dst + |atomic64|RFC | 2142 | | | | | |offset) &= src | |9669, | 2143 | | | | | | | |Section| 2144 | | | | | | | |5.3 | 2145 | +------+-------+----+----+------------------------+--------+-------+ 2146 | |0xdb |any |any |0x51|src = |atomic64|RFC | 2147 | | | | | |atomic_fetch_and_64((u64| |9669, | 2148 | | | | | |*)(dst + offset), src) | |Section| 2149 | | | | | | | |5.3 | 2150 | +------+-------+----+----+------------------------+--------+-------+ 2151 | |0xdb |any |any |0xa0|lock *(u64 *)(dst + |atomic64|RFC | 2152 | | | | | |offset) ^= src | |9669, | 2153 | | | | | | | |Section| 2154 | | | | | | | |5.3 | 2155 | +------+-------+----+----+------------------------+--------+-------+ 2156 | |0xdb |any |any |0xa1|src = |atomic64|RFC | 2157 | | | | | |atomic_fetch_xor_64((u64| |9669, | 2158 | | | | | |*)(dst + offset), src) | |Section| 2159 | | | | | | | |5.3 | 2160 | +------+-------+----+----+------------------------+--------+-------+ 2161 | |0xdb |any |any |0xe1|src = xchg_64((u64 |atomic64|RFC | 2162 | | | | | |*)(dst + offset), src) | |9669, | 2163 | | | | | | | |Section| 2164 | | | | | | | |5.3 | 2165 | +------+-------+----+----+------------------------+--------+-------+ 2166 | |0xdb |any |any |0xf1|r0 = cmpxchg_64((u64 |atomic64|RFC | 2167 | | | | | |*)(dst + offset), r0, | |9669, | 2168 | | | | | |src) | |Section| 2169 | | | | | | | |5.3 | 2170 | +------+-------+----+----+------------------------+--------+-------+ 2171 | |0xdc |0x0 |0 |0x10|dst = htobe16(dst) |base32 |RFC | 2172 | | | | | | | |9669, | 2173 | | | | | | | |Section| 2174 | | | | | | | |4.2 | 2175 | +------+-------+----+----+------------------------+--------+-------+ 2176 | |0xdc |0x0 |0 |0x20|dst = htobe32(dst) |base32 |RFC | 2177 | | | | | | | |9669, | 2178 | | | | | | | |Section| 2179 | | | | | | | |4.2 | 2180 | +------+-------+----+----+------------------------+--------+-------+ 2181 | |0xdc |0x0 |0 |0x40|dst = htobe64(dst) |base64 |RFC | 2182 | | | | | | | |9669, | 2183 | | | | | | | |Section| 2184 | | | | | | | |4.2 | 2185 | +------+-------+----+----+------------------------+--------+-------+ 2186 | |0xdd |any |any |0x00|if dst s<= src goto |base64 |RFC | 2187 | | | | | |+offset | |9669, | 2188 | | | | | | | |Section| 2189 | | | | | | | |4.3 | 2190 | +------+-------+----+----+------------------------+--------+-------+ 2191 | |0xde |any |any |0x00|if (s32)dst s<= (s32)src|base32 |RFC | 2192 | | | | | |goto +offset | |9669, | 2193 | | | | | | | |Section| 2194 | | | | | | | |4.3 | 2195 | +------+-------+----+----+------------------------+--------+-------+ 2196 | 2197 | Table 18: Initial BPF Instruction Set Values 2198 | 2199 | Acknowledgements 2200 | 2201 | This document was generated from instruction-set.rst in the Linux 2202 | kernel repository, to which a number of other individuals have 2203 | authored contributions over time, including Akhil Raj, Alexei 2204 | Starovoitov, Brendan Jackman, Christoph Hellwig, Daniel Borkmann, 2205 | Ilya Leoshkevich, Jiong Wang, Jose E. Marchesi, Kosuke Fujimoto, 2206 | Shahab Vahedi, Tiezhu Yang, Will Hawkins, and Zheng Yejian, with 2207 | review and suggestions by many others including Alan Jowett, Andrii 2208 | Nakryiko, David Vernet, Jim Harris, Quentin Monnet, Song Liu, Shung- 2209 | Hsi Yu, Stanislav Fomichev, Watson Ladd, and Yonghong Song. 2210 | 2211 | Author's Address 2212 | 2213 | Dave Thaler (editor) 2214 | Redmond, WA 98052 2215 | United States of America 2216 | Email: dave.thaler.ietf@gmail.com 2217 | -------------------------------------------------------------------------------- /src/Instruction.zig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattnite/bpf/22616861d8b1a51381d31a9c7cc43a223ce51981/src/Instruction.zig -------------------------------------------------------------------------------- /src/VM.zig: -------------------------------------------------------------------------------- 1 | gpa: Allocator, 2 | pc: u32, 3 | r: [11]u64 = undefined, 4 | stack: [512]u8 = undefined, 5 | instructions: std.ArrayListUnmanaged(Instruction) = .{}, 6 | 7 | pub fn init(allocator: Allocator) VM { 8 | var ret = VM{ 9 | .gpa = allocator, 10 | .pc = 0, 11 | }; 12 | 13 | ret.reset(); 14 | return ret; 15 | } 16 | 17 | pub fn deinit(vm: *VM) void { 18 | vm.instructions.deinit(vm.gpa); 19 | } 20 | 21 | pub fn reset(vm: *VM) void { 22 | vm.pc = 0; 23 | @memset(&vm.r, 0); 24 | @memset(&vm.stack, 0); 25 | vm.instructions.clearRetainingCapacity(); 26 | } 27 | 28 | /// Load program into VM. Clears existing state. 29 | pub fn load(vm: *VM, endian: Endian, instructions: []const u64) !void { 30 | vm.reset(); 31 | 32 | for (instructions) |insn| 33 | try vm.instructions.append(vm.gpa, Instruction.parse(endian, insn)); 34 | } 35 | 36 | pub const Fault = error{ InvalidInstruction, TODO }; 37 | 38 | fn sign_extend(comptime Dst: type, comptime Src: type, src: Src) Dst { 39 | //Sign Extend: To sign extend an X-bit number, A, to a Y-bit number, 40 | // B, means to 41 | // 42 | // 1. Copy all X bits from A to the lower X bits of B. 43 | // 2. Set the value of the remaining Y - X bits of B to the value of 44 | // the most significant bit of A. 45 | 46 | const dst_info = @typeInfo(Dst); 47 | const src_info = @typeInfo(Src); 48 | 49 | comptime { 50 | assert(dst_info.int.signedness == .unsigned); 51 | assert(src_info.int.signedness == .signed); 52 | assert(dst_info.int.bits > src_info.int.bits); 53 | } 54 | 55 | _ = src; 56 | assert(false); // TODO 57 | } 58 | 59 | fn do_alu64(code: ArithmeticCode, dst: *u64, src: u64, offset: u16) !void { 60 | switch (code) { 61 | .ADD => dst.* +%= src, 62 | .SUB => dst.* -%= src, 63 | .MUL => dst.* *%= src, 64 | .DIV => dst.* = if (offset == 0) 65 | if (src != 0) dst.* / src else 0 66 | else 67 | // SDIV 68 | return error.TODO, 69 | .OR => dst.* |= src, 70 | .AND => dst.* &= src, 71 | .LSH => dst.* <<= @as(u6, @truncate(src)), 72 | .RSH => dst.* >>= @as(u6, @truncate(src)), 73 | .NEG => return error.TODO, //dst.* = @bitCast(-@as(i64, @bitCast(src))), 74 | .XOR => dst.* ^= src, 75 | .MOD => if (offset == 0) 76 | return error.TODO 77 | else 78 | // SMOD 79 | return error.TODO, 80 | .MOV => if (offset == 0) { 81 | dst.* = src; 82 | } else 83 | // MOVSX 84 | return error.TODO, 85 | .END => return error.TODO, 86 | .ARSH => return error.TODO, 87 | _ => return error.InvalidInstruction, 88 | } 89 | } 90 | 91 | fn do_alu(code: ArithmeticCode, dst: *u64, src: u32) !void { 92 | _ = dst; 93 | _ = src; 94 | switch (code) { 95 | else => { 96 | std.log.err("ALU code: {}", .{code}); 97 | return error.TODO; 98 | }, 99 | } 100 | } 101 | 102 | /// Execute a single instruction. If the program has exited, it will return the 103 | /// exit code, otherwise null. A fault error is returned if an instruction does 104 | /// anything illegal. 105 | pub fn step(vm: *VM) Fault!?c_int { 106 | const next = vm.instructions.items[vm.pc]; 107 | 108 | switch (next.opcode.class) { 109 | .ALU64 => { 110 | const src = &vm.r[next.regs.src]; 111 | const dst = &vm.r[next.regs.dst]; 112 | switch (next.opcode.specific.arithmetic.source) { 113 | // K means use 32-bit imm value as source operand 114 | .K => try do_alu64(next.opcode.specific.arithmetic.code, dst, next.imm, next.offset), 115 | .X => try do_alu64(next.opcode.specific.arithmetic.code, dst, src.*, next.offset), 116 | } 117 | 118 | vm.pc += 1; 119 | }, 120 | .ALU => { 121 | const src = &vm.r[next.regs.src]; 122 | const dst = &vm.r[next.regs.dst]; 123 | switch (next.opcode.specific.arithmetic.source) { 124 | // K means use 32-bit imm value as source operand 125 | .K => try do_alu(next.opcode.specific.arithmetic.code, dst, next.imm), 126 | .X => try do_alu(next.opcode.specific.arithmetic.code, dst, @truncate(src.*)), 127 | } 128 | 129 | vm.pc += 1; 130 | }, 131 | .JMP => switch (next.opcode.specific.jump.code) { 132 | .EXIT => { 133 | if (next.opcode.specific.jump.source != .K) 134 | return error.InvalidInstruction; 135 | 136 | return @bitCast(@as(c_uint, @truncate(vm.r[0]))); 137 | }, 138 | else => |code| { 139 | std.log.err("JMP code: {}", .{code}); 140 | return error.TODO; 141 | }, 142 | }, 143 | else => |class| { 144 | std.log.err("class: {}", .{class}); 145 | return error.TODO; 146 | }, 147 | } 148 | 149 | return null; 150 | } 151 | 152 | test "return 1" { 153 | var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 154 | defer arena.deinit(); 155 | 156 | inline for (&.{ insn_test.el, insn_test.eb }, &.{ .little, .big }) |examples, endian| { 157 | const program = try insn_test.load_program(arena.allocator(), @field(examples, "return_one")); 158 | 159 | var vm = VM.init(arena.allocator()); 160 | try vm.load(endian, program); 161 | 162 | while (true) { 163 | if (try vm.step()) |return_code| { 164 | try std.testing.expectEqual(1, return_code); 165 | break; 166 | } 167 | } 168 | } 169 | } 170 | 171 | test "step.alu64.k.mov" { 172 | var vm = VM.init(std.testing.allocator); 173 | defer vm.deinit(); 174 | 175 | vm.reset(); 176 | vm.r[2] = 2; 177 | vm.r[3] = 3; 178 | try vm.instructions.append(vm.gpa, .{ 179 | .opcode = .{ 180 | .class = .ALU64, 181 | .specific = .{ 182 | .arithmetic = .{ 183 | .source = .X, 184 | .code = .ADD, 185 | }, 186 | }, 187 | }, 188 | .regs = .{ 189 | .src = 3, 190 | .dst = 2, 191 | }, 192 | .offset = 0, 193 | .imm = 0, 194 | }); 195 | 196 | _ = try vm.step(); 197 | 198 | try std.testing.expectEqual(5, vm.r[2]); 199 | } 200 | 201 | test "all" { 202 | _ = @import("insn.zig"); 203 | } 204 | 205 | const VM = @This(); 206 | const std = @import("std"); 207 | const Allocator = std.mem.Allocator; 208 | const Endian = std.builtin.Endian; 209 | const assert = std.debug.assert; 210 | 211 | const Instruction = @import("insn.zig").Instruction; 212 | const ArithmeticCode = @import("insn.zig").ArithmeticCode; 213 | 214 | const insn_test = @import("insn_test.zig"); 215 | 216 | const insn_execute_max = 1_000_000; 217 | -------------------------------------------------------------------------------- /src/insn.zig: -------------------------------------------------------------------------------- 1 | pub const Instruction = packed struct(u64) { 2 | opcode: packed struct(u8) { 3 | class: Class, 4 | specific: packed union { 5 | arithmetic: packed struct(u5) { 6 | source: Source, 7 | code: ArithmeticCode, 8 | }, 9 | jump: packed struct(u5) { 10 | source: Source, 11 | code: JumpCode, 12 | }, 13 | jump32: packed struct(u5) { 14 | source: Source, 15 | code: Jump32Code, 16 | }, 17 | load_and_store: packed struct(u5) { 18 | sz: LoadStoreSize, 19 | mode: LoadStoreMode, 20 | }, 21 | }, 22 | }, 23 | regs: packed struct(u8) { 24 | src: u4, 25 | dst: u4, 26 | }, 27 | offset: u16, 28 | imm: u32, 29 | 30 | /// This function normalizes instructions given a raw little or big endian 31 | /// instruction. 32 | /// 33 | /// Fields that need byte swapping will be swapped. For whatever reason the 34 | /// little and big endian variants of BPF swap the source and destination 35 | /// register fields despite being contained within a byte boundary. This 36 | /// function fixes that. 37 | pub fn parse(endian: Endian, insn: u64) Instruction { 38 | const opcode: u8 = @truncate(insn); 39 | const reg1: u4 = @truncate(insn >> 8); 40 | const reg2: u4 = @truncate(insn >> 12); 41 | const offset: u16 = @truncate(insn >> 16); 42 | const imm: u32 = @truncate(insn >> 32); 43 | 44 | const class: u3 = @truncate(opcode); 45 | const specific: u5 = @truncate(opcode >> 3); 46 | 47 | return Instruction{ 48 | .opcode = .{ 49 | .class = @enumFromInt(class), 50 | .specific = @bitCast(specific), 51 | }, 52 | .regs = switch (endian) { 53 | .little => .{ 54 | .src = reg1, 55 | .dst = reg2, 56 | }, 57 | .big => .{ 58 | .src = reg2, 59 | .dst = reg1, 60 | }, 61 | }, 62 | .offset = fix_endian(u16, endian, offset), 63 | .imm = fix_endian(u32, endian, imm), 64 | }; 65 | } 66 | 67 | fn fix_endian(comptime T: type, runtime: Endian, value: T) T { 68 | return if (runtime == @import("builtin").cpu.arch.endian()) 69 | value 70 | else 71 | @byteSwap(value); 72 | } 73 | 74 | pub fn disassemble(instruction: *const Instruction, writer: anytype) !void { 75 | errdefer { 76 | var buf: [4096]u8 = undefined; 77 | const message = std.fmt.bufPrint(&buf, "Failed to disassemble instruction: {}", .{instruction}) catch unreachable; 78 | @panic(message); 79 | } 80 | 81 | switch (instruction.opcode.class) { 82 | .LD, 83 | .LDX, 84 | .ST, 85 | .STX, 86 | .ALU, 87 | .JMP, 88 | .JMP32, 89 | => return error.TODO, 90 | .ALU64 => switch (instruction.opcode.specific.arithmetic.source) { 91 | .X => return error.TODO, 92 | .K => switch (instruction.opcode.specific.arithmetic.code) { 93 | .MOV => try writer.print("r{} = {}", .{ instruction.regs.dst, instruction.imm }), 94 | else => return error.TODO, 95 | }, 96 | }, 97 | } 98 | } 99 | 100 | pub fn format( 101 | instruction: Instruction, 102 | comptime _: []const u8, 103 | _: std.fmt.FormatOptions, 104 | writer: anytype, 105 | ) !void { 106 | try writer.print("class={}", .{instruction.opcode.class}); 107 | switch (instruction.opcode.class) { 108 | .LD, .LDX, .ST, .STX => { 109 | const l = instruction.opcode.specific.load_and_store; 110 | try writer.print(" sz={} mode={}", .{ l.sz, l.mode }); 111 | }, 112 | .ALU, .ALU64 => { 113 | const a = instruction.opcode.specific.arithmetic; 114 | try writer.print(" source={} code={}", .{ a.source, a.code }); 115 | }, 116 | .JMP => { 117 | const j = instruction.opcode.specific.jump; 118 | try writer.print(" source={} code={}", .{ j.source, j.code }); 119 | }, 120 | .JMP32 => { 121 | const j = instruction.opcode.specific.jump; 122 | try writer.print(" source={} code={}", .{ j.source, j.code }); 123 | }, 124 | } 125 | 126 | try writer.print(" dst_reg={} src_reg={} offset=0x{X} imm={}", .{ 127 | instruction.regs.dst, 128 | instruction.regs.src, 129 | instruction.offset, 130 | instruction.imm, 131 | }); 132 | } 133 | }; 134 | 135 | pub const LoadStoreSize = enum(u2) { 136 | /// Word (4-bytes) 137 | W = 0, 138 | /// Half-word (2-bytes) 139 | H = 1, 140 | /// Byte 141 | B = 2, 142 | /// Double-word (8-bytes) 143 | DW = 3, 144 | }; 145 | 146 | pub const LoadStoreMode = enum(u3) { 147 | /// 64-bit immediate instructions 148 | IMM = 0, 149 | /// Legacy BPF packet access (absolute) 150 | ABS = 1, 151 | /// Legacy BPF packet access (indirect) 152 | IND = 2, 153 | /// Regular load and store operations 154 | MEM = 3, 155 | /// Sign-extension load and store operations 156 | MEMSX = 4, 157 | /// Atomic operations 158 | ATOMIC = 6, 159 | _, 160 | }; 161 | 162 | pub const Source = enum(u1) { 163 | /// use 32-bit 'imm' value as source operand 164 | K = 0, 165 | /// use 'src_reg' register value as source operand 166 | X = 1, 167 | }; 168 | 169 | // The byte swap instructions use instruction classes of ALU and ALU64 and a 170 | // 4-bit 'code' field of END. 171 | // 172 | // The byte swap instructions operate on the destination register only and do 173 | // not use a separate source register or immediate value. 174 | // 175 | // For ALU, the 1-bit source operand field in the opcode is used to select what 176 | // byte order the operation converts from or to. For ALU64, the 1-bit source 177 | // operand field in the opcode is reserved and MUST be set to 0. 178 | pub const ByteSwapSource = enum(u1) { 179 | /// Convert between host byte order and little endian 180 | LE = 0, 181 | /// Convert between host byte order and big endian 182 | BE = 1, 183 | }; 184 | 185 | pub const Class = enum(u3) { 186 | /// Non-standard load operations 187 | LD = 0x0, 188 | /// Load into register operations 189 | LDX = 0x1, 190 | /// Store from immediate operations 191 | ST = 0x2, 192 | /// Store from register operations 193 | STX = 0x3, 194 | /// 32-bit arithmetic operations 195 | ALU = 0x4, 196 | /// 64-bit jump operations 197 | JMP = 0x5, 198 | /// 32-bit jump operations 199 | JMP32 = 0x6, 200 | /// 64-bit arithmetic operations 201 | ALU64 = 0x7, 202 | }; 203 | 204 | pub const JumpCode = enum(u4) { 205 | /// PC += offset 206 | JA = 0x0, 207 | /// PC += offset if dst == src 208 | JEQ = 0x1, 209 | /// PC += offset if dst > src 210 | JGT = 0x2, 211 | /// PC += offset if dst >= src 212 | JGE = 0x3, 213 | /// PC += offset if dst & src 214 | JSET = 0x4, 215 | /// PC += offset if dst != src 216 | JNE = 0x5, 217 | /// PC += offset if dst > src 218 | JSGT = 0x6, 219 | /// PC += offset if dst >= src 220 | JSGE = 0x7, 221 | 222 | // For given src_reg values: 223 | // 224 | // 0: Call helper function by static ID 225 | // 1: Call PC += imm 226 | // 2: Call helper function by BTF ID 227 | CALL = 0x8, 228 | EXIT = 0x9, 229 | /// PC += offset if dst < src 230 | JLT = 0xA, 231 | /// PC += offset if dst <= src 232 | JLE = 0xB, 233 | /// PC += offset if dst < src 234 | JSLT = 0xC, 235 | /// PC += offset if dst <= src 236 | JSLE = 0xD, 237 | _, 238 | }; 239 | 240 | pub const Jump32Code = 241 | enum(u4) { 242 | /// PC += imm 243 | JA = 0x0, 244 | /// PC += offset if dst == src 245 | JEQ = 0x1, 246 | /// PC += offset if dst > src 247 | JGT = 0x2, 248 | /// PC += offset if dst >= src 249 | JGE = 0x3, 250 | /// PC += offset if dst & src 251 | JSET = 0x4, 252 | /// PC += offset if dst != src 253 | JNE = 0x5, 254 | /// PC += offset if dst > src 255 | JSGT = 0x6, 256 | /// PC += offset if dst >= src 257 | JSGE = 0x7, 258 | /// PC += offset if dst < src 259 | JLT = 0xA, 260 | /// PC += offset if dst <= src 261 | JLE = 0xB, 262 | /// PC += offset if dst < src 263 | JSLT = 0xC, 264 | /// PC += offset if dst <= src 265 | JSLE = 0xD, 266 | _, 267 | }; 268 | 269 | pub const ArithmeticCode = enum(u4) { 270 | /// dst += src 271 | ADD = 0x0, 272 | /// dst -= src 273 | SUB = 0x1, 274 | /// dst *= src 275 | MUL = 0x2, 276 | /// dst = (src != 0) ? (dst / src) : 0 277 | /// TODO: there is SDIV too, it uses offset 278 | DIV = 0x3, 279 | /// dst |= src 280 | OR = 0x4, 281 | /// dst &= src 282 | AND = 0x5, 283 | /// dst <<= (src & mask) 284 | LSH = 0x6, 285 | /// dst >>= (src & mask) 286 | RSH = 0x7, 287 | /// dst = -dst 288 | NEG = 0x8, 289 | /// dst = (src != 0) ? (dst % src) : 0 290 | /// TODO: there is SMOD too, it uses offset 291 | MOD = 0x9, 292 | /// dst ^= src 293 | XOR = 0xA, 294 | /// dst = src 295 | /// TODO: there is sign extending MOV too dst = (s8/s16/s32)src 296 | MOV = 0xB, 297 | /// Sign extending dst >>= (src & mask) 298 | ARSH = 0xC, 299 | /// Byte swap operations 300 | END = 0xD, 301 | _, 302 | }; 303 | 304 | const std = @import("std"); 305 | const Endian = std.builtin.Endian; 306 | -------------------------------------------------------------------------------- /src/insn/examples.bpf.zig: -------------------------------------------------------------------------------- 1 | export fn load() callconv(.Naked) void { 2 | asm volatile ( 3 | \\ r1 = 0x1 4 | ); 5 | } 6 | 7 | export fn return_one(_: ?*anyopaque) callconv(.C) c_int { 8 | return 1; 9 | } 10 | -------------------------------------------------------------------------------- /src/insn_test.zig: -------------------------------------------------------------------------------- 1 | test "serialization" { 2 | try instruction_test("load", .{ 3 | .opcode = .{ 4 | .class = .ALU64, 5 | .specific = .{ 6 | .arithmetic = .{ 7 | .source = .K, 8 | .code = .MOV, 9 | }, 10 | }, 11 | }, 12 | .regs = .{ .src = 1, .dst = 0 }, 13 | .offset = 0, 14 | .imm = 1, 15 | }); 16 | } 17 | 18 | test "disassemble.alu64.k.mov" { 19 | try disassemble_test( 20 | \\r3 = 1 21 | , .{ 22 | .opcode = .{ 23 | .class = .ALU64, 24 | .specific = .{ 25 | .arithmetic = .{ 26 | .source = .K, 27 | .code = .MOV, 28 | }, 29 | }, 30 | }, 31 | .regs = .{ 32 | .src = 0, 33 | .dst = 3, 34 | }, 35 | .offset = 0, 36 | .imm = 1, 37 | }); 38 | } 39 | 40 | fn disassemble_test(expected: []const u8, insn: Instruction) !void { 41 | var out = std.ArrayList(u8).init(std.testing.allocator); 42 | defer out.deinit(); 43 | 44 | try insn.disassemble(out.writer()); 45 | try std.testing.expectEqualStrings(expected, out.items); 46 | } 47 | 48 | fn instruction_test(comptime program_name: []const u8, expected: Instruction) !void { 49 | var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 50 | defer arena.deinit(); 51 | 52 | inline for (&.{ el, eb }, &.{ .little, .big }) |examples, endian| { 53 | const program = try load_program(arena.allocator(), @field(examples, program_name)); 54 | try std.testing.expectEqual(1, program.len); 55 | 56 | expect_instruction(expected, Instruction.parse(endian, program[0])) catch |err| { 57 | if (endian == .little) 58 | std.log.err("Little endian failed", .{}) 59 | else 60 | std.log.err("Big endian failed", .{}); 61 | 62 | std.log.err("0x{X:0>16}", .{program[0]}); 63 | 64 | return err; 65 | }; 66 | } 67 | } 68 | 69 | const expect_equal = std.testing.expectEqual; 70 | 71 | fn expect_instruction(expected: Instruction, actual: Instruction) !void { 72 | try expect_equal(expected.opcode.class, actual.opcode.class); 73 | switch (expected.opcode.class) { 74 | .ALU, .ALU64 => { 75 | try expect_equal(expected.opcode.specific.arithmetic.source, actual.opcode.specific.arithmetic.source); 76 | try expect_equal(expected.opcode.specific.arithmetic.code, actual.opcode.specific.arithmetic.code); 77 | }, 78 | .JMP => { 79 | try expect_equal(expected.opcode.specific.jump.source, actual.opcode.specific.jump.source); 80 | try expect_equal(expected.opcode.specific.jump.code, actual.opcode.specific.jump.code); 81 | }, 82 | .JMP32 => { 83 | try expect_equal(expected.opcode.specific.jump32.source, actual.opcode.specific.jump32.source); 84 | try expect_equal(expected.opcode.specific.jump32.code, actual.opcode.specific.jump32.code); 85 | }, 86 | .LD, .LDX, .ST, .STX => { 87 | try expect_equal(expected.opcode.specific.load_and_store.sz, actual.opcode.specific.load_and_store.sz); 88 | try expect_equal(expected.opcode.specific.load_and_store.mode, actual.opcode.specific.load_and_store.mode); 89 | }, 90 | } 91 | 92 | try std.testing.expectEqual(expected.regs.src, actual.regs.src); 93 | try std.testing.expectEqual(expected.regs.dst, actual.regs.dst); 94 | try std.testing.expectEqual(expected.offset, actual.offset); 95 | try std.testing.expectEqual(expected.imm, actual.imm); 96 | } 97 | 98 | const std = @import("std"); 99 | const Instruction = @import("insn.zig").Instruction; 100 | 101 | const Examples = OptionsToStruct(@import("examples-el")); 102 | pub const el = AssignOptions(Examples, @import("examples-el")); 103 | pub const eb = AssignOptions(Examples, @import("examples-eb")); 104 | 105 | fn OptionsToStruct(comptime ns: type) type { 106 | const ti = @typeInfo(ns).@"struct"; 107 | var fields: [ti.decls.len]std.builtin.Type.StructField = undefined; 108 | 109 | inline for (ti.decls, &fields) |decl, *field| { 110 | field.* = std.builtin.Type.StructField{ 111 | .name = decl.name, 112 | .type = []const u8, 113 | .alignment = @alignOf([]const u8), 114 | .default_value_ptr = null, 115 | .is_comptime = false, 116 | }; 117 | } 118 | 119 | const t = std.builtin.Type{ 120 | .@"struct" = .{ 121 | .backing_integer = null, 122 | .decls = &.{}, 123 | .fields = &fields, 124 | .is_tuple = false, 125 | .layout = .auto, 126 | }, 127 | }; 128 | 129 | return @Type(t); 130 | } 131 | 132 | fn AssignOptions(comptime T: type, comptime ns: type) T { 133 | const ti = @typeInfo(T).@"struct"; 134 | const ns_ti = @typeInfo(ns).@"struct"; 135 | 136 | var ret: T = undefined; 137 | inline for (ti.fields, ns_ti.decls) |field, decl| { 138 | std.debug.assert(std.mem.eql(u8, field.name, decl.name)); 139 | @field(ret, field.name) = @field(ns, decl.name); 140 | } 141 | 142 | return ret; 143 | } 144 | 145 | pub fn load_program(allocator: std.mem.Allocator, path: []const u8) ![]const u64 { 146 | const bytes = try std.fs.cwd().readFileAlloc(allocator, path, 100 * 1024); 147 | return @alignCast(std.mem.bytesAsSlice(u64, bytes)); 148 | } 149 | -------------------------------------------------------------------------------- /src/kern.zig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattnite/bpf/22616861d8b1a51381d31a9c7cc43a223ce51981/src/kern.zig -------------------------------------------------------------------------------- /src/main.zig: -------------------------------------------------------------------------------- 1 | pub fn main() !void { 2 | std.debug.print("All your {s} are belong to us.\n", .{"codebase"}); 3 | 4 | const stdout_file = std.io.getStdOut().writer(); 5 | var bw = std.io.bufferedWriter(stdout_file); 6 | const stdout = bw.writer(); 7 | 8 | try stdout.print("Run `zig build test` to run the tests.\n", .{}); 9 | 10 | try bw.flush(); // Don't forget to flush! 11 | } 12 | 13 | test "simple test" { 14 | var list = std.ArrayList(i32).init(std.testing.allocator); 15 | defer list.deinit(); // Try commenting this out and see if zig detects the memory leak! 16 | try list.append(42); 17 | try std.testing.expectEqual(@as(i32, 42), list.pop()); 18 | } 19 | 20 | test "use other module" { 21 | try std.testing.expectEqual(@as(i32, 150), lib.add(100, 50)); 22 | } 23 | 24 | test "fuzz example" { 25 | const global = struct { 26 | fn testOne(input: []const u8) anyerror!void { 27 | // Try passing `--fuzz` to `zig build test` and see if it manages to fail this test case! 28 | try std.testing.expect(!std.mem.eql(u8, "canyoufindme", input)); 29 | } 30 | }; 31 | try std.testing.fuzz(global.testOne, .{}); 32 | } 33 | 34 | const std = @import("std"); 35 | 36 | /// This imports the separate module containing `root.zig`. Take a look in `build.zig` for details. 37 | const lib = @import("bpf_lib"); 38 | -------------------------------------------------------------------------------- /src/root.zig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattnite/bpf/22616861d8b1a51381d31a9c7cc43a223ce51981/src/root.zig -------------------------------------------------------------------------------- /src/user.zig: -------------------------------------------------------------------------------- 1 | const VM = @import("user/VM.zig"); 2 | --------------------------------------------------------------------------------