From 7b3d3b48d60800ddcda61de480db00ad92bf111c Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Thu, 22 Sep 2022 14:15:45 -0700 Subject: [PATCH 01/25] Add more links to ISA readme Signed-off-by: Dave Thaler --- isa/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/isa/README.md b/isa/README.md index 98c49da..6c96c4e 100644 --- a/isa/README.md +++ b/isa/README.md @@ -15,3 +15,5 @@ Some implementation links include: * https://github.com/generic-ebpf/generic-ebpf/blob/dev/sys/sys/ebpf_vm_isa.h * https://github.com/vbpf/ebpf-verifier/blob/main/src/ebpf_vm_isa.hpp * https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/bpf.h +* https://lore.kernel.org/bpf/8DA9E260-AE56-4B21-90BF-CF0049CFD04D@intel.com/ +* https://github.com/iovisor/bpf-docs/pull/26/files From 71c9076c4625654ec1d7d6c0e983f97a2d221b79 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Mon, 29 Aug 2022 12:04:06 -0700 Subject: [PATCH 02/25] Update ISA documentation * Add section numbers * Add glossary formatting for fields * Use consistent field names * Add appendix with opcode table * Add ISA version information * Add text about underflow, overflow, and division by zero * Add other text based on info in other documents Signed-off-by: Dave Thaler --- isa/README.md | 2 + isa/kernel.org/instruction-set.rst | 765 +++++++++++++++++++++-------- 2 files changed, 560 insertions(+), 207 deletions(-) diff --git a/isa/README.md b/isa/README.md index 6c96c4e..b220048 100644 --- a/isa/README.md +++ b/isa/README.md @@ -8,6 +8,8 @@ Some documentation links include: * https://www.kernel.org/doc/Documentation/networking/filter.txt * https://pchaigno.github.io/bpf/2021/10/20/ebpf-instruction-sets.html * https://www.kernel.org/doc/html/latest/bpf/bpf_design_QA.html#instruction-level-questions +* https://lore.kernel.org/bpf/8DA9E260-AE56-4B21-90BF-CF0049CFD04D@intel.com/ +* https://github.com/iovisor/bpf-docs/pull/26/files Some implementation links include: diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index 1b0e671..7f8ee00 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -1,8 +1,24 @@ +.. contents:: +.. sectnum:: ==================== eBPF Instruction Set ==================== +The eBPF instruction set consists of eleven 64 bit registers, a program counter, +and 512 bytes of stack space. + +Versions +======== + +The current Instruction Set Architecture (ISA) version, sometimes referred to in other documents +as a "CPU" version, is 3. This document also covers older versions of the ISA. + + **Note** + + *Clang implementation*: Clang can select the eBPF ISA version using + ``-mcpu=v2`` for example to select version 2. + Registers and calling convention ================================ @@ -11,198 +27,331 @@ all of which are 64-bits wide. The eBPF calling convention is defined as: - * R0: return value from function calls, and exit value for eBPF programs - * R1 - R5: arguments for function calls - * R6 - R9: callee saved registers that function calls will preserve - * R10: read-only frame pointer to access stack +* R0: return value from function calls, and exit value for eBPF programs +* R1 - R5: arguments for function calls +* R6 - R9: callee saved registers that function calls will preserve +* R10: read-only frame pointer to access stack + +Registers R0 - R5 are scratch registers, meaning the BPF program needs to either +spill them to the BPF stack or move them to callee saved registers if these +arguments are to be reused across multiple function calls. Spilling means +that the value in the register is moved to the BPF stack. The reverse operation +of moving the variable from the BPF stack to the register is called filling. +The reason for spilling/filling is due to the limited number of registers. -R0 - R5 are scratch registers and eBPF programs needs to spill/fill them if -necessary across calls. + **Note** + + *Linux implementation*: In the Linux kernel, the exit value for eBPF + programs is passed as a 32 bit value. + +Upon entering execution of an eBPF program, registers R1 - R5 initially can contain +the input arguments for the program (similar to the argc/argv pair for a typical C program). +The actual number of registers used, and their meaning, is defined by the program type; +for example, a networking program might have an argument that includes network packet data +and/or metadata. + + **Note** + + *Linux implementation*: In the Linux kernel, all program types only use + R1 which contains the "context", which is typically a structure containing all + the inputs needed. Instruction encoding ==================== +An eBPF program is a sequence of instructions. + eBPF has two instruction encodings: - * the basic instruction encoding, which uses 64 bits to encode an instruction - * the wide instruction encoding, which appends a second 64-bit immediate value - (imm64) after the basic instruction for a total of 128 bits. +* the basic instruction encoding, which uses 64 bits to encode an instruction +* the wide instruction encoding, which appends a second 64-bit immediate (i.e., + constant) value after the basic instruction for a total of 128 bits. + +The basic instruction encoding is as follows: -The basic instruction encoding looks as follows: +============= ======= =============== ==================== ============ +32 bits (MSB) 16 bits 4 bits 4 bits 8 bits (LSB) +============= ======= =============== ==================== ============ +imm offset src dst opcode +============= ======= =============== ==================== ============ - ============= ======= =============== ==================== ============ - 32 bits (MSB) 16 bits 4 bits 4 bits 8 bits (LSB) - ============= ======= =============== ==================== ============ - immediate offset source register destination register opcode - ============= ======= =============== ==================== ============ +imm + integer immediate value + +offset + signed integer offset used with pointer arithmetic + +src + source register number (0-10) + +dst + destination register number (0-10) + +opcode + operation to perform Note that most instructions do not use all of the fields. -Unused fields shall be cleared to zero. +Unused fields must be set to zero. + +As discussed below in `64-bit immediate instructions`_, some basic +instructions denote that a 64-bit immediate value follows. Thus +the wide instruction encoding is as follows: + +================= ============= +64 bits (MSB) 64 bits (LSB) +================= ============= +basic instruction imm64 +================= ============= + +where MSB and LSB mean the most significant bits and least significant bits, respectively. + +In the remainder of this document 'src' and 'dst' refer to the values of the source +and destination registers, respectively, rather than the register number. Instruction classes ------------------- -The three LSB bits of the 'opcode' field store the instruction class: - - ========= ===== =============================== - class value description - ========= ===== =============================== - BPF_LD 0x00 non-standard load operations - BPF_LDX 0x01 load into register operations - BPF_ST 0x02 store from immediate operations - BPF_STX 0x03 store from register operations - BPF_ALU 0x04 32-bit arithmetic operations - BPF_JMP 0x05 64-bit jump operations - BPF_JMP32 0x06 32-bit jump operations - BPF_ALU64 0x07 64-bit arithmetic operations - ========= ===== =============================== +The encoding of the 'opcode' field varies and can be determined from +the three least significant bits (LSB) of the 'opcode' field which holds +the "instruction class", as follows: + +========= ===== =============================== ======= ================= +class value description version reference +========= ===== =============================== ======= ================= +BPF_LD 0x00 non-standard load operations 1 `Load and store instructions`_ +BPF_LDX 0x01 load into register operations 1 `Load and store instructions`_ +BPF_ST 0x02 store from immediate operations 1 `Load and store instructions`_ +BPF_STX 0x03 store from register operations 1 `Load and store instructions`_ +BPF_ALU 0x04 32-bit arithmetic operations 3 `Arithmetic and jump instructions`_ +BPF_JMP 0x05 64-bit jump operations 1 `Arithmetic and jump instructions`_ +BPF_JMP32 0x06 32-bit jump operations 3 `Arithmetic and jump instructions`_ +BPF_ALU64 0x07 64-bit arithmetic operations 1 `Arithmetic and jump instructions`_ +========= ===== =============================== ======= ================= + +where 'version' indicates the first ISA version in which support for the value was mandatory. Arithmetic and jump instructions ================================ -For arithmetic and jump instructions (BPF_ALU, BPF_ALU64, BPF_JMP and -BPF_JMP32), the 8-bit 'opcode' field is divided into three parts: +For arithmetic and jump instructions (``BPF_ALU``, ``BPF_ALU64``, ``BPF_JMP`` and +``BPF_JMP32``), the 8-bit 'opcode' field is divided into three parts: + +============== ====== ================= +4 bits (MSB) 1 bit 3 bits (LSB) +============== ====== ================= +code source instruction class +============== ====== ================= - ============== ====== ================= - 4 bits (MSB) 1 bit 3 bits (LSB) - ============== ====== ================= - operation code source instruction class - ============== ====== ================= +code + the operation code, whose meaning varies by instruction class -The 4th bit encodes the source operand: +source + the source operand location, which unless otherwise specified is one of: ====== ===== ======================================== source value description ====== ===== ======================================== - BPF_K 0x00 use 32-bit immediate as source operand - BPF_X 0x08 use 'src_reg' register as source operand + BPF_K 0x00 use 32-bit 'imm' value as source operand + BPF_X 0x08 use 'src' register value as source operand ====== ===== ======================================== -The four MSB bits store the operation code. - +instruction class + the instruction class (see `Instruction classes`_) Arithmetic instructions ----------------------- -BPF_ALU uses 32-bit wide operands while BPF_ALU64 uses 64-bit wide operands for +Instruction class ``BPF_ALU`` uses 32-bit wide operands (zeroing the upper 32 bits +of the destination register) while ``BPF_ALU64`` uses 64-bit wide operands for otherwise identical operations. -The code field encodes the operation as below: - ======== ===== ================================================= - code value description - ======== ===== ================================================= - BPF_ADD 0x00 dst += src - BPF_SUB 0x10 dst -= src - BPF_MUL 0x20 dst \*= src - BPF_DIV 0x30 dst /= src - BPF_OR 0x40 dst \|= src - BPF_AND 0x50 dst &= src - BPF_LSH 0x60 dst <<= src - BPF_RSH 0x70 dst >>= src - BPF_NEG 0x80 dst = ~src - BPF_MOD 0x90 dst %= src - BPF_XOR 0xa0 dst ^= src - BPF_MOV 0xb0 dst = src - BPF_ARSH 0xc0 sign extending shift right - BPF_END 0xd0 byte swap operations (see separate section below) - ======== ===== ================================================= +Support for ``BPF_ALU`` is required in ISA version 3, and optional in earlier +versions. + + **Note** + + *Clang implementation*: + For ISA versions prior to 3, Clang v7.0 and later can enable ``BPF_ALU`` support with + ``-Xclang -target-feature -Xclang +alu32``. + +The 4-bit 'code' field encodes the operation as follows: + +======== ===== ================================================= +code value description +======== ===== ================================================= +BPF_ADD 0x00 dst += src +BPF_SUB 0x10 dst -= src +BPF_MUL 0x20 dst \*= src +BPF_DIV 0x30 dst /= src +BPF_OR 0x40 dst \|= src +BPF_AND 0x50 dst &= src +BPF_LSH 0x60 dst <<= src +BPF_RSH 0x70 dst >>= src +BPF_NEG 0x80 dst = ~src +BPF_MOD 0x90 dst %= src +BPF_XOR 0xa0 dst ^= src +BPF_MOV 0xb0 dst = src +BPF_ARSH 0xc0 sign extending shift right +BPF_END 0xd0 byte swap operations (see `Byte swap instructions`_ below) +======== ===== ================================================= + +Underflow and overflow are allowed during arithmetic operations, +meaning the 64-bit or 32-bit value will wrap. + +``BPF_DIV`` has an implicit program exit condition as well. If +eBPF program execution would result in division by zero, +program execution must be gracefully aborted. + +Examples: -BPF_ADD | BPF_X | BPF_ALU means:: +``BPF_ADD | BPF_X | BPF_ALU`` (0x0c) means:: - dst_reg = (u32) dst_reg + (u32) src_reg; + dst = (uint32_t) (dst + src); -BPF_ADD | BPF_X | BPF_ALU64 means:: +where '(uint32_t)' indicates truncation to 32 bits. - dst_reg = dst_reg + src_reg + **Note** -BPF_XOR | BPF_K | BPF_ALU means:: + *Linux implementation*: In the Linux kernel, uint32_t is expressed as u32, + uint64_t is expressed as u64, etc. This document uses the standard C terminology + as the cross-platform specification. - src_reg = (u32) src_reg ^ (u32) imm32 +``BPF_ADD | BPF_X | BPF_ALU64`` (0x0f) means:: -BPF_XOR | BPF_K | BPF_ALU64 means:: + dst = dst + src - src_reg = src_reg ^ imm32 +``BPF_XOR | BPF_K | BPF_ALU`` (0xa4) means:: + + src = (uint32_t) src ^ (uint32_t) imm + +``BPF_XOR | BPF_K | BPF_ALU64`` (0xa7) means:: + + src = src ^ imm Byte swap instructions ----------------------- +~~~~~~~~~~~~~~~~~~~~~~ The byte swap instructions use an instruction class of ``BPF_ALU`` and a 4-bit -code field of ``BPF_END``. +'code' field of ``BPF_END``. The byte swap instructions operate on the destination register only and do not use a separate source register or immediate value. -The 1-bit source operand field in the opcode is used to to select what byte -order the operation convert from or to: +Byte swap instructions use non-default semantics of the 1-bit 'source' field in +the 'opcode' field. Instead of indicating the source operator, it is instead +used to select what byte order the operation converts from or to: - ========= ===== ================================================= - source value description - ========= ===== ================================================= - BPF_TO_LE 0x00 convert between host byte order and little endian - BPF_TO_BE 0x08 convert between host byte order and big endian - ========= ===== ================================================= - -The imm field encodes the width of the swap operations. The following widths -are supported: 16, 32 and 64. - -Examples: +========= ===== ================================================= +source value description +========= ===== ================================================= +BPF_TO_LE 0x00 convert between host byte order and little endian +BPF_TO_BE 0x08 convert between host byte order and big endian +========= ===== ================================================= -``BPF_ALU | BPF_TO_LE | BPF_END`` with imm = 16 means:: + **Note** - dst_reg = htole16(dst_reg) + *Linux implementation*: + ``BPF_FROM_LE`` and ``BPF_FROM_BE`` exist as aliases for ``BPF_TO_LE`` and + ``BPF_TO_BE`` respectively. -``BPF_ALU | BPF_TO_BE | BPF_END`` with imm = 64 means:: +The 'imm' field encodes the width of the swap operations. The following widths +are supported: 16, 32 and 64. The following table summarizes the resulting +possibilities: - dst_reg = htobe64(dst_reg) +============================= ========= === ======== ================== +opcode construction opcode imm mnemonic pseudocode +============================= ========= === ======== ================== +BPF_END | BPF_TO_LE | BPF_ALU 0xd4 16 le16 dst dst = htole16(dst) +BPF_END | BPF_TO_LE | BPF_ALU 0xd4 32 le32 dst dst = htole32(dst) +BPF_END | BPF_TO_LE | BPF_ALU 0xd4 64 le64 dst dst = htole64(dst) +BPF_END | BPF_TO_BE | BPF_ALU 0xdc 16 be16 dst dst = htobe16(dst) +BPF_END | BPF_TO_BE | BPF_ALU 0xdc 32 be32 dst dst = htobe32(dst) +BPF_END | BPF_TO_BE | BPF_ALU 0xdc 64 be64 dst dst = htobe64(dst) +============================= ========= === ======== ================== -``BPF_FROM_LE`` and ``BPF_FROM_BE`` exist as aliases for ``BPF_TO_LE`` and -``BPF_TO_BE`` respectively. +where +* mnenomic indicates a short form that might be displayed by some tools such as disassemblers +* 'htoleNN()' indicates converting a NN-bit value from host byte order to little-endian byte order +* 'htobeNN()' indicates converting a NN-bit value from host byte order to big-endian byte order Jump instructions ----------------- -BPF_JMP32 uses 32-bit wide operands while BPF_JMP uses 64-bit wide operands for +Instruction class ``BPF_JMP32`` uses 32-bit wide operands while ``BPF_JMP`` uses 64-bit wide operands for otherwise identical operations. -The code field encodes the operation as below: - - ======== ===== ========================= ============ - code value description notes - ======== ===== ========================= ============ - BPF_JA 0x00 PC += off BPF_JMP only - BPF_JEQ 0x10 PC += off if dst == src - BPF_JGT 0x20 PC += off if dst > src unsigned - BPF_JGE 0x30 PC += off if dst >= src unsigned - BPF_JSET 0x40 PC += off if dst & src - BPF_JNE 0x50 PC += off if dst != src - BPF_JSGT 0x60 PC += off if dst > src signed - BPF_JSGE 0x70 PC += off if dst >= src signed - BPF_CALL 0x80 function call - BPF_EXIT 0x90 function / program return BPF_JMP only - BPF_JLT 0xa0 PC += off if dst < src unsigned - BPF_JLE 0xb0 PC += off if dst <= src unsigned - BPF_JSLT 0xc0 PC += off if dst < src signed - BPF_JSLE 0xd0 PC += off if dst <= src signed - ======== ===== ========================= ============ - -The eBPF program needs to store the return value into register R0 before doing a -BPF_EXIT. +Support for ``BPF_JMP32`` is required in ISA version 3, and optional in earlier +versions. + +The 4-bit 'code' field encodes the operation as below, where PC is the program counter: + +======== ===== ============================ ======= ============ +code value description version notes +======== ===== ============================ ======= ============ +BPF_JA 0x00 PC += offset 1 BPF_JMP only +BPF_JEQ 0x10 PC += offset if dst == src 1 +BPF_JGT 0x20 PC += offset if dst > src 1 unsigned +BPF_JGE 0x30 PC += offset if dst >= src 1 unsigned +BPF_JSET 0x40 PC += offset if dst & src 1 +BPF_JNE 0x50 PC += offset if dst != src 1 +BPF_JSGT 0x60 PC += offset if dst > src 1 signed +BPF_JSGE 0x70 PC += offset if dst >= src 1 signed +BPF_CALL 0x80 call function imm 1 see `Helper functions`_ +BPF_EXIT 0x90 function / program return 1 BPF_JMP only +BPF_JLT 0xa0 PC += offset if dst < src 2 unsigned +BPF_JLE 0xb0 PC += offset if dst <= src 2 unsigned +BPF_JSLT 0xc0 PC += offset if dst < src 2 signed +BPF_JSLE 0xd0 PC += offset if dst <= src 2 signed +======== ===== ============================ ======= ============ + +where 'version' indicates the first ISA version in which the value was supported. + +Helper functions +~~~~~~~~~~~~~~~~ +Helper functions are a concept whereby BPF programs can call into +set of function calls exposed by the eBPF runtime. Each helper +function is identified by an integer used in a ``BPF_CALL`` instruction. +The available helper functions may differ for each eBPF program type. + +Conceptually, each helper function is implemented with a commonly shared function +signature defined as: + + uint64_t function(uint64_t r1, uint64_t r2, uint64_t r3, uint64_t r4, uint64_t r5) + +In actuality, each helper function is defined as taking between 0 and 5 arguments, +with the remaining registers being ignored. The definition of a helper function +is responsible for specifying the type (e.g., integer, pointer, etc.) of the value returned, +the number of arguments, and the type of each argument. Load and store instructions =========================== -For load and store instructions (BPF_LD, BPF_LDX, BPF_ST and BPF_STX), the +For load and store instructions (``BPF_LD``, ``BPF_LDX``, ``BPF_ST``, and ``BPF_STX``), the 8-bit 'opcode' field is divided as: - ============ ====== ================= - 3 bits (MSB) 2 bits 3 bits (LSB) - ============ ====== ================= - mode size instruction class - ============ ====== ================= +============ ====== ================= +3 bits (MSB) 2 bits 3 bits (LSB) +============ ====== ================= +mode size instruction class +============ ====== ================= -The size modifier is one of: +mode + one of: + + ============= ===== ==================================== ============= + mode modifier value description reference + ============= ===== ==================================== ============= + BPF_IMM 0x00 64-bit immediate instructions `64-bit immediate instructions`_ + BPF_ABS 0x20 legacy BPF packet access (absolute) `Legacy BPF Packet access instructions`_ + BPF_IND 0x40 legacy BPF packet access (indirect) `Legacy BPF Packet access instructions`_ + BPF_MEM 0x60 regular load and store operations `Regular load and store operations`_ + BPF_ATOMIC 0xc0 atomic operations `Atomic operations`_ + ============= ===== ==================================== ============= + +size + one of: ============= ===== ===================== size modifier value description @@ -213,18 +362,8 @@ The size modifier is one of: BPF_DW 0x18 double word (8 bytes) ============= ===== ===================== -The mode modifier is one of: - - ============= ===== ==================================== - mode modifier value description - ============= ===== ==================================== - BPF_IMM 0x00 64-bit immediate instructions - BPF_ABS 0x20 legacy BPF packet access (absolute) - BPF_IND 0x40 legacy BPF packet access (indirect) - BPF_MEM 0x60 regular load and store operations - BPF_ATOMIC 0xc0 atomic operations - ============= ===== ==================================== - +instruction class + the instruction class (see `Instruction classes`_) Regular load and store operations --------------------------------- @@ -232,19 +371,22 @@ Regular load and store operations The ``BPF_MEM`` mode modifier is used to encode regular load and store instructions that transfer data between a register and memory. -``BPF_MEM | | BPF_STX`` means:: - - *(size *) (dst_reg + off) = src_reg - -``BPF_MEM | | BPF_ST`` means:: - - *(size *) (dst_reg + off) = imm32 - -``BPF_MEM | | BPF_LDX`` means:: - - dst_reg = *(size *) (src_reg + off) - -Where size is one of: ``BPF_B``, ``BPF_H``, ``BPF_W``, or ``BPF_DW``. +============================= ========= ================================== +opcode construction opcode pseudocode +============================= ========= ================================== +BPF_MEM | BPF_B | BPF_LDX 0x71 dst = *(uint8_t *) (src + offset) +BPF_MEM | BPF_H | BPF_LDX 0x69 dst = *(uint16_t *) (src + offset) +BPF_MEM | BPF_W | BPF_LDX 0x61 dst = *(uint32_t *) (src + offset) +BPF_MEM | BPF_DW | BPF_LDX 0x79 dst = *(uint64_t *) (src + offset) +BPF_MEM | BPF_B | BPF_ST 0x72 *(uint8_t *) (dst + offset) = imm +BPF_MEM | BPF_H | BPF_ST 0x6a *(uint16_t *) (dst + offset) = imm +BPF_MEM | BPF_W | BPF_ST 0x62 *(uint32_t *) (dst + offset) = imm +BPF_MEM | BPF_DW | BPF_ST 0x7a *(uint64_t *) (dst + offset) = imm +BPF_MEM | BPF_B | BPF_STX 0x73 *(uint8_t *) (dst + offset) = src +BPF_MEM | BPF_H | BPF_STX 0x6b *(uint16_t *) (dst + offset) = src +BPF_MEM | BPF_W | BPF_STX 0x63 *(uint32_t *) (dst + offset) = src +BPF_MEM | BPF_DW | BPF_STX 0x7b *(uint64_t *) (dst + offset) = src +============================= ========= ================================== Atomic operations ----------------- @@ -256,76 +398,83 @@ by other eBPF programs or means outside of this specification. All atomic operations supported by eBPF are encoded as store operations that use the ``BPF_ATOMIC`` mode modifier as follows: - * ``BPF_ATOMIC | BPF_W | BPF_STX`` for 32-bit operations - * ``BPF_ATOMIC | BPF_DW | BPF_STX`` for 64-bit operations - * 8-bit and 16-bit wide atomic operations are not supported. +* ``BPF_ATOMIC | BPF_W | BPF_STX`` (0xc3) for 32-bit operations +* ``BPF_ATOMIC | BPF_DW | BPF_STX`` (0xdb) for 64-bit operations + +Note that 8-bit (``BPF_B``) and 16-bit (``BPF_H``) wide atomic operations are not supported, +nor is ``BPF_ATOMIC | | BPF_ST``. -The imm field is used to encode the actual atomic operation. +The 'imm' field is used to encode the actual atomic operation. Simple atomic operation use a subset of the values defined to encode -arithmetic operations in the imm field to encode the atomic operation: +arithmetic operations in the 'imm' field to encode the atomic operation: - ======== ===== =========== - imm value description - ======== ===== =========== - BPF_ADD 0x00 atomic add - BPF_OR 0x40 atomic or - BPF_AND 0x50 atomic and - BPF_XOR 0xa0 atomic xor - ======== ===== =========== +======== ===== =========== ======= +imm value description version +======== ===== =========== ======= +BPF_ADD 0x00 atomic add 1 +BPF_OR 0x40 atomic or 3 +BPF_AND 0x50 atomic and 3 +BPF_XOR 0xa0 atomic xor 3 +======== ===== =========== ======= +where 'version' indicates the first ISA version in which the value was supported. -``BPF_ATOMIC | BPF_W | BPF_STX`` with imm = BPF_ADD means:: +``BPF_ATOMIC | BPF_W | BPF_STX`` (0xc3) with 'imm' = BPF_ADD means:: - *(u32 *)(dst_reg + off16) += src_reg + *(uint32_t *)(dst + offset) += src -``BPF_ATOMIC | BPF_DW | BPF_STX`` with imm = BPF ADD means:: +``BPF_ATOMIC | BPF_DW | BPF_STX`` (0xdb) with 'imm' = BPF ADD means:: - *(u64 *)(dst_reg + off16) += src_reg + *(uint64_t *)(dst + offset) += src -``BPF_XADD`` is a deprecated name for ``BPF_ATOMIC | BPF_ADD``. +``BPF_XADD`` appeared in version 1, but is now considered to be a deprecated alias +for ``BPF_ATOMIC | BPF_ADD``. -In addition to the simple atomic operations, there also is a modifier and +In addition to the simple atomic operations above, there also is a modifier and two complex atomic operations: - =========== ================ =========================== - imm value description - =========== ================ =========================== - BPF_FETCH 0x01 modifier: return old value - BPF_XCHG 0xe0 | BPF_FETCH atomic exchange - BPF_CMPXCHG 0xf0 | BPF_FETCH atomic compare and exchange - =========== ================ =========================== +=========== ================ =========================== ======= +imm value description version +=========== ================ =========================== ======= +BPF_FETCH 0x01 modifier: return old value 3 +BPF_XCHG 0xe0 | BPF_FETCH atomic exchange 3 +BPF_CMPXCHG 0xf0 | BPF_FETCH atomic compare and exchange 3 +=========== ================ =========================== ======= The ``BPF_FETCH`` modifier is optional for simple atomic operations, and always set for the complex atomic operations. If the ``BPF_FETCH`` flag -is set, then the operation also overwrites ``src_reg`` with the value that +is set, then the operation also overwrites ``src`` with the value that was in memory before it was modified. -The ``BPF_XCHG`` operation atomically exchanges ``src_reg`` with the value -addressed by ``dst_reg + off``. +The ``BPF_XCHG`` operation atomically exchanges ``src`` with the value +addressed by ``dst + offset``. The ``BPF_CMPXCHG`` operation atomically compares the value addressed by -``dst_reg + off`` with ``R0``. If they match, the value addressed by -``dst_reg + off`` is replaced with ``src_reg``. In either case, the -value that was at ``dst_reg + off`` before the operation is zero-extended +``dst + offset`` with ``R0``. If they match, the value addressed by +``dst + offset`` is replaced with ``src``. In either case, the +value that was at ``dst + offset`` before the operation is zero-extended and loaded back to ``R0``. -Clang can generate atomic instructions by default when ``-mcpu=v3`` is -enabled. If a lower version for ``-mcpu`` is set, the only atomic instruction -Clang can generate is ``BPF_ADD`` *without* ``BPF_FETCH``. If you need to enable -the atomics features, while keeping a lower ``-mcpu`` version, you can use -``-Xclang -target-feature -Xclang +alu32``. + **Note** + + *Clang implementation*: + Clang can generate atomic instructions by default when ``-mcpu=v3`` is + enabled. If a lower version for ``-mcpu`` is set, the only atomic instruction + Clang can generate is ``BPF_ADD`` *without* ``BPF_FETCH``. If you need to enable + the atomics features, while keeping a lower ``-mcpu`` version, you can use + ``-Xclang -target-feature -Xclang +alu32``. 64-bit immediate instructions ----------------------------- -Instructions with the ``BPF_IMM`` mode modifier use the wide instruction +Instructions with the ``BPF_IMM`` 'mode' modifier use the wide instruction encoding for an extra imm64 value. There is currently only one such instruction. -``BPF_LD | BPF_DW | BPF_IMM`` means:: +``BPF_IMM | BPF_DW | BPF_LD`` (0x18) means:: - dst_reg = imm64 + dst = imm64 Legacy BPF Packet access instructions @@ -333,34 +482,236 @@ Legacy BPF Packet access instructions eBPF has special instructions for access to packet data that have been carried over from classic BPF to retain the performance of legacy socket -filters running in the eBPF interpreter. +filters running in an eBPF interpreter. The instructions come in two forms: ``BPF_ABS | | BPF_LD`` and ``BPF_IND | | BPF_LD``. These instructions are used to access packet data and can only be used when -the program context is a pointer to networking packet. ``BPF_ABS`` +the program context contains a pointer to a networking packet. ``BPF_ABS`` accesses packet data at an absolute offset specified by the immediate data and ``BPF_IND`` access packet data at an offset that includes the value of a register in addition to the immediate data. These instructions have seven implicit operands: - * Register R6 is an implicit input that must contain pointer to a - struct sk_buff. - * Register R0 is an implicit output which contains the data fetched from - the packet. - * Registers R1-R5 are scratch registers that are clobbered after a call to - ``BPF_ABS | BPF_LD`` or ``BPF_IND | BPF_LD`` instructions. - -These instructions have an implicit program exit condition as well. When an -eBPF program is trying to access the data beyond the packet boundary, the -program execution will be aborted. - -``BPF_ABS | BPF_W | BPF_LD`` means:: - - R0 = ntohl(*(u32 *) (((struct sk_buff *) R6)->data + imm32)) - -``BPF_IND | BPF_W | BPF_LD`` means:: - - R0 = ntohl(*(u32 *) (((struct sk_buff *) R6)->data + src_reg + imm32)) +* Register R6 is an implicit input that must contain a pointer to a + context structure with a packet data pointer. +* Register R0 is an implicit output which contains the data fetched from + the packet. +* Registers R1-R5 are scratch registers that are clobbered by the + instruction. + + **Note** + + *Linux implementation*: In Linux, R6 references a struct sk_buff. + +These instructions have an implicit program exit condition as well. If an +eBPF program attempts access data beyond the packet boundary, the +program execution must be gracefully aborted. + +``BPF_ABS | BPF_W | BPF_LD`` (0x20) means:: + + R0 = ntohl(*(uint32_t *) (R6->data + imm)) + +where ``ntohl()`` converts a 32-bit value from network byte order to host byte order. + +``BPF_IND | BPF_W | BPF_LD`` (0x40) means:: + + R0 = ntohl(*(uint32_t *) (R6->data + src + imm)) + +Appendix +======== + +For reference, the following table lists opcodes in order by value. + +====== ==== =================================================== ============= +opcode imm description reference +====== ==== =================================================== ============= +0x04 any dst = (uint32_t)(dst + imm) `Arithmetic instructions`_ +0x05 0x00 goto +offset `Jump instructions`_ +0x07 any dst += imm `Arithmetic instructions`_ +0x0c 0x00 dst = (uint32_t)(dst + src) `Arithmetic instructions`_ +0x0f 0x00 dst += src `Arithmetic instructions`_ +0x14 any dst = (uint32_t)(dst - imm) `Arithmetic instructions`_ +0x15 any if dst == imm goto +offset `Jump instructions`_ +0x16 any if (uint32_t)dst == imm goto +offset `Jump instructions`_ +0x17 any dst -= imm `Arithmetic instructions`_ +0x18 any dst = imm `Load and store instructions`_ +0x1c 0x00 dst = (uint32_t)(dst - src) `Arithmetic instructions`_ +0x1d 0x00 if dst == src goto +offset `Jump instructions`_ +0x1e 0x00 if (uint32_t)dst == (uint32_t)src goto +offset `Jump instructions`_ +0x1f 0x00 dst -= src `Arithmetic instructions`_ +0x20 any dst = ntohl(\*(uint32_t \*)(R6->data + imm)) `Load and store instructions`_ +0x24 any dst = (uint32_t)(dst \* imm) `Arithmetic instructions`_ +0x25 any if dst > imm goto +offset `Jump instructions`_ +0x26 any if (uint32_t)dst > imm goto +offset `Jump instructions`_ +0x27 any dst \*= imm `Arithmetic instructions`_ +0x28 any dst = ntohs(\*(uint16_t \*)(R6->data + imm)) `Load and store instructions`_ +0x2c 0x00 dst = (uint32_t)(dst \* src) `Arithmetic instructions`_ +0x2d 0x00 if dst > src goto +offset `Jump instructions`_ +0x2e 0x00 if (uint32_t)dst > (uint32_t)src goto +offset `Jump instructions`_ +0x2f 0x00 dst \*= src `Arithmetic instructions`_ +0x30 any dst = (\*(uint8_t \*)(R6->data + imm)) `Load and store instructions`_ +0x34 any dst = (uint32_t)(dst / imm) `Arithmetic instructions`_ +0x35 any if dst >= imm goto +offset `Jump instructions`_ +0x36 any if (uint32_t)dst >= imm goto +offset `Jump instructions`_ +0x37 any dst /= imm `Arithmetic instructions`_ +0x38 any dst = ntohll(\*(uint64_t \*)(R6->data + imm)) `Load and store instructions`_ +0x3c 0x00 dst = (uint32_t)(dst / src) `Arithmetic instructions`_ +0x3d 0x00 if dst >= src goto +offset `Jump instructions`_ +0x3e 0x00 if (uint32_t)dst >= (uint32_t)src goto +offset `Jump instructions`_ +0x3f 0x00 dst /= src `Arithmetic instructions`_ +0x40 any dst = ntohl(\*(uint32_t \*)(R6->data + src + imm)) `Load and store instructions`_ +0x44 any dst = (uint32_t)(dst \| imm) `Arithmetic instructions`_ +0x45 any if dst & imm goto +offset `Jump instructions`_ +0x46 any if (uint32_t)dst & imm goto +offset `Jump instructions`_ +0x47 any dst \|= imm `Arithmetic instructions`_ +0x48 any dst = ntohs(\*(uint16_t \*)(R6->data + src + imm)) `Load and store instructions`_ +0x4c 0x00 dst = (uint32_t)(dst \| src) `Arithmetic instructions`_ +0x4d 0x00 if dst & src goto +offset `Jump instructions`_ +0x4e 0x00 if (uint32_t)dst & (uint32_t)src goto +offset `Jump instructions`_ +0x4f 0x00 dst \|= src `Arithmetic instructions`_ +0x50 any dst = \*(uint8_t \*)(R6->data + src + imm)) `Load and store instructions`_ +0x54 any dst = (uint32_t)(dst & imm) `Arithmetic instructions`_ +0x55 any if dst != imm goto +offset `Jump instructions`_ +0x56 any if (uint32_t)dst != imm goto +offset `Jump instructions`_ +0x57 any dst &= imm `Arithmetic instructions`_ +0x58 any dst = ntohll(\*(uint64_t \*)(R6->data + src + imm)) `Load and store instructions`_ +0x5c 0x00 dst = (uint32_t)(dst & src) `Arithmetic instructions`_ +0x5d 0x00 if dst != src goto +offset `Jump instructions`_ +0x5e 0x00 if (uint32_t)dst != (uint32_t)src goto +offset `Jump instructions`_ +0x5f 0x00 dst &= src `Arithmetic instructions`_ +0x61 0x00 dst = \*(uint32_t \*)(src + offset) `Load and store instructions`_ +0x62 any \*(uint32_t \*)(dst + offset) = imm `Load and store instructions`_ +0x63 0x00 \*(uint32_t \*)(dst + offset) = src `Load and store instructions`_ +0x64 any dst = (uint32_t)(dst << imm) `Arithmetic instructions`_ +0x65 any if dst s> imm goto +offset `Jump instructions`_ +0x66 any if (int32_t)dst s> (int32_t)imm goto +offset `Jump instructions`_ +0x67 any dst <<= imm `Arithmetic instructions`_ +0x69 0x00 dst = \*(uint16_t \*)(src + offset) `Load and store instructions`_ +0x6a any \*(uint16_t \*)(dst + offset) = imm `Load and store instructions`_ +0x6b 0x00 \*(uint16_t \*)(dst + offset) = src `Load and store instructions`_ +0x6c 0x00 dst = (uint32_t)(dst << src) `Arithmetic instructions`_ +0x6d 0x00 if dst s> src goto +offset `Jump instructions`_ +0x6e 0x00 if (int32_t)dst s> (int32_t)src goto +offset `Jump instructions`_ +0x6f 0x00 dst <<= src `Arithmetic instructions`_ +0x71 0x00 dst = \*(uint8_t \*)(src + offset) `Load and store instructions`_ +0x72 any \*(uint8_t \*)(dst + offset) = imm `Load and store instructions`_ +0x73 0x00 \*(uint8_t \*)(dst + offset) = src `Load and store instructions`_ +0x74 any dst = (uint32_t)(dst >> imm) `Arithmetic instructions`_ +0x75 any if dst s>= imm goto +offset `Jump instructions`_ +0x76 any if (int32_t)dst s>= (int32_t)imm goto +offset `Jump instructions`_ +0x77 any dst >>= imm `Arithmetic instructions`_ +0x79 0x00 dst = \*(uint64_t \*)(src + offset) `Load and store instructions`_ +0x7a any \*(uint64_t \*)(dst + offset) = imm `Load and store instructions`_ +0x7b 0x00 \*(uint64_t \*)(dst + offset) = src `Load and store instructions`_ +0x7c 0x00 dst = (uint32_t)(dst >> src) `Arithmetic instructions`_ +0x7d 0x00 if dst s>= src goto +offset `Jump instructions`_ +0x7e 0x00 if (int32_t)dst s>= (int32_t)src goto +offset `Jump instructions`_ +0x7f 0x00 dst >>= src `Arithmetic instructions`_ +0x84 0x00 dst = (uint32_t)-dst `Arithmetic instructions`_ +0x85 any call imm `Jump instructions`_ +0x87 0x00 dst = -dst `Arithmetic instructions`_ +0x94 any dst = (uint32_t)(dst % imm) `Arithmetic instructions`_ +0x95 0x00 return `Jump instructions`_ +0x97 any dst %= imm `Arithmetic instructions`_ +0x9c 0x00 dst = (uint32_t)(dst % src) `Arithmetic instructions`_ +0x9f 0x00 dst %= src `Arithmetic instructions`_ +0xa4 any dst = (uint32_t)(dst ^ imm) `Arithmetic instructions`_ +0xa5 any if dst < imm goto +offset `Jump instructions`_ +0xa6 any if (uint32_t)dst < imm goto +offset `Jump instructions`_ +0xa7 any dst ^= imm `Arithmetic instructions`_ +0xac 0x00 dst = (uint32_t)(dst ^ src) `Arithmetic instructions`_ +0xad 0x00 if dst < src goto +offset `Jump instructions`_ +0xae 0x00 if (uint32_t)dst < (uint32_t)src goto +offset `Jump instructions`_ +0xaf 0x00 dst ^= src `Arithmetic instructions`_ +0xb4 any dst = (uint32_t) imm `Arithmetic instructions`_ +0xb5 any if dst <= imm goto +offset `Jump instructions`_ +0xa6 any if (uint32_t)dst <= imm goto +offset `Jump instructions`_ +0xb7 any dst = imm `Arithmetic instructions`_ +0xbc 0x00 dst = (uint32_t) src `Arithmetic instructions`_ +0xbd 0x00 if dst <= src goto +offset `Jump instructions`_ +0xbe 0x00 if (uint32_t)dst <= (uint32_t)src goto +offset `Jump instructions`_ +0xbf 0x00 dst = src `Arithmetic instructions`_ +0xc3 0x00 lock \*(uint32_t \*)(dst + offset) += src `Atomic operations`_ +0xc3 0x01 lock:: `Atomic operations`_ + + *(uint32_t *)(dst + offset) += src + src = *(uint32_t *)(dst + offset) +0xc3 0x40 \*(uint32_t \*)(dst + offset) \|= src `Atomic operations`_ +0xc3 0x41 lock:: `Atomic operations`_ + + *(uint32_t *)(dst + offset) |= src + src = *(uint32_t *)(dst + offset) +0xc3 0x50 \*(uint32_t \*)(dst + offset) &= src `Atomic operations`_ +0xc3 0x51 lock:: `Atomic operations`_ + + *(uint32_t *)(dst + offset) &= src + src = *(uint32_t *)(dst + offset) +0xc3 0xa0 \*(uint32_t \*)(dst + offset) ^= src `Atomic operations`_ +0xc3 0xa1 lock:: `Atomic operations`_ + + *(uint32_t *)(dst + offset) ^= src + src = *(uint32_t *)(dst + offset) +0xc3 0xe1 lock:: `Atomic operations`_ + + temp = *(uint32_t *)(dst + offset) + *(uint32_t *)(dst + offset) = src + src = temp +0xc3 0xf1 lock:: `Atomic operations`_ + + temp = *(uint32_t *)(dst + offset) + if *(uint32_t)(dst + offset) == R0 + *(uint32_t)(dst + offset) = src + R0 = temp +0xc4 any dst = (uint32_t)(dst s>> imm) `Arithmetic instructions`_ +0xc5 any if dst s< imm goto +offset `Jump instructions`_ +0xc6 any if (int32_t)dst s< (int32_t)imm goto +offset `Jump instructions`_ +0xc7 any dst s>>= imm `Arithmetic instructions`_ +0xcc 0x00 dst = (uint32_t)(dst s>> src) `Arithmetic instructions`_ +0xcd 0x00 if dst s< src goto +offset `Jump instructions`_ +0xce 0x00 if (int32_t)dst s< (int32_t)src goto +offset `Jump instructions`_ +0xcf 0x00 dst s>>= src `Arithmetic instructions`_ +0xd4 0x10 dst = htole16(dst) `Byte swap instructions`_ +0xd4 0x20 dst = htole32(dst) `Byte swap instructions`_ +0xd4 0x40 dst = htole64(dst) `Byte swap instructions`_ +0xd5 any if dst s<= imm goto +offset `Jump instructions`_ +0xd6 any if (int32_t)dst s<= (int32_t)imm goto +offset `Jump instructions`_ +0xc3 0x00 lock \*(uint64_t \*)(dst + offset) += src `Atomic operations`_ +0xdb 0x01 lock:: `Atomic operations`_ + + *(uint64_t *)(dst + offset) += src + src = *(uint64_t *)(dst + offset) +0xdb 0x40 \*(uint64_t \*)(dst + offset) \|= src `Atomic operations`_ +0xdb 0x41 lock:: `Atomic operations`_ + + *(uint64_t *)(dst + offset) |= src + lock src = *(uint64_t *)(dst + offset) +0xdb 0x50 \*(uint64_t \*)(dst + offset) &= src `Atomic operations`_ +0xdb 0x51 lock:: `Atomic operations`_ + + *(uint64_t *)(dst + offset) &= src + src = *(uint64_t *)(dst + offset) +0xdb 0xa0 \*(uint64_t \*)(dst + offset) ^= src `Atomic operations`_ +0xdb 0xa1 lock:: `Atomic operations`_ + + *(uint64_t *)(dst + offset) ^= src + src = *(uint64_t *)(dst + offset) +0xdb 0xe1 lock:: `Atomic operations`_ + + temp = *(uint64_t *)(dst + offset) + *(uint64_t *)(dst + offset) = src + src = temp +0xdb 0xf1 lock:: `Atomic operations`_ + + temp = *(uint64_t *)(dst + offset) + if *(uint64_t)(dst + offset) == R0 + *(uint64_t)(dst + offset) = src + R0 = temp +0xdc 0x10 dst = htobe16(dst) `Byte swap instructions`_ +0xdc 0x20 dst = htobe32(dst) `Byte swap instructions`_ +0xdc 0x40 dst = htobe64(dst) `Byte swap instructions`_ +0xdd 0x00 if dst s<= src goto +offset `Jump instructions`_ +0xde 0x00 if (int32_t)dst s<= (int32_t)src goto +offset `Jump instructions`_ +====== ==== =================================================== ============= From b424eb088fb31745182d4dfa5847af77e8c16407 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Tue, 13 Sep 2022 16:01:40 +0100 Subject: [PATCH 03/25] Move legacy packet instructions to linux historical notes Also specify that div-by-zero results in zero and mod-zero results in the source value Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 86 ++++++++--------------- isa/kernel.org/linux-historical-notes.rst | 63 +++++++++++++++++ 2 files changed, 91 insertions(+), 58 deletions(-) create mode 100644 isa/kernel.org/linux-historical-notes.rst diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index 7f8ee00..6910e7c 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -182,25 +182,27 @@ code value description BPF_ADD 0x00 dst += src BPF_SUB 0x10 dst -= src BPF_MUL 0x20 dst \*= src -BPF_DIV 0x30 dst /= src +BPF_DIV 0x30 dst = (src != 0) ? (dst / src) : 0 BPF_OR 0x40 dst \|= src BPF_AND 0x50 dst &= src BPF_LSH 0x60 dst <<= src BPF_RSH 0x70 dst >>= src BPF_NEG 0x80 dst = ~src -BPF_MOD 0x90 dst %= src +BPF_MOD 0x90 dst = (src != 0) ? (dst % src) : src BPF_XOR 0xa0 dst ^= src BPF_MOV 0xb0 dst = src BPF_ARSH 0xc0 sign extending shift right BPF_END 0xd0 byte swap operations (see `Byte swap instructions`_ below) ======== ===== ================================================= -Underflow and overflow are allowed during arithmetic operations, -meaning the 64-bit or 32-bit value will wrap. +where 'src' is the source operand value. -``BPF_DIV`` has an implicit program exit condition as well. If +Underflow and overflow are allowed during arithmetic operations, +meaning the 64-bit or 32-bit value will wrap. If eBPF program execution would result in division by zero, -program execution must be gracefully aborted. +the destination register is instead set to zero. +If execution would result in modulo by zero, +the destination register is instead set to the source value. Examples: @@ -480,45 +482,13 @@ There is currently only one such instruction. Legacy BPF Packet access instructions ------------------------------------- -eBPF has special instructions for access to packet data that have been -carried over from classic BPF to retain the performance of legacy socket -filters running in an eBPF interpreter. - -The instructions come in two forms: ``BPF_ABS | | BPF_LD`` and -``BPF_IND | | BPF_LD``. - -These instructions are used to access packet data and can only be used when -the program context contains a pointer to a networking packet. ``BPF_ABS`` -accesses packet data at an absolute offset specified by the immediate data -and ``BPF_IND`` access packet data at an offset that includes the value of -a register in addition to the immediate data. - -These instructions have seven implicit operands: - -* Register R6 is an implicit input that must contain a pointer to a - context structure with a packet data pointer. -* Register R0 is an implicit output which contains the data fetched from - the packet. -* Registers R1-R5 are scratch registers that are clobbered by the - instruction. +Linux introduced special instructions for access to packet data that were +carried over from classic BPF. However, these instructions are +deprecated and should no longer be used in any version of the ISA. **Note** - *Linux implementation*: In Linux, R6 references a struct sk_buff. - -These instructions have an implicit program exit condition as well. If an -eBPF program attempts access data beyond the packet boundary, the -program execution must be gracefully aborted. - -``BPF_ABS | BPF_W | BPF_LD`` (0x20) means:: - - R0 = ntohl(*(uint32_t *) (R6->data + imm)) - -where ``ntohl()`` converts a 32-bit value from network byte order to host byte order. - -``BPF_IND | BPF_W | BPF_LD`` (0x40) means:: - - R0 = ntohl(*(uint32_t *) (R6->data + src + imm)) + *Linux implementation*: Details can be found in the `Linux historical notes `_. Appendix ======== @@ -542,42 +512,42 @@ opcode imm description reference 0x1d 0x00 if dst == src goto +offset `Jump instructions`_ 0x1e 0x00 if (uint32_t)dst == (uint32_t)src goto +offset `Jump instructions`_ 0x1f 0x00 dst -= src `Arithmetic instructions`_ -0x20 any dst = ntohl(\*(uint32_t \*)(R6->data + imm)) `Load and store instructions`_ +0x20 any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ 0x24 any dst = (uint32_t)(dst \* imm) `Arithmetic instructions`_ 0x25 any if dst > imm goto +offset `Jump instructions`_ 0x26 any if (uint32_t)dst > imm goto +offset `Jump instructions`_ 0x27 any dst \*= imm `Arithmetic instructions`_ -0x28 any dst = ntohs(\*(uint16_t \*)(R6->data + imm)) `Load and store instructions`_ +0x28 any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ 0x2c 0x00 dst = (uint32_t)(dst \* src) `Arithmetic instructions`_ 0x2d 0x00 if dst > src goto +offset `Jump instructions`_ 0x2e 0x00 if (uint32_t)dst > (uint32_t)src goto +offset `Jump instructions`_ 0x2f 0x00 dst \*= src `Arithmetic instructions`_ -0x30 any dst = (\*(uint8_t \*)(R6->data + imm)) `Load and store instructions`_ -0x34 any dst = (uint32_t)(dst / imm) `Arithmetic instructions`_ +0x30 any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ +0x34 any dst = (uint32_t)((imm != 0) ? (dst / imm) : 0) `Arithmetic instructions`_ 0x35 any if dst >= imm goto +offset `Jump instructions`_ 0x36 any if (uint32_t)dst >= imm goto +offset `Jump instructions`_ -0x37 any dst /= imm `Arithmetic instructions`_ -0x38 any dst = ntohll(\*(uint64_t \*)(R6->data + imm)) `Load and store instructions`_ -0x3c 0x00 dst = (uint32_t)(dst / src) `Arithmetic instructions`_ +0x37 any dst = (imm != 0) ? (dst / imm) : 0 `Arithmetic instructions`_ +0x38 any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ +0x3c 0x00 dst = (uint32_t)((imm != 0) ? (dst / src) : 0) `Arithmetic instructions`_ 0x3d 0x00 if dst >= src goto +offset `Jump instructions`_ 0x3e 0x00 if (uint32_t)dst >= (uint32_t)src goto +offset `Jump instructions`_ -0x3f 0x00 dst /= src `Arithmetic instructions`_ -0x40 any dst = ntohl(\*(uint32_t \*)(R6->data + src + imm)) `Load and store instructions`_ +0x3f 0x00 dst = (src !+ 0) ? (dst / src) : 0 `Arithmetic instructions`_ +0x40 any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ 0x44 any dst = (uint32_t)(dst \| imm) `Arithmetic instructions`_ 0x45 any if dst & imm goto +offset `Jump instructions`_ 0x46 any if (uint32_t)dst & imm goto +offset `Jump instructions`_ 0x47 any dst \|= imm `Arithmetic instructions`_ -0x48 any dst = ntohs(\*(uint16_t \*)(R6->data + src + imm)) `Load and store instructions`_ +0x48 any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ 0x4c 0x00 dst = (uint32_t)(dst \| src) `Arithmetic instructions`_ 0x4d 0x00 if dst & src goto +offset `Jump instructions`_ 0x4e 0x00 if (uint32_t)dst & (uint32_t)src goto +offset `Jump instructions`_ 0x4f 0x00 dst \|= src `Arithmetic instructions`_ -0x50 any dst = \*(uint8_t \*)(R6->data + src + imm)) `Load and store instructions`_ +0x50 any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ 0x54 any dst = (uint32_t)(dst & imm) `Arithmetic instructions`_ 0x55 any if dst != imm goto +offset `Jump instructions`_ 0x56 any if (uint32_t)dst != imm goto +offset `Jump instructions`_ 0x57 any dst &= imm `Arithmetic instructions`_ -0x58 any dst = ntohll(\*(uint64_t \*)(R6->data + src + imm)) `Load and store instructions`_ +0x58 any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ 0x5c 0x00 dst = (uint32_t)(dst & src) `Arithmetic instructions`_ 0x5d 0x00 if dst != src goto +offset `Jump instructions`_ 0x5e 0x00 if (uint32_t)dst != (uint32_t)src goto +offset `Jump instructions`_ @@ -613,11 +583,11 @@ opcode imm description reference 0x84 0x00 dst = (uint32_t)-dst `Arithmetic instructions`_ 0x85 any call imm `Jump instructions`_ 0x87 0x00 dst = -dst `Arithmetic instructions`_ -0x94 any dst = (uint32_t)(dst % imm) `Arithmetic instructions`_ +0x94 any dst = (uint32_t)((imm != 0) ? (dst % imm) : imm) `Arithmetic instructions`_ 0x95 0x00 return `Jump instructions`_ -0x97 any dst %= imm `Arithmetic instructions`_ -0x9c 0x00 dst = (uint32_t)(dst % src) `Arithmetic instructions`_ -0x9f 0x00 dst %= src `Arithmetic instructions`_ +0x97 any dst = (imm != 0) ? (dst % imm) : imm `Arithmetic instructions`_ +0x9c 0x00 dst = (uint32_t)((src != 0) ? (dst % src) : src) `Arithmetic instructions`_ +0x9f 0x00 dst = (src != 0) ? (dst % src) : src `Arithmetic instructions`_ 0xa4 any dst = (uint32_t)(dst ^ imm) `Arithmetic instructions`_ 0xa5 any if dst < imm goto +offset `Jump instructions`_ 0xa6 any if (uint32_t)dst < imm goto +offset `Jump instructions`_ diff --git a/isa/kernel.org/linux-historical-notes.rst b/isa/kernel.org/linux-historical-notes.rst new file mode 100644 index 0000000..c0362df --- /dev/null +++ b/isa/kernel.org/linux-historical-notes.rst @@ -0,0 +1,63 @@ +.. contents:: +.. sectnum:: + +===================== +Linux historial notes +===================== + +Legacy BPF Packet access instructions +===================================== + +As mentioned in the `ISA standard documentation `_, +Linux has special eBPF instructions for access to packet data that have been +carried over from classic BPF to retain the performance of legacy socket +filters running in the eBPF interpreter. + +The instructions come in two forms: ``BPF_ABS | | BPF_LD`` and +``BPF_IND | | BPF_LD``. + +These instructions are used to access packet data and can only be used when +the program context is a pointer to a networking packet. ``BPF_ABS`` +accesses packet data at an absolute offset specified by the immediate data +and ``BPF_IND`` access packet data at an offset that includes the value of +a register in addition to the immediate data. + +These instructions have seven implicit operands: + +* Register R6 is an implicit input that must contain a pointer to a + struct sk_buff. +* Register R0 is an implicit output which contains the data fetched from + the packet. +* Registers R1-R5 are scratch registers that are clobbered by the + instruction. + +These instructions have an implicit program exit condition as well. If an +eBPF program attempts access data beyond the packet boundary, the +program execution will be aborted. + +``BPF_ABS | BPF_W | BPF_LD`` (0x20) means:: + + R0 = ntohl(*(u32 *) ((struct sk_buff *) R6->data + imm)) + +where ``ntohl()`` converts a 32-bit value from network byte order to host byte order. + +``BPF_IND | BPF_W | BPF_LD`` (0x40) means:: + + R0 = ntohl(*(u32 *) ((struct sk_buff *) R6->data + src + imm)) + +Appendix +======== + +For reference, the following table lists legacy Linux-specific opcodes in order by value. + +====== ==== =================================================== ============= +opcode imm description reference +====== ==== =================================================== ============= +0x20 any dst = ntohl(\*(uint32_t \*)(R6->data + imm)) `Legacy BPF Packet access instructions`_ +0x28 any dst = ntohs(\*(uint16_t \*)(R6->data + imm)) `Legacy BPF Packet access instructions`_ +0x30 any dst = (\*(uint8_t \*)(R6->data + imm)) `Legacy BPF Packet access instructions`_ +0x38 any dst = ntohll(\*(uint64_t \*)(R6->data + imm)) `Legacy BPF Packet access instructions`_ +0x40 any dst = ntohl(\*(uint32_t \*)(R6->data + src + imm)) `Legacy BPF Packet access instructions`_ +0x48 any dst = ntohs(\*(uint16_t \*)(R6->data + src + imm)) `Legacy BPF Packet access instructions`_ +0x50 any dst = \*(uint8_t \*)(R6->data + src + imm)) `Legacy BPF Packet access instructions`_ +0x58 any dst = ntohll(\*(uint64_t \*)(R6->data + src + imm)) `Legacy BPF Packet access instructions`_ From d6c2740f5d0c3b8dee03fe9a03e202bf6314c7cd Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Wed, 14 Sep 2022 10:36:58 +0100 Subject: [PATCH 04/25] Feedback from Shung-Hsi Yu Note that imm is signed Fix typo in Appendix Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index 6910e7c..eec7768 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -76,7 +76,7 @@ imm offset src dst opcode ============= ======= =============== ==================== ============ imm - integer immediate value + signed integer immediate value offset signed integer offset used with pointer arithmetic @@ -648,7 +648,7 @@ opcode imm description reference 0xd4 0x40 dst = htole64(dst) `Byte swap instructions`_ 0xd5 any if dst s<= imm goto +offset `Jump instructions`_ 0xd6 any if (int32_t)dst s<= (int32_t)imm goto +offset `Jump instructions`_ -0xc3 0x00 lock \*(uint64_t \*)(dst + offset) += src `Atomic operations`_ +0xdb 0x00 lock \*(uint64_t \*)(dst + offset) += src `Atomic operations`_ 0xdb 0x01 lock:: `Atomic operations`_ *(uint64_t *)(dst + offset) += src From 874fb82a6e6e9bd75e44d7e31fb6404e4d0916dc Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Wed, 14 Sep 2022 10:58:29 +0100 Subject: [PATCH 05/25] Add note about invalid instruction 0x8d used by clang -O0 As reported by Shung-Hsi Yu Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index eec7768..a60e636 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -327,6 +327,14 @@ with the remaining registers being ignored. The definition of a helper function is responsible for specifying the type (e.g., integer, pointer, etc.) of the value returned, the number of arguments, and the type of each argument. +Note that ``BPF_CALL | BPF_X | BPF_JMP`` (0x8d), where the helper function integer +would be read from a specified register, is not currently permitted. + + **Note** + + *Clang implementation*: + Clang will generate this invalid instruction if ``-O0`` is used. + Load and store instructions =========================== From 31e6a1c425752c88910070354bb88f566bb18a57 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Wed, 14 Sep 2022 12:19:47 +0100 Subject: [PATCH 06/25] Add src column to Appendix table In preparation for adding instructions that use it Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 380 ++++++++++++++--------------- 1 file changed, 190 insertions(+), 190 deletions(-) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index a60e636..6f2cf10 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -503,193 +503,193 @@ Appendix For reference, the following table lists opcodes in order by value. -====== ==== =================================================== ============= -opcode imm description reference -====== ==== =================================================== ============= -0x04 any dst = (uint32_t)(dst + imm) `Arithmetic instructions`_ -0x05 0x00 goto +offset `Jump instructions`_ -0x07 any dst += imm `Arithmetic instructions`_ -0x0c 0x00 dst = (uint32_t)(dst + src) `Arithmetic instructions`_ -0x0f 0x00 dst += src `Arithmetic instructions`_ -0x14 any dst = (uint32_t)(dst - imm) `Arithmetic instructions`_ -0x15 any if dst == imm goto +offset `Jump instructions`_ -0x16 any if (uint32_t)dst == imm goto +offset `Jump instructions`_ -0x17 any dst -= imm `Arithmetic instructions`_ -0x18 any dst = imm `Load and store instructions`_ -0x1c 0x00 dst = (uint32_t)(dst - src) `Arithmetic instructions`_ -0x1d 0x00 if dst == src goto +offset `Jump instructions`_ -0x1e 0x00 if (uint32_t)dst == (uint32_t)src goto +offset `Jump instructions`_ -0x1f 0x00 dst -= src `Arithmetic instructions`_ -0x20 any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ -0x24 any dst = (uint32_t)(dst \* imm) `Arithmetic instructions`_ -0x25 any if dst > imm goto +offset `Jump instructions`_ -0x26 any if (uint32_t)dst > imm goto +offset `Jump instructions`_ -0x27 any dst \*= imm `Arithmetic instructions`_ -0x28 any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ -0x2c 0x00 dst = (uint32_t)(dst \* src) `Arithmetic instructions`_ -0x2d 0x00 if dst > src goto +offset `Jump instructions`_ -0x2e 0x00 if (uint32_t)dst > (uint32_t)src goto +offset `Jump instructions`_ -0x2f 0x00 dst \*= src `Arithmetic instructions`_ -0x30 any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ -0x34 any dst = (uint32_t)((imm != 0) ? (dst / imm) : 0) `Arithmetic instructions`_ -0x35 any if dst >= imm goto +offset `Jump instructions`_ -0x36 any if (uint32_t)dst >= imm goto +offset `Jump instructions`_ -0x37 any dst = (imm != 0) ? (dst / imm) : 0 `Arithmetic instructions`_ -0x38 any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ -0x3c 0x00 dst = (uint32_t)((imm != 0) ? (dst / src) : 0) `Arithmetic instructions`_ -0x3d 0x00 if dst >= src goto +offset `Jump instructions`_ -0x3e 0x00 if (uint32_t)dst >= (uint32_t)src goto +offset `Jump instructions`_ -0x3f 0x00 dst = (src !+ 0) ? (dst / src) : 0 `Arithmetic instructions`_ -0x40 any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ -0x44 any dst = (uint32_t)(dst \| imm) `Arithmetic instructions`_ -0x45 any if dst & imm goto +offset `Jump instructions`_ -0x46 any if (uint32_t)dst & imm goto +offset `Jump instructions`_ -0x47 any dst \|= imm `Arithmetic instructions`_ -0x48 any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ -0x4c 0x00 dst = (uint32_t)(dst \| src) `Arithmetic instructions`_ -0x4d 0x00 if dst & src goto +offset `Jump instructions`_ -0x4e 0x00 if (uint32_t)dst & (uint32_t)src goto +offset `Jump instructions`_ -0x4f 0x00 dst \|= src `Arithmetic instructions`_ -0x50 any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ -0x54 any dst = (uint32_t)(dst & imm) `Arithmetic instructions`_ -0x55 any if dst != imm goto +offset `Jump instructions`_ -0x56 any if (uint32_t)dst != imm goto +offset `Jump instructions`_ -0x57 any dst &= imm `Arithmetic instructions`_ -0x58 any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ -0x5c 0x00 dst = (uint32_t)(dst & src) `Arithmetic instructions`_ -0x5d 0x00 if dst != src goto +offset `Jump instructions`_ -0x5e 0x00 if (uint32_t)dst != (uint32_t)src goto +offset `Jump instructions`_ -0x5f 0x00 dst &= src `Arithmetic instructions`_ -0x61 0x00 dst = \*(uint32_t \*)(src + offset) `Load and store instructions`_ -0x62 any \*(uint32_t \*)(dst + offset) = imm `Load and store instructions`_ -0x63 0x00 \*(uint32_t \*)(dst + offset) = src `Load and store instructions`_ -0x64 any dst = (uint32_t)(dst << imm) `Arithmetic instructions`_ -0x65 any if dst s> imm goto +offset `Jump instructions`_ -0x66 any if (int32_t)dst s> (int32_t)imm goto +offset `Jump instructions`_ -0x67 any dst <<= imm `Arithmetic instructions`_ -0x69 0x00 dst = \*(uint16_t \*)(src + offset) `Load and store instructions`_ -0x6a any \*(uint16_t \*)(dst + offset) = imm `Load and store instructions`_ -0x6b 0x00 \*(uint16_t \*)(dst + offset) = src `Load and store instructions`_ -0x6c 0x00 dst = (uint32_t)(dst << src) `Arithmetic instructions`_ -0x6d 0x00 if dst s> src goto +offset `Jump instructions`_ -0x6e 0x00 if (int32_t)dst s> (int32_t)src goto +offset `Jump instructions`_ -0x6f 0x00 dst <<= src `Arithmetic instructions`_ -0x71 0x00 dst = \*(uint8_t \*)(src + offset) `Load and store instructions`_ -0x72 any \*(uint8_t \*)(dst + offset) = imm `Load and store instructions`_ -0x73 0x00 \*(uint8_t \*)(dst + offset) = src `Load and store instructions`_ -0x74 any dst = (uint32_t)(dst >> imm) `Arithmetic instructions`_ -0x75 any if dst s>= imm goto +offset `Jump instructions`_ -0x76 any if (int32_t)dst s>= (int32_t)imm goto +offset `Jump instructions`_ -0x77 any dst >>= imm `Arithmetic instructions`_ -0x79 0x00 dst = \*(uint64_t \*)(src + offset) `Load and store instructions`_ -0x7a any \*(uint64_t \*)(dst + offset) = imm `Load and store instructions`_ -0x7b 0x00 \*(uint64_t \*)(dst + offset) = src `Load and store instructions`_ -0x7c 0x00 dst = (uint32_t)(dst >> src) `Arithmetic instructions`_ -0x7d 0x00 if dst s>= src goto +offset `Jump instructions`_ -0x7e 0x00 if (int32_t)dst s>= (int32_t)src goto +offset `Jump instructions`_ -0x7f 0x00 dst >>= src `Arithmetic instructions`_ -0x84 0x00 dst = (uint32_t)-dst `Arithmetic instructions`_ -0x85 any call imm `Jump instructions`_ -0x87 0x00 dst = -dst `Arithmetic instructions`_ -0x94 any dst = (uint32_t)((imm != 0) ? (dst % imm) : imm) `Arithmetic instructions`_ -0x95 0x00 return `Jump instructions`_ -0x97 any dst = (imm != 0) ? (dst % imm) : imm `Arithmetic instructions`_ -0x9c 0x00 dst = (uint32_t)((src != 0) ? (dst % src) : src) `Arithmetic instructions`_ -0x9f 0x00 dst = (src != 0) ? (dst % src) : src `Arithmetic instructions`_ -0xa4 any dst = (uint32_t)(dst ^ imm) `Arithmetic instructions`_ -0xa5 any if dst < imm goto +offset `Jump instructions`_ -0xa6 any if (uint32_t)dst < imm goto +offset `Jump instructions`_ -0xa7 any dst ^= imm `Arithmetic instructions`_ -0xac 0x00 dst = (uint32_t)(dst ^ src) `Arithmetic instructions`_ -0xad 0x00 if dst < src goto +offset `Jump instructions`_ -0xae 0x00 if (uint32_t)dst < (uint32_t)src goto +offset `Jump instructions`_ -0xaf 0x00 dst ^= src `Arithmetic instructions`_ -0xb4 any dst = (uint32_t) imm `Arithmetic instructions`_ -0xb5 any if dst <= imm goto +offset `Jump instructions`_ -0xa6 any if (uint32_t)dst <= imm goto +offset `Jump instructions`_ -0xb7 any dst = imm `Arithmetic instructions`_ -0xbc 0x00 dst = (uint32_t) src `Arithmetic instructions`_ -0xbd 0x00 if dst <= src goto +offset `Jump instructions`_ -0xbe 0x00 if (uint32_t)dst <= (uint32_t)src goto +offset `Jump instructions`_ -0xbf 0x00 dst = src `Arithmetic instructions`_ -0xc3 0x00 lock \*(uint32_t \*)(dst + offset) += src `Atomic operations`_ -0xc3 0x01 lock:: `Atomic operations`_ - - *(uint32_t *)(dst + offset) += src - src = *(uint32_t *)(dst + offset) -0xc3 0x40 \*(uint32_t \*)(dst + offset) \|= src `Atomic operations`_ -0xc3 0x41 lock:: `Atomic operations`_ - - *(uint32_t *)(dst + offset) |= src - src = *(uint32_t *)(dst + offset) -0xc3 0x50 \*(uint32_t \*)(dst + offset) &= src `Atomic operations`_ -0xc3 0x51 lock:: `Atomic operations`_ - - *(uint32_t *)(dst + offset) &= src - src = *(uint32_t *)(dst + offset) -0xc3 0xa0 \*(uint32_t \*)(dst + offset) ^= src `Atomic operations`_ -0xc3 0xa1 lock:: `Atomic operations`_ - - *(uint32_t *)(dst + offset) ^= src - src = *(uint32_t *)(dst + offset) -0xc3 0xe1 lock:: `Atomic operations`_ - - temp = *(uint32_t *)(dst + offset) - *(uint32_t *)(dst + offset) = src - src = temp -0xc3 0xf1 lock:: `Atomic operations`_ - - temp = *(uint32_t *)(dst + offset) - if *(uint32_t)(dst + offset) == R0 - *(uint32_t)(dst + offset) = src - R0 = temp -0xc4 any dst = (uint32_t)(dst s>> imm) `Arithmetic instructions`_ -0xc5 any if dst s< imm goto +offset `Jump instructions`_ -0xc6 any if (int32_t)dst s< (int32_t)imm goto +offset `Jump instructions`_ -0xc7 any dst s>>= imm `Arithmetic instructions`_ -0xcc 0x00 dst = (uint32_t)(dst s>> src) `Arithmetic instructions`_ -0xcd 0x00 if dst s< src goto +offset `Jump instructions`_ -0xce 0x00 if (int32_t)dst s< (int32_t)src goto +offset `Jump instructions`_ -0xcf 0x00 dst s>>= src `Arithmetic instructions`_ -0xd4 0x10 dst = htole16(dst) `Byte swap instructions`_ -0xd4 0x20 dst = htole32(dst) `Byte swap instructions`_ -0xd4 0x40 dst = htole64(dst) `Byte swap instructions`_ -0xd5 any if dst s<= imm goto +offset `Jump instructions`_ -0xd6 any if (int32_t)dst s<= (int32_t)imm goto +offset `Jump instructions`_ -0xdb 0x00 lock \*(uint64_t \*)(dst + offset) += src `Atomic operations`_ -0xdb 0x01 lock:: `Atomic operations`_ - - *(uint64_t *)(dst + offset) += src - src = *(uint64_t *)(dst + offset) -0xdb 0x40 \*(uint64_t \*)(dst + offset) \|= src `Atomic operations`_ -0xdb 0x41 lock:: `Atomic operations`_ - - *(uint64_t *)(dst + offset) |= src - lock src = *(uint64_t *)(dst + offset) -0xdb 0x50 \*(uint64_t \*)(dst + offset) &= src `Atomic operations`_ -0xdb 0x51 lock:: `Atomic operations`_ - - *(uint64_t *)(dst + offset) &= src - src = *(uint64_t *)(dst + offset) -0xdb 0xa0 \*(uint64_t \*)(dst + offset) ^= src `Atomic operations`_ -0xdb 0xa1 lock:: `Atomic operations`_ - - *(uint64_t *)(dst + offset) ^= src - src = *(uint64_t *)(dst + offset) -0xdb 0xe1 lock:: `Atomic operations`_ - - temp = *(uint64_t *)(dst + offset) - *(uint64_t *)(dst + offset) = src - src = temp -0xdb 0xf1 lock:: `Atomic operations`_ - - temp = *(uint64_t *)(dst + offset) - if *(uint64_t)(dst + offset) == R0 - *(uint64_t)(dst + offset) = src - R0 = temp -0xdc 0x10 dst = htobe16(dst) `Byte swap instructions`_ -0xdc 0x20 dst = htobe32(dst) `Byte swap instructions`_ -0xdc 0x40 dst = htobe64(dst) `Byte swap instructions`_ -0xdd 0x00 if dst s<= src goto +offset `Jump instructions`_ -0xde 0x00 if (int32_t)dst s<= (int32_t)src goto +offset `Jump instructions`_ -====== ==== =================================================== ============= +====== ==== ==== =================================================== ======================================== +opcode imm src description reference +====== ==== ==== =================================================== ======================================== +0x04 any 0x00 dst = (uint32_t)(dst + imm) `Arithmetic instructions`_ +0x05 0x00 0x00 goto +offset `Jump instructions`_ +0x07 any 0x00 dst += imm `Arithmetic instructions`_ +0x0c 0x00 any dst = (uint32_t)(dst + src) `Arithmetic instructions`_ +0x0f 0x00 any dst += src `Arithmetic instructions`_ +0x14 any 0x00 dst = (uint32_t)(dst - imm) `Arithmetic instructions`_ +0x15 any 0x00 if dst == imm goto +offset `Jump instructions`_ +0x16 any 0x00 if (uint32_t)dst == imm goto +offset `Jump instructions`_ +0x17 any 0x00 dst -= imm `Arithmetic instructions`_ +0x18 0x00 0x00 dst = imm64 `Load and store instructions`_ +0x1c 0x00 any dst = (uint32_t)(dst - src) `Arithmetic instructions`_ +0x1d 0x00 any if dst == src goto +offset `Jump instructions`_ +0x1e 0x00 any if (uint32_t)dst == (uint32_t)src goto +offset `Jump instructions`_ +0x1f 0x00 any dst -= src `Arithmetic instructions`_ +0x20 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ +0x24 any 0x00 dst = (uint32_t)(dst \* imm) `Arithmetic instructions`_ +0x25 any 0x00 if dst > imm goto +offset `Jump instructions`_ +0x26 any 0x00 if (uint32_t)dst > imm goto +offset `Jump instructions`_ +0x27 any 0x00 dst \*= imm `Arithmetic instructions`_ +0x28 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ +0x2c 0x00 any dst = (uint32_t)(dst \* src) `Arithmetic instructions`_ +0x2d 0x00 any if dst > src goto +offset `Jump instructions`_ +0x2e 0x00 any if (uint32_t)dst > (uint32_t)src goto +offset `Jump instructions`_ +0x2f 0x00 any dst \*= src `Arithmetic instructions`_ +0x30 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ +0x34 any 0x00 dst = (uint32_t)((imm != 0) ? (dst / imm) : 0) `Arithmetic instructions`_ +0x35 any 0x00 if dst >= imm goto +offset `Jump instructions`_ +0x36 any 0x00 if (uint32_t)dst >= imm goto +offset `Jump instructions`_ +0x37 any 0x00 dst = (imm != 0) ? (dst / imm) : 0 `Arithmetic instructions`_ +0x38 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ +0x3c 0x00 any dst = (uint32_t)((imm != 0) ? (dst / src) : 0) `Arithmetic instructions`_ +0x3d 0x00 any if dst >= src goto +offset `Jump instructions`_ +0x3e 0x00 any if (uint32_t)dst >= (uint32_t)src goto +offset `Jump instructions`_ +0x3f 0x00 any dst = (src !+ 0) ? (dst / src) : 0 `Arithmetic instructions`_ +0x40 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ +0x44 any 0x00 dst = (uint32_t)(dst \| imm) `Arithmetic instructions`_ +0x45 any 0x00 if dst & imm goto +offset `Jump instructions`_ +0x46 any 0x00 if (uint32_t)dst & imm goto +offset `Jump instructions`_ +0x47 any 0x00 dst \|= imm `Arithmetic instructions`_ +0x48 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ +0x4c 0x00 any dst = (uint32_t)(dst \| src) `Arithmetic instructions`_ +0x4d 0x00 any if dst & src goto +offset `Jump instructions`_ +0x4e 0x00 any if (uint32_t)dst & (uint32_t)src goto +offset `Jump instructions`_ +0x4f 0x00 any dst \|= src `Arithmetic instructions`_ +0x50 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ +0x54 any 0x00 dst = (uint32_t)(dst & imm) `Arithmetic instructions`_ +0x55 any 0x00 if dst != imm goto +offset `Jump instructions`_ +0x56 any 0x00 if (uint32_t)dst != imm goto +offset `Jump instructions`_ +0x57 any 0x00 dst &= imm `Arithmetic instructions`_ +0x58 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ +0x5c 0x00 any dst = (uint32_t)(dst & src) `Arithmetic instructions`_ +0x5d 0x00 any if dst != src goto +offset `Jump instructions`_ +0x5e 0x00 any if (uint32_t)dst != (uint32_t)src goto +offset `Jump instructions`_ +0x5f 0x00 any dst &= src `Arithmetic instructions`_ +0x61 0x00 any dst = \*(uint32_t \*)(src + offset) `Load and store instructions`_ +0x62 any 0x00 \*(uint32_t \*)(dst + offset) = imm `Load and store instructions`_ +0x63 0x00 any \*(uint32_t \*)(dst + offset) = src `Load and store instructions`_ +0x64 any 0x00 dst = (uint32_t)(dst << imm) `Arithmetic instructions`_ +0x65 any 0x00 if dst s> imm goto +offset `Jump instructions`_ +0x66 any 0x00 if (int32_t)dst s> (int32_t)imm goto +offset `Jump instructions`_ +0x67 any 0x00 dst <<= imm `Arithmetic instructions`_ +0x69 0x00 any dst = \*(uint16_t \*)(src + offset) `Load and store instructions`_ +0x6a any 0x00 \*(uint16_t \*)(dst + offset) = imm `Load and store instructions`_ +0x6b 0x00 any \*(uint16_t \*)(dst + offset) = src `Load and store instructions`_ +0x6c 0x00 any dst = (uint32_t)(dst << src) `Arithmetic instructions`_ +0x6d 0x00 any if dst s> src goto +offset `Jump instructions`_ +0x6e 0x00 any if (int32_t)dst s> (int32_t)src goto +offset `Jump instructions`_ +0x6f 0x00 any dst <<= src `Arithmetic instructions`_ +0x71 0x00 any dst = \*(uint8_t \*)(src + offset) `Load and store instructions`_ +0x72 any 0x00 \*(uint8_t \*)(dst + offset) = imm `Load and store instructions`_ +0x73 0x00 any \*(uint8_t \*)(dst + offset) = src `Load and store instructions`_ +0x74 any 0x00 dst = (uint32_t)(dst >> imm) `Arithmetic instructions`_ +0x75 any 0x00 if dst s>= imm goto +offset `Jump instructions`_ +0x76 any 0x00 if (int32_t)dst s>= (int32_t)imm goto +offset `Jump instructions`_ +0x77 any 0x00 dst >>= imm `Arithmetic instructions`_ +0x79 0x00 any dst = \*(uint64_t \*)(src + offset) `Load and store instructions`_ +0x7a any 0x00 \*(uint64_t \*)(dst + offset) = imm `Load and store instructions`_ +0x7b 0x00 any \*(uint64_t \*)(dst + offset) = src `Load and store instructions`_ +0x7c 0x00 any dst = (uint32_t)(dst >> src) `Arithmetic instructions`_ +0x7d 0x00 any if dst s>= src goto +offset `Jump instructions`_ +0x7e 0x00 any if (int32_t)dst s>= (int32_t)src goto +offset `Jump instructions`_ +0x7f 0x00 any dst >>= src `Arithmetic instructions`_ +0x84 0x00 0x00 dst = (uint32_t)-dst `Arithmetic instructions`_ +0x85 any 0x00 call imm `Jump instructions`_ +0x87 0x00 0x00 dst = -dst `Arithmetic instructions`_ +0x94 any 0x00 dst = (uint32_t)((imm != 0) ? (dst % imm) : imm) `Arithmetic instructions`_ +0x95 0x00 0x00 return `Jump instructions`_ +0x97 any 0x00 dst = (imm != 0) ? (dst % imm) : imm `Arithmetic instructions`_ +0x9c 0x00 any dst = (uint32_t)((src != 0) ? (dst % src) : src) `Arithmetic instructions`_ +0x9f 0x00 any dst = (src != 0) ? (dst % src) : src `Arithmetic instructions`_ +0xa4 any 0x00 dst = (uint32_t)(dst ^ imm) `Arithmetic instructions`_ +0xa5 any 0x00 if dst < imm goto +offset `Jump instructions`_ +0xa6 any 0x00 if (uint32_t)dst < imm goto +offset `Jump instructions`_ +0xa7 any 0x00 dst ^= imm `Arithmetic instructions`_ +0xac 0x00 any dst = (uint32_t)(dst ^ src) `Arithmetic instructions`_ +0xad 0x00 any if dst < src goto +offset `Jump instructions`_ +0xae 0x00 any if (uint32_t)dst < (uint32_t)src goto +offset `Jump instructions`_ +0xaf 0x00 any dst ^= src `Arithmetic instructions`_ +0xb4 any 0x00 dst = (uint32_t) imm `Arithmetic instructions`_ +0xb5 any 0x00 if dst <= imm goto +offset `Jump instructions`_ +0xa6 any 0x00 if (uint32_t)dst <= imm goto +offset `Jump instructions`_ +0xb7 any 0x00 dst = imm `Arithmetic instructions`_ +0xbc 0x00 any dst = (uint32_t) src `Arithmetic instructions`_ +0xbd 0x00 any if dst <= src goto +offset `Jump instructions`_ +0xbe 0x00 any if (uint32_t)dst <= (uint32_t)src goto +offset `Jump instructions`_ +0xbf 0x00 any dst = src `Arithmetic instructions`_ +0xc3 0x00 any lock \*(uint32_t \*)(dst + offset) += src `Atomic operations`_ +0xc3 0x01 any lock:: `Atomic operations`_ + + *(uint32_t *)(dst + offset) += src + src = *(uint32_t *)(dst + offset) +0xc3 0x40 any \*(uint32_t \*)(dst + offset) \|= src `Atomic operations`_ +0xc3 0x41 any lock:: `Atomic operations`_ + + *(uint32_t *)(dst + offset) |= src + src = *(uint32_t *)(dst + offset) +0xc3 0x50 any \*(uint32_t \*)(dst + offset) &= src `Atomic operations`_ +0xc3 0x51 any lock:: `Atomic operations`_ + + *(uint32_t *)(dst + offset) &= src + src = *(uint32_t *)(dst + offset) +0xc3 0xa0 any \*(uint32_t \*)(dst + offset) ^= src `Atomic operations`_ +0xc3 0xa1 any lock:: `Atomic operations`_ + + *(uint32_t *)(dst + offset) ^= src + src = *(uint32_t *)(dst + offset) +0xc3 0xe1 any lock:: `Atomic operations`_ + + temp = *(uint32_t *)(dst + offset) + *(uint32_t *)(dst + offset) = src + src = temp +0xc3 0xf1 any lock:: `Atomic operations`_ + + temp = *(uint32_t *)(dst + offset) + if *(uint32_t)(dst + offset) == R0 + *(uint32_t)(dst + offset) = src + R0 = temp +0xc4 any 0x00 dst = (uint32_t)(dst s>> imm) `Arithmetic instructions`_ +0xc5 any 0x00 if dst s< imm goto +offset `Jump instructions`_ +0xc6 any 0x00 if (int32_t)dst s< (int32_t)imm goto +offset `Jump instructions`_ +0xc7 any 0x00 dst s>>= imm `Arithmetic instructions`_ +0xcc 0x00 any dst = (uint32_t)(dst s>> src) `Arithmetic instructions`_ +0xcd 0x00 any if dst s< src goto +offset `Jump instructions`_ +0xce 0x00 any if (int32_t)dst s< (int32_t)src goto +offset `Jump instructions`_ +0xcf 0x00 any dst s>>= src `Arithmetic instructions`_ +0xd4 0x10 0x00 dst = htole16(dst) `Byte swap instructions`_ +0xd4 0x20 0x00 dst = htole32(dst) `Byte swap instructions`_ +0xd4 0x40 0x00 dst = htole64(dst) `Byte swap instructions`_ +0xd5 any 0x00 if dst s<= imm goto +offset `Jump instructions`_ +0xd6 any 0x00 if (int32_t)dst s<= (int32_t)imm goto +offset `Jump instructions`_ +0xdb 0x00 any lock \*(uint64_t \*)(dst + offset) += src `Atomic operations`_ +0xdb 0x01 any lock:: `Atomic operations`_ + + *(uint64_t *)(dst + offset) += src + src = *(uint64_t *)(dst + offset) +0xdb 0x40 any \*(uint64_t \*)(dst + offset) \|= src `Atomic operations`_ +0xdb 0x41 any lock:: `Atomic operations`_ + + *(uint64_t *)(dst + offset) |= src + lock src = *(uint64_t *)(dst + offset) +0xdb 0x50 any \*(uint64_t \*)(dst + offset) &= src `Atomic operations`_ +0xdb 0x51 any lock:: `Atomic operations`_ + + *(uint64_t *)(dst + offset) &= src + src = *(uint64_t *)(dst + offset) +0xdb 0xa0 any \*(uint64_t \*)(dst + offset) ^= src `Atomic operations`_ +0xdb 0xa1 any lock:: `Atomic operations`_ + + *(uint64_t *)(dst + offset) ^= src + src = *(uint64_t *)(dst + offset) +0xdb 0xe1 any lock:: `Atomic operations`_ + + temp = *(uint64_t *)(dst + offset) + *(uint64_t *)(dst + offset) = src + src = temp +0xdb 0xf1 any lock:: `Atomic operations`_ + + temp = *(uint64_t *)(dst + offset) + if *(uint64_t)(dst + offset) == R0 + *(uint64_t)(dst + offset) = src + R0 = temp +0xdc 0x10 0x00 dst = htobe16(dst) `Byte swap instructions`_ +0xdc 0x20 0x00 dst = htobe32(dst) `Byte swap instructions`_ +0xdc 0x40 0x00 dst = htobe64(dst) `Byte swap instructions`_ +0xdd 0x00 any if dst s<= src goto +offset `Jump instructions`_ +0xde 0x00 any if (int32_t)dst s<= (int32_t)src goto +offset `Jump instructions`_ +====== ==== ==== =================================================== ======================================== From 22b3a5b516052c7f4dc99bf97c2bbcb85654df85 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Wed, 14 Sep 2022 17:14:45 +0100 Subject: [PATCH 07/25] Fix construction of imm64 Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 34 +++++++++++++++++++----------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index 6f2cf10..bb6a866 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -67,7 +67,8 @@ eBPF has two instruction encodings: * the wide instruction encoding, which appends a second 64-bit immediate (i.e., constant) value after the basic instruction for a total of 128 bits. -The basic instruction encoding is as follows: +The basic instruction encoding is as follows, where MSB and LSB mean the most significant +bits and least significant bits, respectively: ============= ======= =============== ==================== ============ 32 bits (MSB) 16 bits 4 bits 4 bits 8 bits (LSB) @@ -82,7 +83,8 @@ offset signed integer offset used with pointer arithmetic src - source register number (0-10) + the source register number (0-10), except where otherwise specified + (`64-bit immediate instructions`_ reuse this field for other purposes) dst destination register number (0-10) @@ -93,17 +95,24 @@ opcode Note that most instructions do not use all of the fields. Unused fields must be set to zero. -As discussed below in `64-bit immediate instructions`_, some basic -instructions denote that a 64-bit immediate value follows. Thus -the wide instruction encoding is as follows: +As discussed below in `64-bit immediate instructions`_, some +instructions use a 64-bit immediate value that is constructed as follows. +The 64 bits following the basic instruction contain a pseudo instruction +using the same format but with opcode, dst, src, and offset all set to zero, +and imm containing the high 32 bits of the immediate value. -================= ============= +================= ================== 64 bits (MSB) 64 bits (LSB) -================= ============= -basic instruction imm64 -================= ============= +================= ================== +basic instruction pseudo instruction +================= ================== -where MSB and LSB mean the most significant bits and least significant bits, respectively. +Thus the 64-bit immediate value is constructed as follows: + + imm64 = imm + (imm_high << 32); + +where 'imm_high' refers to the imm value of the pseudo instruction +following the basic instruction. In the remainder of this document 'src' and 'dst' refer to the values of the source and destination registers, respectively, rather than the register number. @@ -478,7 +487,7 @@ and loaded back to ``R0``. ----------------------------- Instructions with the ``BPF_IMM`` 'mode' modifier use the wide instruction -encoding for an extra imm64 value. +encoding defined in `Instruction encoding`_. There is currently only one such instruction. @@ -506,6 +515,7 @@ For reference, the following table lists opcodes in order by value. ====== ==== ==== =================================================== ======================================== opcode imm src description reference ====== ==== ==== =================================================== ======================================== +0x00 any 0x00 (additional immediate value) `64-bit immediate instructions`_ 0x04 any 0x00 dst = (uint32_t)(dst + imm) `Arithmetic instructions`_ 0x05 0x00 0x00 goto +offset `Jump instructions`_ 0x07 any 0x00 dst += imm `Arithmetic instructions`_ @@ -515,7 +525,7 @@ opcode imm src description referen 0x15 any 0x00 if dst == imm goto +offset `Jump instructions`_ 0x16 any 0x00 if (uint32_t)dst == imm goto +offset `Jump instructions`_ 0x17 any 0x00 dst -= imm `Arithmetic instructions`_ -0x18 0x00 0x00 dst = imm64 `Load and store instructions`_ +0x18 0x00 0x00 dst = imm64 `64-bit immediate instructions`_ 0x1c 0x00 any dst = (uint32_t)(dst - src) `Arithmetic instructions`_ 0x1d 0x00 any if dst == src goto +offset `Jump instructions`_ 0x1e 0x00 any if (uint32_t)dst == (uint32_t)src goto +offset `Jump instructions`_ From 712a32d3163c363da2696bf8c1d3e4aff4639671 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Wed, 14 Sep 2022 18:42:42 +0100 Subject: [PATCH 08/25] Add additional 0x18 opcodes by src value Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 68 +++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 7 deletions(-) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index bb6a866..77df268 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -109,9 +109,9 @@ basic instruction pseudo instruction Thus the 64-bit immediate value is constructed as follows: - imm64 = imm + (imm_high << 32); + imm64 = imm + (next_imm << 32) -where 'imm_high' refers to the imm value of the pseudo instruction +where 'next_imm' refers to the imm value of the pseudo instruction following the basic instruction. In the remainder of this document 'src' and 'dst' refer to the values of the source @@ -217,7 +217,7 @@ Examples: ``BPF_ADD | BPF_X | BPF_ALU`` (0x0c) means:: - dst = (uint32_t) (dst + src); + dst = (uint32_t) (dst + src) where '(uint32_t)' indicates truncation to 32 bits. @@ -487,14 +487,62 @@ and loaded back to ``R0``. ----------------------------- Instructions with the ``BPF_IMM`` 'mode' modifier use the wide instruction -encoding defined in `Instruction encoding`_. +encoding defined in `Instruction encoding`_, and use the 'src' field of the +basic instruction to hold an opcode subtype. + +The following instructions are defined, and use additional concepts defined below: + +========================= ====== ==== ===================================== =========== ============== +opcode construction opcode src pseudocode imm type dst type +========================= ====== ==== ===================================== =========== ============== +BPF_IMM | BPF_DW | BPF_LD 0x18 0x00 dst = imm64 integer integer +BPF_IMM | BPF_DW | BPF_LD 0x18 0x01 dst = map_by_fd(imm) map fd map +BPF_IMM | BPF_DW | BPF_LD 0x18 0x02 dst = mva(map_by_fd(imm)) + next_imm map fd data pointer +BPF_IMM | BPF_DW | BPF_LD 0x18 0x03 dst = variable_addr(imm) variable id data pointer +BPF_IMM | BPF_DW | BPF_LD 0x18 0x04 dst = code_addr(imm) integer code pointer +BPF_IMM | BPF_DW | BPF_LD 0x18 0x05 dst = mva(map_by_idx(imm)) map index map +BPF_IMM | BPF_DW | BPF_LD 0x18 0x06 dst = mva(map_by_idx(imm)) + next_imm map index data pointer +========================= ====== ==== ===================================== =========== ============== -There is currently only one such instruction. +where + +* map_by_fd(fd) means to convert a 32-bit POSIX file descriptor into an address of a map object (see `Map objects`_) +* map_by_index(index) means to convert a 32-bit index into an address of a map object +* mva(map) gets the address of the memory region expressed by a given map object +* variable_addr(id) gets the address of a variable (see `Variables`_) with a given id +* code_addr(offset) gets the address of the instruction at a specified relative offset in units of 64-bit blocks +* the 'imm type' can be used by disassemblers for display +* the 'dst type' can be used for verification and JIT compilation purposes + +Map objects +~~~~~~~~~~~ + +Maps are shared memory regions accessible by eBPF programs on some platforms, where we use the term "map object" +to refer to an object containing the data and metadata (e.g., size) about the memory region. +A map can have various semantics as defined in a separate document, and may or may not have a single +contiguous memory region, but the 'mva(map)' is currently only defined for maps that do have a single +contiguous memory region. Support for maps is optional. + + **Note** + + *Linux implementation*: Linux only supports the 'mva(map)' operation on array maps with a single element. + +Each map object can have a POSIX file descriptor (fd) if supported by the platform, +where 'map_by_fd(fd)' means to get the map with the specified file descriptor. +Each eBPF program can also be defined to use a set of maps associated with the program +at load time, and 'map_by_index(index)' means to get the map with the given index in the set +associated with the eBPF program containing the instruction. -``BPF_IMM | BPF_DW | BPF_LD`` (0x18) means:: +Variables +~~~~~~~~~ - dst = imm64 +Variables are memory regions, identified by integer ids, accessible by eBPF programs on +some platforms. The 'variable_addr(id)' operation means to get the address of the memory region +identified by the given id. Support for such variables is optional. + + **Note** + *Linux implementation*: Linux uses BTF ids to identify variables. Legacy BPF Packet access instructions ------------------------------------- @@ -526,6 +574,12 @@ opcode imm src description referen 0x16 any 0x00 if (uint32_t)dst == imm goto +offset `Jump instructions`_ 0x17 any 0x00 dst -= imm `Arithmetic instructions`_ 0x18 0x00 0x00 dst = imm64 `64-bit immediate instructions`_ +0x18 0x00 0x01 dst = map_by_fd(imm) `64-bit immediate instructions`_ +0x18 0x00 0x02 dst = mva(map_by_fd(imm)) + next_imm `64-bit immediate instructions`_ +0x18 0x00 0x03 dst = variable_addr(imm) `64-bit immediate instructions`_ +0x18 0x00 0x04 dst = code_addr(imm) `64-bit immediate instructions`_ +0x18 0x00 0x05 dst = mva(map_by_idx(imm)) `64-bit immediate instructions`_ +0x18 0x00 0x06 dst = mva(map_by_idx(imm)) + next_imm `64-bit immediate instructions`_ 0x1c 0x00 any dst = (uint32_t)(dst - src) `Arithmetic instructions`_ 0x1d 0x00 any if dst == src goto +offset `Jump instructions`_ 0x1e 0x00 any if (uint32_t)dst == (uint32_t)src goto +offset `Jump instructions`_ From bfb4831411a62716bc34d91c8108449079d452c8 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Fri, 16 Sep 2022 01:25:53 +0100 Subject: [PATCH 09/25] Minor cleanup Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 422 ++++++++++++++--------------- 1 file changed, 211 insertions(+), 211 deletions(-) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index 77df268..ec27f2a 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -54,7 +54,7 @@ and/or metadata. *Linux implementation*: In the Linux kernel, all program types only use R1 which contains the "context", which is typically a structure containing all - the inputs needed. + the inputs needed. Instruction encoding ==================== @@ -76,7 +76,7 @@ bits and least significant bits, respectively: imm offset src dst opcode ============= ======= =============== ==================== ============ -imm +imm signed integer immediate value offset @@ -393,7 +393,7 @@ instructions that transfer data between a register and memory. ============================= ========= ================================== opcode construction opcode pseudocode ============================= ========= ================================== -BPF_MEM | BPF_B | BPF_LDX 0x71 dst = *(uint8_t *) (src + offset) +BPF_MEM | BPF_B | BPF_LDX 0x71 dst = *(uint8_t *) (src + offset) BPF_MEM | BPF_H | BPF_LDX 0x69 dst = *(uint16_t *) (src + offset) BPF_MEM | BPF_W | BPF_LDX 0x61 dst = *(uint32_t *) (src + offset) BPF_MEM | BPF_DW | BPF_LDX 0x79 dst = *(uint64_t *) (src + offset) @@ -492,17 +492,17 @@ basic instruction to hold an opcode subtype. The following instructions are defined, and use additional concepts defined below: -========================= ====== ==== ===================================== =========== ============== -opcode construction opcode src pseudocode imm type dst type -========================= ====== ==== ===================================== =========== ============== -BPF_IMM | BPF_DW | BPF_LD 0x18 0x00 dst = imm64 integer integer -BPF_IMM | BPF_DW | BPF_LD 0x18 0x01 dst = map_by_fd(imm) map fd map -BPF_IMM | BPF_DW | BPF_LD 0x18 0x02 dst = mva(map_by_fd(imm)) + next_imm map fd data pointer -BPF_IMM | BPF_DW | BPF_LD 0x18 0x03 dst = variable_addr(imm) variable id data pointer -BPF_IMM | BPF_DW | BPF_LD 0x18 0x04 dst = code_addr(imm) integer code pointer -BPF_IMM | BPF_DW | BPF_LD 0x18 0x05 dst = mva(map_by_idx(imm)) map index map -BPF_IMM | BPF_DW | BPF_LD 0x18 0x06 dst = mva(map_by_idx(imm)) + next_imm map index data pointer -========================= ====== ==== ===================================== =========== ============== +========================= ====== === ===================================== =========== ============== +opcode construction opcode src pseudocode imm type dst type +========================= ====== === ===================================== =========== ============== +BPF_IMM | BPF_DW | BPF_LD 0x18 0x0 dst = imm64 integer integer +BPF_IMM | BPF_DW | BPF_LD 0x18 0x1 dst = map_by_fd(imm) map fd map +BPF_IMM | BPF_DW | BPF_LD 0x18 0x2 dst = mva(map_by_fd(imm)) + next_imm map fd data pointer +BPF_IMM | BPF_DW | BPF_LD 0x18 0x3 dst = variable_addr(imm) variable id data pointer +BPF_IMM | BPF_DW | BPF_LD 0x18 0x4 dst = code_addr(imm) integer code pointer +BPF_IMM | BPF_DW | BPF_LD 0x18 0x5 dst = mva(map_by_idx(imm)) map index map +BPF_IMM | BPF_DW | BPF_LD 0x18 0x6 dst = mva(map_by_idx(imm)) + next_imm map index data pointer +========================= ====== === ===================================== =========== ============== where @@ -560,200 +560,200 @@ Appendix For reference, the following table lists opcodes in order by value. -====== ==== ==== =================================================== ======================================== -opcode imm src description reference -====== ==== ==== =================================================== ======================================== -0x00 any 0x00 (additional immediate value) `64-bit immediate instructions`_ -0x04 any 0x00 dst = (uint32_t)(dst + imm) `Arithmetic instructions`_ -0x05 0x00 0x00 goto +offset `Jump instructions`_ -0x07 any 0x00 dst += imm `Arithmetic instructions`_ -0x0c 0x00 any dst = (uint32_t)(dst + src) `Arithmetic instructions`_ -0x0f 0x00 any dst += src `Arithmetic instructions`_ -0x14 any 0x00 dst = (uint32_t)(dst - imm) `Arithmetic instructions`_ -0x15 any 0x00 if dst == imm goto +offset `Jump instructions`_ -0x16 any 0x00 if (uint32_t)dst == imm goto +offset `Jump instructions`_ -0x17 any 0x00 dst -= imm `Arithmetic instructions`_ -0x18 0x00 0x00 dst = imm64 `64-bit immediate instructions`_ -0x18 0x00 0x01 dst = map_by_fd(imm) `64-bit immediate instructions`_ -0x18 0x00 0x02 dst = mva(map_by_fd(imm)) + next_imm `64-bit immediate instructions`_ -0x18 0x00 0x03 dst = variable_addr(imm) `64-bit immediate instructions`_ -0x18 0x00 0x04 dst = code_addr(imm) `64-bit immediate instructions`_ -0x18 0x00 0x05 dst = mva(map_by_idx(imm)) `64-bit immediate instructions`_ -0x18 0x00 0x06 dst = mva(map_by_idx(imm)) + next_imm `64-bit immediate instructions`_ -0x1c 0x00 any dst = (uint32_t)(dst - src) `Arithmetic instructions`_ -0x1d 0x00 any if dst == src goto +offset `Jump instructions`_ -0x1e 0x00 any if (uint32_t)dst == (uint32_t)src goto +offset `Jump instructions`_ -0x1f 0x00 any dst -= src `Arithmetic instructions`_ -0x20 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ -0x24 any 0x00 dst = (uint32_t)(dst \* imm) `Arithmetic instructions`_ -0x25 any 0x00 if dst > imm goto +offset `Jump instructions`_ -0x26 any 0x00 if (uint32_t)dst > imm goto +offset `Jump instructions`_ -0x27 any 0x00 dst \*= imm `Arithmetic instructions`_ -0x28 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ -0x2c 0x00 any dst = (uint32_t)(dst \* src) `Arithmetic instructions`_ -0x2d 0x00 any if dst > src goto +offset `Jump instructions`_ -0x2e 0x00 any if (uint32_t)dst > (uint32_t)src goto +offset `Jump instructions`_ -0x2f 0x00 any dst \*= src `Arithmetic instructions`_ -0x30 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ -0x34 any 0x00 dst = (uint32_t)((imm != 0) ? (dst / imm) : 0) `Arithmetic instructions`_ -0x35 any 0x00 if dst >= imm goto +offset `Jump instructions`_ -0x36 any 0x00 if (uint32_t)dst >= imm goto +offset `Jump instructions`_ -0x37 any 0x00 dst = (imm != 0) ? (dst / imm) : 0 `Arithmetic instructions`_ -0x38 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ -0x3c 0x00 any dst = (uint32_t)((imm != 0) ? (dst / src) : 0) `Arithmetic instructions`_ -0x3d 0x00 any if dst >= src goto +offset `Jump instructions`_ -0x3e 0x00 any if (uint32_t)dst >= (uint32_t)src goto +offset `Jump instructions`_ -0x3f 0x00 any dst = (src !+ 0) ? (dst / src) : 0 `Arithmetic instructions`_ -0x40 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ -0x44 any 0x00 dst = (uint32_t)(dst \| imm) `Arithmetic instructions`_ -0x45 any 0x00 if dst & imm goto +offset `Jump instructions`_ -0x46 any 0x00 if (uint32_t)dst & imm goto +offset `Jump instructions`_ -0x47 any 0x00 dst \|= imm `Arithmetic instructions`_ -0x48 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ -0x4c 0x00 any dst = (uint32_t)(dst \| src) `Arithmetic instructions`_ -0x4d 0x00 any if dst & src goto +offset `Jump instructions`_ -0x4e 0x00 any if (uint32_t)dst & (uint32_t)src goto +offset `Jump instructions`_ -0x4f 0x00 any dst \|= src `Arithmetic instructions`_ -0x50 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ -0x54 any 0x00 dst = (uint32_t)(dst & imm) `Arithmetic instructions`_ -0x55 any 0x00 if dst != imm goto +offset `Jump instructions`_ -0x56 any 0x00 if (uint32_t)dst != imm goto +offset `Jump instructions`_ -0x57 any 0x00 dst &= imm `Arithmetic instructions`_ -0x58 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ -0x5c 0x00 any dst = (uint32_t)(dst & src) `Arithmetic instructions`_ -0x5d 0x00 any if dst != src goto +offset `Jump instructions`_ -0x5e 0x00 any if (uint32_t)dst != (uint32_t)src goto +offset `Jump instructions`_ -0x5f 0x00 any dst &= src `Arithmetic instructions`_ -0x61 0x00 any dst = \*(uint32_t \*)(src + offset) `Load and store instructions`_ -0x62 any 0x00 \*(uint32_t \*)(dst + offset) = imm `Load and store instructions`_ -0x63 0x00 any \*(uint32_t \*)(dst + offset) = src `Load and store instructions`_ -0x64 any 0x00 dst = (uint32_t)(dst << imm) `Arithmetic instructions`_ -0x65 any 0x00 if dst s> imm goto +offset `Jump instructions`_ -0x66 any 0x00 if (int32_t)dst s> (int32_t)imm goto +offset `Jump instructions`_ -0x67 any 0x00 dst <<= imm `Arithmetic instructions`_ -0x69 0x00 any dst = \*(uint16_t \*)(src + offset) `Load and store instructions`_ -0x6a any 0x00 \*(uint16_t \*)(dst + offset) = imm `Load and store instructions`_ -0x6b 0x00 any \*(uint16_t \*)(dst + offset) = src `Load and store instructions`_ -0x6c 0x00 any dst = (uint32_t)(dst << src) `Arithmetic instructions`_ -0x6d 0x00 any if dst s> src goto +offset `Jump instructions`_ -0x6e 0x00 any if (int32_t)dst s> (int32_t)src goto +offset `Jump instructions`_ -0x6f 0x00 any dst <<= src `Arithmetic instructions`_ -0x71 0x00 any dst = \*(uint8_t \*)(src + offset) `Load and store instructions`_ -0x72 any 0x00 \*(uint8_t \*)(dst + offset) = imm `Load and store instructions`_ -0x73 0x00 any \*(uint8_t \*)(dst + offset) = src `Load and store instructions`_ -0x74 any 0x00 dst = (uint32_t)(dst >> imm) `Arithmetic instructions`_ -0x75 any 0x00 if dst s>= imm goto +offset `Jump instructions`_ -0x76 any 0x00 if (int32_t)dst s>= (int32_t)imm goto +offset `Jump instructions`_ -0x77 any 0x00 dst >>= imm `Arithmetic instructions`_ -0x79 0x00 any dst = \*(uint64_t \*)(src + offset) `Load and store instructions`_ -0x7a any 0x00 \*(uint64_t \*)(dst + offset) = imm `Load and store instructions`_ -0x7b 0x00 any \*(uint64_t \*)(dst + offset) = src `Load and store instructions`_ -0x7c 0x00 any dst = (uint32_t)(dst >> src) `Arithmetic instructions`_ -0x7d 0x00 any if dst s>= src goto +offset `Jump instructions`_ -0x7e 0x00 any if (int32_t)dst s>= (int32_t)src goto +offset `Jump instructions`_ -0x7f 0x00 any dst >>= src `Arithmetic instructions`_ -0x84 0x00 0x00 dst = (uint32_t)-dst `Arithmetic instructions`_ -0x85 any 0x00 call imm `Jump instructions`_ -0x87 0x00 0x00 dst = -dst `Arithmetic instructions`_ -0x94 any 0x00 dst = (uint32_t)((imm != 0) ? (dst % imm) : imm) `Arithmetic instructions`_ -0x95 0x00 0x00 return `Jump instructions`_ -0x97 any 0x00 dst = (imm != 0) ? (dst % imm) : imm `Arithmetic instructions`_ -0x9c 0x00 any dst = (uint32_t)((src != 0) ? (dst % src) : src) `Arithmetic instructions`_ -0x9f 0x00 any dst = (src != 0) ? (dst % src) : src `Arithmetic instructions`_ -0xa4 any 0x00 dst = (uint32_t)(dst ^ imm) `Arithmetic instructions`_ -0xa5 any 0x00 if dst < imm goto +offset `Jump instructions`_ -0xa6 any 0x00 if (uint32_t)dst < imm goto +offset `Jump instructions`_ -0xa7 any 0x00 dst ^= imm `Arithmetic instructions`_ -0xac 0x00 any dst = (uint32_t)(dst ^ src) `Arithmetic instructions`_ -0xad 0x00 any if dst < src goto +offset `Jump instructions`_ -0xae 0x00 any if (uint32_t)dst < (uint32_t)src goto +offset `Jump instructions`_ -0xaf 0x00 any dst ^= src `Arithmetic instructions`_ -0xb4 any 0x00 dst = (uint32_t) imm `Arithmetic instructions`_ -0xb5 any 0x00 if dst <= imm goto +offset `Jump instructions`_ -0xa6 any 0x00 if (uint32_t)dst <= imm goto +offset `Jump instructions`_ -0xb7 any 0x00 dst = imm `Arithmetic instructions`_ -0xbc 0x00 any dst = (uint32_t) src `Arithmetic instructions`_ -0xbd 0x00 any if dst <= src goto +offset `Jump instructions`_ -0xbe 0x00 any if (uint32_t)dst <= (uint32_t)src goto +offset `Jump instructions`_ -0xbf 0x00 any dst = src `Arithmetic instructions`_ -0xc3 0x00 any lock \*(uint32_t \*)(dst + offset) += src `Atomic operations`_ -0xc3 0x01 any lock:: `Atomic operations`_ - - *(uint32_t *)(dst + offset) += src - src = *(uint32_t *)(dst + offset) -0xc3 0x40 any \*(uint32_t \*)(dst + offset) \|= src `Atomic operations`_ -0xc3 0x41 any lock:: `Atomic operations`_ - - *(uint32_t *)(dst + offset) |= src - src = *(uint32_t *)(dst + offset) -0xc3 0x50 any \*(uint32_t \*)(dst + offset) &= src `Atomic operations`_ -0xc3 0x51 any lock:: `Atomic operations`_ - - *(uint32_t *)(dst + offset) &= src - src = *(uint32_t *)(dst + offset) -0xc3 0xa0 any \*(uint32_t \*)(dst + offset) ^= src `Atomic operations`_ -0xc3 0xa1 any lock:: `Atomic operations`_ - - *(uint32_t *)(dst + offset) ^= src - src = *(uint32_t *)(dst + offset) -0xc3 0xe1 any lock:: `Atomic operations`_ - - temp = *(uint32_t *)(dst + offset) - *(uint32_t *)(dst + offset) = src - src = temp -0xc3 0xf1 any lock:: `Atomic operations`_ - - temp = *(uint32_t *)(dst + offset) - if *(uint32_t)(dst + offset) == R0 - *(uint32_t)(dst + offset) = src - R0 = temp -0xc4 any 0x00 dst = (uint32_t)(dst s>> imm) `Arithmetic instructions`_ -0xc5 any 0x00 if dst s< imm goto +offset `Jump instructions`_ -0xc6 any 0x00 if (int32_t)dst s< (int32_t)imm goto +offset `Jump instructions`_ -0xc7 any 0x00 dst s>>= imm `Arithmetic instructions`_ -0xcc 0x00 any dst = (uint32_t)(dst s>> src) `Arithmetic instructions`_ -0xcd 0x00 any if dst s< src goto +offset `Jump instructions`_ -0xce 0x00 any if (int32_t)dst s< (int32_t)src goto +offset `Jump instructions`_ -0xcf 0x00 any dst s>>= src `Arithmetic instructions`_ -0xd4 0x10 0x00 dst = htole16(dst) `Byte swap instructions`_ -0xd4 0x20 0x00 dst = htole32(dst) `Byte swap instructions`_ -0xd4 0x40 0x00 dst = htole64(dst) `Byte swap instructions`_ -0xd5 any 0x00 if dst s<= imm goto +offset `Jump instructions`_ -0xd6 any 0x00 if (int32_t)dst s<= (int32_t)imm goto +offset `Jump instructions`_ -0xdb 0x00 any lock \*(uint64_t \*)(dst + offset) += src `Atomic operations`_ -0xdb 0x01 any lock:: `Atomic operations`_ - - *(uint64_t *)(dst + offset) += src - src = *(uint64_t *)(dst + offset) -0xdb 0x40 any \*(uint64_t \*)(dst + offset) \|= src `Atomic operations`_ -0xdb 0x41 any lock:: `Atomic operations`_ - - *(uint64_t *)(dst + offset) |= src - lock src = *(uint64_t *)(dst + offset) -0xdb 0x50 any \*(uint64_t \*)(dst + offset) &= src `Atomic operations`_ -0xdb 0x51 any lock:: `Atomic operations`_ - - *(uint64_t *)(dst + offset) &= src - src = *(uint64_t *)(dst + offset) -0xdb 0xa0 any \*(uint64_t \*)(dst + offset) ^= src `Atomic operations`_ -0xdb 0xa1 any lock:: `Atomic operations`_ - - *(uint64_t *)(dst + offset) ^= src - src = *(uint64_t *)(dst + offset) -0xdb 0xe1 any lock:: `Atomic operations`_ - - temp = *(uint64_t *)(dst + offset) - *(uint64_t *)(dst + offset) = src - src = temp -0xdb 0xf1 any lock:: `Atomic operations`_ - - temp = *(uint64_t *)(dst + offset) - if *(uint64_t)(dst + offset) == R0 - *(uint64_t)(dst + offset) = src - R0 = temp -0xdc 0x10 0x00 dst = htobe16(dst) `Byte swap instructions`_ -0xdc 0x20 0x00 dst = htobe32(dst) `Byte swap instructions`_ -0xdc 0x40 0x00 dst = htobe64(dst) `Byte swap instructions`_ -0xdd 0x00 any if dst s<= src goto +offset `Jump instructions`_ -0xde 0x00 any if (int32_t)dst s<= (int32_t)src goto +offset `Jump instructions`_ -====== ==== ==== =================================================== ======================================== +====== === ==== =================================================== ======================================== +opcode src imm description reference +====== === ==== =================================================== ======================================== +0x00 0x0 any (additional immediate value) `64-bit immediate instructions`_ +0x04 0x0 any dst = (uint32_t)(dst + imm) `Arithmetic instructions`_ +0x05 0x0 0x00 goto +offset `Jump instructions`_ +0x07 0x0 any dst += imm `Arithmetic instructions`_ +0x0c any 0x00 dst = (uint32_t)(dst + src) `Arithmetic instructions`_ +0x0f any 0x00 dst += src `Arithmetic instructions`_ +0x14 0x0 any dst = (uint32_t)(dst - imm) `Arithmetic instructions`_ +0x15 0x0 any if dst == imm goto +offset `Jump instructions`_ +0x16 0x0 any if (uint32_t)dst == imm goto +offset `Jump instructions`_ +0x17 0x0 any dst -= imm `Arithmetic instructions`_ +0x18 0x0 0x00 dst = imm64 `64-bit immediate instructions`_ +0x18 0x1 0x00 dst = map_by_fd(imm) `64-bit immediate instructions`_ +0x18 0x2 0x00 dst = mva(map_by_fd(imm)) + next_imm `64-bit immediate instructions`_ +0x18 0x3 0x00 dst = variable_addr(imm) `64-bit immediate instructions`_ +0x18 0x4 0x00 dst = code_addr(imm) `64-bit immediate instructions`_ +0x18 0x5 0x00 dst = mva(map_by_idx(imm)) `64-bit immediate instructions`_ +0x18 0x6 0x00 dst = mva(map_by_idx(imm)) + next_imm `64-bit immediate instructions`_ +0x1c any 0x00 dst = (uint32_t)(dst - src) `Arithmetic instructions`_ +0x1d any 0x00 if dst == src goto +offset `Jump instructions`_ +0x1e any 0x00 if (uint32_t)dst == (uint32_t)src goto +offset `Jump instructions`_ +0x1f any 0x00 dst -= src `Arithmetic instructions`_ +0x20 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ +0x24 0x0 any dst = (uint32_t)(dst \* imm) `Arithmetic instructions`_ +0x25 0x0 any if dst > imm goto +offset `Jump instructions`_ +0x26 0x0 any if (uint32_t)dst > imm goto +offset `Jump instructions`_ +0x27 0x0 any dst \*= imm `Arithmetic instructions`_ +0x28 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ +0x2c any 0x00 dst = (uint32_t)(dst \* src) `Arithmetic instructions`_ +0x2d any 0x00 if dst > src goto +offset `Jump instructions`_ +0x2e any 0x00 if (uint32_t)dst > (uint32_t)src goto +offset `Jump instructions`_ +0x2f any 0x00 dst \*= src `Arithmetic instructions`_ +0x30 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ +0x34 0x0 any dst = (uint32_t)((imm != 0) ? (dst / imm) : 0) `Arithmetic instructions`_ +0x35 0x0 any if dst >= imm goto +offset `Jump instructions`_ +0x36 0x0 any if (uint32_t)dst >= imm goto +offset `Jump instructions`_ +0x37 0x0 any dst = (imm != 0) ? (dst / imm) : 0 `Arithmetic instructions`_ +0x38 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ +0x3c any 0x00 dst = (uint32_t)((imm != 0) ? (dst / src) : 0) `Arithmetic instructions`_ +0x3d any 0x00 if dst >= src goto +offset `Jump instructions`_ +0x3e any 0x00 if (uint32_t)dst >= (uint32_t)src goto +offset `Jump instructions`_ +0x3f any 0x00 dst = (src !+ 0) ? (dst / src) : 0 `Arithmetic instructions`_ +0x40 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ +0x44 0x0 any dst = (uint32_t)(dst \| imm) `Arithmetic instructions`_ +0x45 0x0 any if dst & imm goto +offset `Jump instructions`_ +0x46 0x0 any if (uint32_t)dst & imm goto +offset `Jump instructions`_ +0x47 0x0 any dst \|= imm `Arithmetic instructions`_ +0x48 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ +0x4c any 0x00 dst = (uint32_t)(dst \| src) `Arithmetic instructions`_ +0x4d any 0x00 if dst & src goto +offset `Jump instructions`_ +0x4e any 0x00 if (uint32_t)dst & (uint32_t)src goto +offset `Jump instructions`_ +0x4f any 0x00 dst \|= src `Arithmetic instructions`_ +0x50 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ +0x54 0x0 any dst = (uint32_t)(dst & imm) `Arithmetic instructions`_ +0x55 0x0 any if dst != imm goto +offset `Jump instructions`_ +0x56 0x0 any if (uint32_t)dst != imm goto +offset `Jump instructions`_ +0x57 0x0 any dst &= imm `Arithmetic instructions`_ +0x58 any any (deprecated, implementation-specific) `Legacy BPF Packet access instructions`_ +0x5c any 0x00 dst = (uint32_t)(dst & src) `Arithmetic instructions`_ +0x5d any 0x00 if dst != src goto +offset `Jump instructions`_ +0x5e any 0x00 if (uint32_t)dst != (uint32_t)src goto +offset `Jump instructions`_ +0x5f any 0x00 dst &= src `Arithmetic instructions`_ +0x61 any 0x00 dst = \*(uint32_t \*)(src + offset) `Load and store instructions`_ +0x62 0x0 any \*(uint32_t \*)(dst + offset) = imm `Load and store instructions`_ +0x63 any 0x00 \*(uint32_t \*)(dst + offset) = src `Load and store instructions`_ +0x64 0x0 any dst = (uint32_t)(dst << imm) `Arithmetic instructions`_ +0x65 0x0 any if dst s> imm goto +offset `Jump instructions`_ +0x66 0x0 any if (int32_t)dst s> (int32_t)imm goto +offset `Jump instructions`_ +0x67 0x0 any dst <<= imm `Arithmetic instructions`_ +0x69 any 0x00 dst = \*(uint16_t \*)(src + offset) `Load and store instructions`_ +0x6a 0x0 any \*(uint16_t \*)(dst + offset) = imm `Load and store instructions`_ +0x6b any 0x00 \*(uint16_t \*)(dst + offset) = src `Load and store instructions`_ +0x6c any 0x00 dst = (uint32_t)(dst << src) `Arithmetic instructions`_ +0x6d any 0x00 if dst s> src goto +offset `Jump instructions`_ +0x6e any 0x00 if (int32_t)dst s> (int32_t)src goto +offset `Jump instructions`_ +0x6f any 0x00 dst <<= src `Arithmetic instructions`_ +0x71 any 0x00 dst = \*(uint8_t \*)(src + offset) `Load and store instructions`_ +0x72 0x0 any \*(uint8_t \*)(dst + offset) = imm `Load and store instructions`_ +0x73 any 0x00 \*(uint8_t \*)(dst + offset) = src `Load and store instructions`_ +0x74 0x0 any dst = (uint32_t)(dst >> imm) `Arithmetic instructions`_ +0x75 0x0 any if dst s>= imm goto +offset `Jump instructions`_ +0x76 0x0 any if (int32_t)dst s>= (int32_t)imm goto +offset `Jump instructions`_ +0x77 0x0 any dst >>= imm `Arithmetic instructions`_ +0x79 any 0x00 dst = \*(uint64_t \*)(src + offset) `Load and store instructions`_ +0x7a 0x0 any \*(uint64_t \*)(dst + offset) = imm `Load and store instructions`_ +0x7b any 0x00 \*(uint64_t \*)(dst + offset) = src `Load and store instructions`_ +0x7c any 0x00 dst = (uint32_t)(dst >> src) `Arithmetic instructions`_ +0x7d any 0x00 if dst s>= src goto +offset `Jump instructions`_ +0x7e any 0x00 if (int32_t)dst s>= (int32_t)src goto +offset `Jump instructions`_ +0x7f any 0x00 dst >>= src `Arithmetic instructions`_ +0x84 0x0 0x00 dst = (uint32_t)-dst `Arithmetic instructions`_ +0x85 0x0 any call imm `Jump instructions`_ +0x87 0x0 0x00 dst = -dst `Arithmetic instructions`_ +0x94 0x0 any dst = (uint32_t)((imm != 0) ? (dst % imm) : imm) `Arithmetic instructions`_ +0x95 0x0 0x00 return `Jump instructions`_ +0x97 0x0 any dst = (imm != 0) ? (dst % imm) : imm `Arithmetic instructions`_ +0x9c any 0x00 dst = (uint32_t)((src != 0) ? (dst % src) : src) `Arithmetic instructions`_ +0x9f any 0x00 dst = (src != 0) ? (dst % src) : src `Arithmetic instructions`_ +0xa4 0x0 any dst = (uint32_t)(dst ^ imm) `Arithmetic instructions`_ +0xa5 0x0 any if dst < imm goto +offset `Jump instructions`_ +0xa6 0x0 any if (uint32_t)dst < imm goto +offset `Jump instructions`_ +0xa7 0x0 any dst ^= imm `Arithmetic instructions`_ +0xac any 0x00 dst = (uint32_t)(dst ^ src) `Arithmetic instructions`_ +0xad any 0x00 if dst < src goto +offset `Jump instructions`_ +0xae any 0x00 if (uint32_t)dst < (uint32_t)src goto +offset `Jump instructions`_ +0xaf any 0x00 dst ^= src `Arithmetic instructions`_ +0xb4 0x0 any dst = (uint32_t) imm `Arithmetic instructions`_ +0xb5 0x0 any if dst <= imm goto +offset `Jump instructions`_ +0xa6 0x0 any if (uint32_t)dst <= imm goto +offset `Jump instructions`_ +0xb7 0x0 any dst = imm `Arithmetic instructions`_ +0xbc any 0x00 dst = (uint32_t) src `Arithmetic instructions`_ +0xbd any 0x00 if dst <= src goto +offset `Jump instructions`_ +0xbe any 0x00 if (uint32_t)dst <= (uint32_t)src goto +offset `Jump instructions`_ +0xbf any 0x00 dst = src `Arithmetic instructions`_ +0xc3 any 0x00 lock \*(uint32_t \*)(dst + offset) += src `Atomic operations`_ +0xc3 any 0x01 lock:: `Atomic operations`_ + + *(uint32_t *)(dst + offset) += src + src = *(uint32_t *)(dst + offset) +0xc3 any 0x40 \*(uint32_t \*)(dst + offset) \|= src `Atomic operations`_ +0xc3 any 0x41 lock:: `Atomic operations`_ + + *(uint32_t *)(dst + offset) |= src + src = *(uint32_t *)(dst + offset) +0xc3 any 0x50 \*(uint32_t \*)(dst + offset) &= src `Atomic operations`_ +0xc3 any 0x51 lock:: `Atomic operations`_ + + *(uint32_t *)(dst + offset) &= src + src = *(uint32_t *)(dst + offset) +0xc3 any 0xa0 \*(uint32_t \*)(dst + offset) ^= src `Atomic operations`_ +0xc3 any 0xa1 lock:: `Atomic operations`_ + + *(uint32_t *)(dst + offset) ^= src + src = *(uint32_t *)(dst + offset) +0xc3 any 0xe1 lock:: `Atomic operations`_ + + temp = *(uint32_t *)(dst + offset) + *(uint32_t *)(dst + offset) = src + src = temp +0xc3 any 0xf1 lock:: `Atomic operations`_ + + temp = *(uint32_t *)(dst + offset) + if *(uint32_t)(dst + offset) == R0 + *(uint32_t)(dst + offset) = src + R0 = temp +0xc4 0x0 any dst = (uint32_t)(dst s>> imm) `Arithmetic instructions`_ +0xc5 0x0 any if dst s< imm goto +offset `Jump instructions`_ +0xc6 0x0 any if (int32_t)dst s< (int32_t)imm goto +offset `Jump instructions`_ +0xc7 0x0 any dst s>>= imm `Arithmetic instructions`_ +0xcc any 0x00 dst = (uint32_t)(dst s>> src) `Arithmetic instructions`_ +0xcd any 0x00 if dst s< src goto +offset `Jump instructions`_ +0xce any 0x00 if (int32_t)dst s< (int32_t)src goto +offset `Jump instructions`_ +0xcf any 0x00 dst s>>= src `Arithmetic instructions`_ +0xd4 0x0 0x10 dst = htole16(dst) `Byte swap instructions`_ +0xd4 0x0 0x20 dst = htole32(dst) `Byte swap instructions`_ +0xd4 0x0 0x40 dst = htole64(dst) `Byte swap instructions`_ +0xd5 0x0 any if dst s<= imm goto +offset `Jump instructions`_ +0xd6 0x0 any if (int32_t)dst s<= (int32_t)imm goto +offset `Jump instructions`_ +0xdb any 0x00 lock \*(uint64_t \*)(dst + offset) += src `Atomic operations`_ +0xdb any 0x01 lock:: `Atomic operations`_ + + *(uint64_t *)(dst + offset) += src + src = *(uint64_t *)(dst + offset) +0xdb any 0x40 \*(uint64_t \*)(dst + offset) \|= src `Atomic operations`_ +0xdb any 0x41 lock:: `Atomic operations`_ + + *(uint64_t *)(dst + offset) |= src + lock src = *(uint64_t *)(dst + offset) +0xdb any 0x50 \*(uint64_t \*)(dst + offset) &= src `Atomic operations`_ +0xdb any 0x51 lock:: `Atomic operations`_ + + *(uint64_t *)(dst + offset) &= src + src = *(uint64_t *)(dst + offset) +0xdb any 0xa0 \*(uint64_t \*)(dst + offset) ^= src `Atomic operations`_ +0xdb any 0xa1 lock:: `Atomic operations`_ + + *(uint64_t *)(dst + offset) ^= src + src = *(uint64_t *)(dst + offset) +0xdb any 0xe1 lock:: `Atomic operations`_ + + temp = *(uint64_t *)(dst + offset) + *(uint64_t *)(dst + offset) = src + src = temp +0xdb any 0xf1 lock:: `Atomic operations`_ + + temp = *(uint64_t *)(dst + offset) + if *(uint64_t)(dst + offset) == R0 + *(uint64_t)(dst + offset) = src + R0 = temp +0xdc 0x0 0x10 dst = htobe16(dst) `Byte swap instructions`_ +0xdc 0x0 0x20 dst = htobe32(dst) `Byte swap instructions`_ +0xdc 0x0 0x40 dst = htobe64(dst) `Byte swap instructions`_ +0xdd any 0x00 if dst s<= src goto +offset `Jump instructions`_ +0xde any 0x00 if (int32_t)dst s<= (int32_t)src goto +offset `Jump instructions`_ +====== === ==== =================================================== ======================================== From f83177086e8491b9b2c0466ae778ec9427fdff7f Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Fri, 16 Sep 2022 15:13:46 -0700 Subject: [PATCH 10/25] Specify modulo with negative numbers Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index ec27f2a..1d7f0e5 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -240,6 +240,14 @@ where '(uint32_t)' indicates truncation to 32 bits. src = src ^ imm +Also note that the modulo operation often varies by language +when the dividend or divisor are negative, where Python, Ruby, etc. +differ from C, Go, Java, etc. This specification requires that +modulo use the widely accepted mathematical definition given by Donald +Knuth and implemented in C, Go, etc.: + + a % n = a - n * floor(a / n) + Byte swap instructions ~~~~~~~~~~~~~~~~~~~~~~ From 508e6fdb831308e82b407d97a24d288546387892 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Wed, 21 Sep 2022 09:07:55 -0700 Subject: [PATCH 11/25] Address feedback from Quentin Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index 1d7f0e5..822dec2 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -508,7 +508,7 @@ BPF_IMM | BPF_DW | BPF_LD 0x18 0x1 dst = map_by_fd(imm) m BPF_IMM | BPF_DW | BPF_LD 0x18 0x2 dst = mva(map_by_fd(imm)) + next_imm map fd data pointer BPF_IMM | BPF_DW | BPF_LD 0x18 0x3 dst = variable_addr(imm) variable id data pointer BPF_IMM | BPF_DW | BPF_LD 0x18 0x4 dst = code_addr(imm) integer code pointer -BPF_IMM | BPF_DW | BPF_LD 0x18 0x5 dst = mva(map_by_idx(imm)) map index map +BPF_IMM | BPF_DW | BPF_LD 0x18 0x5 dst = map_by_idx(imm) map index map BPF_IMM | BPF_DW | BPF_LD 0x18 0x6 dst = mva(map_by_idx(imm)) + next_imm map index data pointer ========================= ====== === ===================================== =========== ============== @@ -516,7 +516,7 @@ where * map_by_fd(fd) means to convert a 32-bit POSIX file descriptor into an address of a map object (see `Map objects`_) * map_by_index(index) means to convert a 32-bit index into an address of a map object -* mva(map) gets the address of the memory region expressed by a given map object +* mva(map) gets the address of the first value in a given map object * variable_addr(id) gets the address of a variable (see `Variables`_) with a given id * code_addr(offset) gets the address of the instruction at a specified relative offset in units of 64-bit blocks * the 'imm type' can be used by disassemblers for display @@ -586,7 +586,7 @@ opcode src imm description referenc 0x18 0x2 0x00 dst = mva(map_by_fd(imm)) + next_imm `64-bit immediate instructions`_ 0x18 0x3 0x00 dst = variable_addr(imm) `64-bit immediate instructions`_ 0x18 0x4 0x00 dst = code_addr(imm) `64-bit immediate instructions`_ -0x18 0x5 0x00 dst = mva(map_by_idx(imm)) `64-bit immediate instructions`_ +0x18 0x5 0x00 dst = map_by_idx(imm) `64-bit immediate instructions`_ 0x18 0x6 0x00 dst = mva(map_by_idx(imm)) + next_imm `64-bit immediate instructions`_ 0x1c any 0x00 dst = (uint32_t)(dst - src) `Arithmetic instructions`_ 0x1d any 0x00 if dst == src goto +offset `Jump instructions`_ From ae3832571163efe56b905a3a42d0bdaeada26e5e Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Wed, 21 Sep 2022 12:59:37 -0700 Subject: [PATCH 12/25] Add extended call instructions Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 54 +++++++++++++++++++----------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index 822dec2..298966a 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -306,30 +306,32 @@ versions. The 4-bit 'code' field encodes the operation as below, where PC is the program counter: -======== ===== ============================ ======= ============ -code value description version notes -======== ===== ============================ ======= ============ -BPF_JA 0x00 PC += offset 1 BPF_JMP only -BPF_JEQ 0x10 PC += offset if dst == src 1 -BPF_JGT 0x20 PC += offset if dst > src 1 unsigned -BPF_JGE 0x30 PC += offset if dst >= src 1 unsigned -BPF_JSET 0x40 PC += offset if dst & src 1 -BPF_JNE 0x50 PC += offset if dst != src 1 -BPF_JSGT 0x60 PC += offset if dst > src 1 signed -BPF_JSGE 0x70 PC += offset if dst >= src 1 signed -BPF_CALL 0x80 call function imm 1 see `Helper functions`_ -BPF_EXIT 0x90 function / program return 1 BPF_JMP only -BPF_JLT 0xa0 PC += offset if dst < src 2 unsigned -BPF_JLE 0xb0 PC += offset if dst <= src 2 unsigned -BPF_JSLT 0xc0 PC += offset if dst < src 2 signed -BPF_JSLE 0xd0 PC += offset if dst <= src 2 signed +======== ===== === ============================ ======= ============ +code value src description version notes +======== ===== === ============================ ======= ============ +BPF_JA 0x00 0x0 PC += offset 1 BPF_JMP only +BPF_JEQ 0x10 any PC += offset if dst == src 1 +BPF_JGT 0x20 any PC += offset if dst > src 1 unsigned +BPF_JGE 0x30 any PC += offset if dst >= src 1 unsigned +BPF_JSET 0x40 any PC += offset if dst & src 1 +BPF_JNE 0x50 any PC += offset if dst != src 1 +BPF_JSGT 0x60 any PC += offset if dst > src 1 signed +BPF_JSGE 0x70 any PC += offset if dst >= src 1 signed +BPF_CALL 0x80 0x0 call helper function imm 1 see `Helper functions`_ +BPF_CALL 0x80 0x1 call PC += offset 1 see `eBPF functions`_ +BPF_CALL 0x80 0x2 call runtime function imm 1 see `Runtime functions`_ +BPF_EXIT 0x95 0x0 return 1 BPF_JMP only +BPF_JLT 0xa0 any PC += offset if dst < src 2 unsigned +BPF_JLE 0xb0 any PC += offset if dst <= src 2 unsigned +BPF_JSLT 0xc0 any PC += offset if dst < src 2 signed +BPF_JSLE 0xd0 any PC += offset if dst <= src 2 signed ======== ===== ============================ ======= ============ where 'version' indicates the first ISA version in which the value was supported. Helper functions ~~~~~~~~~~~~~~~~ -Helper functions are a concept whereby BPF programs can call into +Helper functions are a concept whereby BPF programs can call into a set of function calls exposed by the eBPF runtime. Each helper function is identified by an integer used in a ``BPF_CALL`` instruction. The available helper functions may differ for each eBPF program type. @@ -352,6 +354,18 @@ would be read from a specified register, is not currently permitted. *Clang implementation*: Clang will generate this invalid instruction if ``-O0`` is used. +Runtime functions +~~~~~~~~~~~~~~~~~ +Runtime functions are like helper functions except that they are not specific +to eBPF programs. They use a different numbering space from helper functions, +but otherwise the same considerations apply. + +eBPF functions +~~~~~~~~~~~~~~ +eBPF functions are functions exposed by the same eBPF program as the caller, +and are referenced by offset from the call instruction, similar to 'BPF_JA'. +A 'BPF_EXIT' within the eBPF function will return to the caller. + Load and store instructions =========================== @@ -661,7 +675,9 @@ opcode src imm description referenc 0x7e any 0x00 if (int32_t)dst s>= (int32_t)src goto +offset `Jump instructions`_ 0x7f any 0x00 dst >>= src `Arithmetic instructions`_ 0x84 0x0 0x00 dst = (uint32_t)-dst `Arithmetic instructions`_ -0x85 0x0 any call imm `Jump instructions`_ +0x85 0x0 any call helper function imm `Helper functions`_ +0x85 0x1 any call PC += offset `eBPF functions`_ +0x85 0x2 any call runtime function imm `Runtime functions`_ 0x87 0x0 0x00 dst = -dst `Arithmetic instructions`_ 0x94 0x0 any dst = (uint32_t)((imm != 0) ? (dst % imm) : imm) `Arithmetic instructions`_ 0x95 0x0 0x00 return `Jump instructions`_ From 33c190f39326f18bebf800e1a4e81ab056bd2760 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Wed, 21 Sep 2022 15:38:15 -0700 Subject: [PATCH 13/25] Move all Linux implementation notes to a separate document Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 39 +------------------ ...x-historical-notes.rst => linux-notes.rst} | 35 +++++++++++++++-- 2 files changed, 34 insertions(+), 40 deletions(-) rename isa/kernel.org/{linux-historical-notes.rst => linux-notes.rst} (74%) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index 298966a..e5d0f43 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -39,23 +39,12 @@ that the value in the register is moved to the BPF stack. The reverse operation of moving the variable from the BPF stack to the register is called filling. The reason for spilling/filling is due to the limited number of registers. - **Note** - - *Linux implementation*: In the Linux kernel, the exit value for eBPF - programs is passed as a 32 bit value. - Upon entering execution of an eBPF program, registers R1 - R5 initially can contain the input arguments for the program (similar to the argc/argv pair for a typical C program). The actual number of registers used, and their meaning, is defined by the program type; for example, a networking program might have an argument that includes network packet data and/or metadata. - **Note** - - *Linux implementation*: In the Linux kernel, all program types only use - R1 which contains the "context", which is typically a structure containing all - the inputs needed. - Instruction encoding ==================== @@ -221,12 +210,6 @@ Examples: where '(uint32_t)' indicates truncation to 32 bits. - **Note** - - *Linux implementation*: In the Linux kernel, uint32_t is expressed as u32, - uint64_t is expressed as u64, etc. This document uses the standard C terminology - as the cross-platform specification. - ``BPF_ADD | BPF_X | BPF_ALU64`` (0x0f) means:: dst = dst + src @@ -268,12 +251,6 @@ BPF_TO_LE 0x00 convert between host byte order and little endian BPF_TO_BE 0x08 convert between host byte order and big endian ========= ===== ================================================= - **Note** - - *Linux implementation*: - ``BPF_FROM_LE`` and ``BPF_FROM_BE`` exist as aliases for ``BPF_TO_LE`` and - ``BPF_TO_BE`` respectively. - The 'imm' field encodes the width of the swap operations. The following widths are supported: 16, 32 and 64. The following table summarizes the resulting possibilities: @@ -545,10 +522,6 @@ A map can have various semantics as defined in a separate document, and may or m contiguous memory region, but the 'mva(map)' is currently only defined for maps that do have a single contiguous memory region. Support for maps is optional. - **Note** - - *Linux implementation*: Linux only supports the 'mva(map)' operation on array maps with a single element. - Each map object can have a POSIX file descriptor (fd) if supported by the platform, where 'map_by_fd(fd)' means to get the map with the specified file descriptor. Each eBPF program can also be defined to use a set of maps associated with the program @@ -562,20 +535,12 @@ Variables are memory regions, identified by integer ids, accessible by eBPF prog some platforms. The 'variable_addr(id)' operation means to get the address of the memory region identified by the given id. Support for such variables is optional. - **Note** - - *Linux implementation*: Linux uses BTF ids to identify variables. - Legacy BPF Packet access instructions ------------------------------------- -Linux introduced special instructions for access to packet data that were +eBPF previously introduced special instructions for access to packet data that were carried over from classic BPF. However, these instructions are -deprecated and should no longer be used in any version of the ISA. - - **Note** - - *Linux implementation*: Details can be found in the `Linux historical notes `_. +deprecated and should no longer be used. Appendix ======== diff --git a/isa/kernel.org/linux-historical-notes.rst b/isa/kernel.org/linux-notes.rst similarity index 74% rename from isa/kernel.org/linux-historical-notes.rst rename to isa/kernel.org/linux-notes.rst index c0362df..fac86f3 100644 --- a/isa/kernel.org/linux-historical-notes.rst +++ b/isa/kernel.org/linux-notes.rst @@ -1,9 +1,38 @@ .. contents:: .. sectnum:: -===================== -Linux historial notes -===================== +========================== +Linux implementation notes +========================== + +This document provides more details specific to the Linux kernel implementation of the eBPF instruction set. + +Registers and calling convention +================================ + +All program types only use R1 which contains the "context", which is typically a structure containing all +the inputs needed, and the exit value for eBPF programs is passed as a 32 bit value. + +Arithmetic instructions +======================= + +While the eBPF instruction set document uses the standard C terminology as the cross-platform specification, +in the Linux kernel, uint32_t is expressed as u32, uint64_t is expressed as u64, etc. + +Byte swap instructions +====================== + +``BPF_FROM_LE`` and ``BPF_FROM_BE`` exist as aliases for ``BPF_TO_LE`` and ``BPF_TO_BE`` respectively. + +Map objects +=========== + +Linux only supports the 'mva(map)' operation on array maps with a single element. + +Variables +========= + +Linux uses BTF ids to identify variables. Legacy BPF Packet access instructions ===================================== From b80f5587ddc2c4f5c754a673406a3b41fce34ea1 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Wed, 21 Sep 2022 15:43:29 -0700 Subject: [PATCH 14/25] Move Clang notes to a separate document Signed-off-by: Dave Thaler --- isa/kernel.org/clang-notes.rst | 35 ++++++++++++++++++++++++++++++ isa/kernel.org/instruction-set.rst | 25 --------------------- 2 files changed, 35 insertions(+), 25 deletions(-) create mode 100644 isa/kernel.org/clang-notes.rst diff --git a/isa/kernel.org/clang-notes.rst b/isa/kernel.org/clang-notes.rst new file mode 100644 index 0000000..3c93442 --- /dev/null +++ b/isa/kernel.org/clang-notes.rst @@ -0,0 +1,35 @@ +.. contents:: +.. sectnum:: + +========================== +Clang implementation notes +========================== + +This document provides more details specific to the Clang/LLVM implementation of the eBPF instruction set. + +Versions +======== + +Clang defined "CPU" versions, where a CPU version of 3 corresponds to the current eBPF ISA. + +Clang can select the eBPF ISA version using ``-mcpu=v3`` for example to select version 3. + +Arithmetic instructions +======================= + +For CPU versions prior to 3, Clang v7.0 and later can enable ``BPF_ALU`` support with +``-Xclang -target-feature -Xclang +alu32``. In CPU version 3, support is automatically included. + +Invalid instructions +==================== + +Clang will generate the invalid ``BPF_CALL | BPF_X | BPF_JMP`` (0x8d) instruction if ``-O0`` is used. + +Atomic operations +================= + +Clang can generate atomic instructions by default when ``-mcpu=v3`` is +enabled. If a lower version for ``-mcpu`` is set, the only atomic instruction +Clang can generate is ``BPF_ADD`` *without* ``BPF_FETCH``. If you need to enable +the atomics features, while keeping a lower ``-mcpu`` version, you can use +``-Xclang -target-feature -Xclang +alu32``. diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index e5d0f43..6136329 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -14,11 +14,6 @@ Versions The current Instruction Set Architecture (ISA) version, sometimes referred to in other documents as a "CPU" version, is 3. This document also covers older versions of the ISA. - **Note** - - *Clang implementation*: Clang can select the eBPF ISA version using - ``-mcpu=v2`` for example to select version 2. - Registers and calling convention ================================ @@ -166,12 +161,6 @@ otherwise identical operations. Support for ``BPF_ALU`` is required in ISA version 3, and optional in earlier versions. - **Note** - - *Clang implementation*: - For ISA versions prior to 3, Clang v7.0 and later can enable ``BPF_ALU`` support with - ``-Xclang -target-feature -Xclang +alu32``. - The 4-bit 'code' field encodes the operation as follows: ======== ===== ================================================= @@ -326,11 +315,6 @@ the number of arguments, and the type of each argument. Note that ``BPF_CALL | BPF_X | BPF_JMP`` (0x8d), where the helper function integer would be read from a specified register, is not currently permitted. - **Note** - - *Clang implementation*: - Clang will generate this invalid instruction if ``-O0`` is used. - Runtime functions ~~~~~~~~~~~~~~~~~ Runtime functions are like helper functions except that they are not specific @@ -473,15 +457,6 @@ The ``BPF_CMPXCHG`` operation atomically compares the value addressed by value that was at ``dst + offset`` before the operation is zero-extended and loaded back to ``R0``. - **Note** - - *Clang implementation*: - Clang can generate atomic instructions by default when ``-mcpu=v3`` is - enabled. If a lower version for ``-mcpu`` is set, the only atomic instruction - Clang can generate is ``BPF_ADD`` *without* ``BPF_FETCH``. If you need to enable - the atomics features, while keeping a lower ``-mcpu`` version, you can use - ``-Xclang -target-feature -Xclang +alu32``. - 64-bit immediate instructions ----------------------------- From 0f30bc10d4501509528c86e287104e4a319d25c1 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Wed, 21 Sep 2022 15:48:29 -0700 Subject: [PATCH 15/25] Redo versioning to just state the latest version is v1.0 Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 123 ++++++++++++----------------- 1 file changed, 52 insertions(+), 71 deletions(-) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index 6136329..62703bc 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -1,19 +1,15 @@ .. contents:: .. sectnum:: -==================== -eBPF Instruction Set -==================== +======================================== +eBPF Instruction Set Specification, v1.0 +======================================== + +This document specifies version 1.0 of the eBPF instruction set. The eBPF instruction set consists of eleven 64 bit registers, a program counter, and 512 bytes of stack space. -Versions -======== - -The current Instruction Set Architecture (ISA) version, sometimes referred to in other documents -as a "CPU" version, is 3. This document also covers older versions of the ISA. - Registers and calling convention ================================ @@ -108,20 +104,18 @@ The encoding of the 'opcode' field varies and can be determined from the three least significant bits (LSB) of the 'opcode' field which holds the "instruction class", as follows: -========= ===== =============================== ======= ================= -class value description version reference -========= ===== =============================== ======= ================= -BPF_LD 0x00 non-standard load operations 1 `Load and store instructions`_ -BPF_LDX 0x01 load into register operations 1 `Load and store instructions`_ -BPF_ST 0x02 store from immediate operations 1 `Load and store instructions`_ -BPF_STX 0x03 store from register operations 1 `Load and store instructions`_ -BPF_ALU 0x04 32-bit arithmetic operations 3 `Arithmetic and jump instructions`_ -BPF_JMP 0x05 64-bit jump operations 1 `Arithmetic and jump instructions`_ -BPF_JMP32 0x06 32-bit jump operations 3 `Arithmetic and jump instructions`_ -BPF_ALU64 0x07 64-bit arithmetic operations 1 `Arithmetic and jump instructions`_ -========= ===== =============================== ======= ================= - -where 'version' indicates the first ISA version in which support for the value was mandatory. +========= ===== =============================== ================= +class value description reference +========= ===== =============================== ================= +BPF_LD 0x00 non-standard load operations `Load and store instructions`_ +BPF_LDX 0x01 load into register operations `Load and store instructions`_ +BPF_ST 0x02 store from immediate operations `Load and store instructions`_ +BPF_STX 0x03 store from register operations `Load and store instructions`_ +BPF_ALU 0x04 32-bit arithmetic operations `Arithmetic and jump instructions`_ +BPF_JMP 0x05 64-bit jump operations `Arithmetic and jump instructions`_ +BPF_JMP32 0x06 32-bit jump operations `Arithmetic and jump instructions`_ +BPF_ALU64 0x07 64-bit arithmetic operations `Arithmetic and jump instructions`_ +========= ===== =============================== ================= Arithmetic and jump instructions ================================ @@ -158,9 +152,6 @@ Instruction class ``BPF_ALU`` uses 32-bit wide operands (zeroing the upper 32 bi of the destination register) while ``BPF_ALU64`` uses 64-bit wide operands for otherwise identical operations. -Support for ``BPF_ALU`` is required in ISA version 3, and optional in earlier -versions. - The 4-bit 'code' field encodes the operation as follows: ======== ===== ================================================= @@ -267,33 +258,28 @@ Jump instructions Instruction class ``BPF_JMP32`` uses 32-bit wide operands while ``BPF_JMP`` uses 64-bit wide operands for otherwise identical operations. -Support for ``BPF_JMP32`` is required in ISA version 3, and optional in earlier -versions. - The 4-bit 'code' field encodes the operation as below, where PC is the program counter: -======== ===== === ============================ ======= ============ -code value src description version notes -======== ===== === ============================ ======= ============ -BPF_JA 0x00 0x0 PC += offset 1 BPF_JMP only -BPF_JEQ 0x10 any PC += offset if dst == src 1 -BPF_JGT 0x20 any PC += offset if dst > src 1 unsigned -BPF_JGE 0x30 any PC += offset if dst >= src 1 unsigned -BPF_JSET 0x40 any PC += offset if dst & src 1 -BPF_JNE 0x50 any PC += offset if dst != src 1 -BPF_JSGT 0x60 any PC += offset if dst > src 1 signed -BPF_JSGE 0x70 any PC += offset if dst >= src 1 signed -BPF_CALL 0x80 0x0 call helper function imm 1 see `Helper functions`_ -BPF_CALL 0x80 0x1 call PC += offset 1 see `eBPF functions`_ -BPF_CALL 0x80 0x2 call runtime function imm 1 see `Runtime functions`_ -BPF_EXIT 0x95 0x0 return 1 BPF_JMP only -BPF_JLT 0xa0 any PC += offset if dst < src 2 unsigned -BPF_JLE 0xb0 any PC += offset if dst <= src 2 unsigned -BPF_JSLT 0xc0 any PC += offset if dst < src 2 signed -BPF_JSLE 0xd0 any PC += offset if dst <= src 2 signed -======== ===== ============================ ======= ============ - -where 'version' indicates the first ISA version in which the value was supported. +======== ===== === ========================== ============ +code value src description notes +======== ===== === ========================== ============ +BPF_JA 0x00 0x0 PC += offset BPF_JMP only +BPF_JEQ 0x10 any PC += offset if dst == src +BPF_JGT 0x20 any PC += offset if dst > src unsigned +BPF_JGE 0x30 any PC += offset if dst >= src unsigned +BPF_JSET 0x40 any PC += offset if dst & src +BPF_JNE 0x50 any PC += offset if dst != src +BPF_JSGT 0x60 any PC += offset if dst > src signed +BPF_JSGE 0x70 any PC += offset if dst >= src signed +BPF_CALL 0x80 0x0 call helper function imm see `Helper functions`_ +BPF_CALL 0x80 0x1 call PC += offset see `eBPF functions`_ +BPF_CALL 0x80 0x2 call runtime function imm see `Runtime functions`_ +BPF_EXIT 0x95 0x0 return BPF_JMP only +BPF_JLT 0xa0 any PC += offset if dst < src unsigned +BPF_JLE 0xb0 any PC += offset if dst <= src unsigned +BPF_JSLT 0xc0 any PC += offset if dst < src signed +BPF_JSLE 0xd0 any PC += offset if dst <= src signed +======== ===== === =========================== ============ Helper functions ~~~~~~~~~~~~~~~~ @@ -410,16 +396,14 @@ The 'imm' field is used to encode the actual atomic operation. Simple atomic operation use a subset of the values defined to encode arithmetic operations in the 'imm' field to encode the atomic operation: -======== ===== =========== ======= -imm value description version -======== ===== =========== ======= -BPF_ADD 0x00 atomic add 1 -BPF_OR 0x40 atomic or 3 -BPF_AND 0x50 atomic and 3 -BPF_XOR 0xa0 atomic xor 3 -======== ===== =========== ======= - -where 'version' indicates the first ISA version in which the value was supported. +======== ===== =========== +imm value description +======== ===== =========== +BPF_ADD 0x00 atomic add +BPF_OR 0x40 atomic or +BPF_AND 0x50 atomic and +BPF_XOR 0xa0 atomic xor +======== ===== =========== ``BPF_ATOMIC | BPF_W | BPF_STX`` (0xc3) with 'imm' = BPF_ADD means:: @@ -429,19 +413,16 @@ where 'version' indicates the first ISA version in which the value was supported *(uint64_t *)(dst + offset) += src -``BPF_XADD`` appeared in version 1, but is now considered to be a deprecated alias -for ``BPF_ATOMIC | BPF_ADD``. - In addition to the simple atomic operations above, there also is a modifier and two complex atomic operations: -=========== ================ =========================== ======= -imm value description version -=========== ================ =========================== ======= -BPF_FETCH 0x01 modifier: return old value 3 -BPF_XCHG 0xe0 | BPF_FETCH atomic exchange 3 -BPF_CMPXCHG 0xf0 | BPF_FETCH atomic compare and exchange 3 -=========== ================ =========================== ======= +=========== ================ =========================== +imm value description +=========== ================ =========================== +BPF_FETCH 0x01 modifier: return old value +BPF_XCHG 0xe0 | BPF_FETCH atomic exchange +BPF_CMPXCHG 0xf0 | BPF_FETCH atomic compare and exchange +=========== ================ =========================== The ``BPF_FETCH`` modifier is optional for simple atomic operations, and always set for the complex atomic operations. If the ``BPF_FETCH`` flag From d230335faa97aa5977b5a7d31f557a9a9d24643e Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Wed, 21 Sep 2022 15:51:50 -0700 Subject: [PATCH 16/25] Add note about documentation conventions Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index 62703bc..f60dcfd 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -10,6 +10,11 @@ This document specifies version 1.0 of the eBPF instruction set. The eBPF instruction set consists of eleven 64 bit registers, a program counter, and 512 bytes of stack space. +Documentation conventions +========================= + +This specification uses the standard C types (uint32_t, etc.) in documentation. + Registers and calling convention ================================ From 6e145d289c068039d81a1700cc1d7ac533bf8697 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Thu, 22 Sep 2022 09:56:46 -0700 Subject: [PATCH 17/25] Fix asterisk escaping Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index f60dcfd..175ac84 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -364,22 +364,22 @@ Regular load and store operations The ``BPF_MEM`` mode modifier is used to encode regular load and store instructions that transfer data between a register and memory. -============================= ========= ================================== +============================= ========= ==================================== opcode construction opcode pseudocode -============================= ========= ================================== -BPF_MEM | BPF_B | BPF_LDX 0x71 dst = *(uint8_t *) (src + offset) -BPF_MEM | BPF_H | BPF_LDX 0x69 dst = *(uint16_t *) (src + offset) -BPF_MEM | BPF_W | BPF_LDX 0x61 dst = *(uint32_t *) (src + offset) -BPF_MEM | BPF_DW | BPF_LDX 0x79 dst = *(uint64_t *) (src + offset) -BPF_MEM | BPF_B | BPF_ST 0x72 *(uint8_t *) (dst + offset) = imm -BPF_MEM | BPF_H | BPF_ST 0x6a *(uint16_t *) (dst + offset) = imm -BPF_MEM | BPF_W | BPF_ST 0x62 *(uint32_t *) (dst + offset) = imm -BPF_MEM | BPF_DW | BPF_ST 0x7a *(uint64_t *) (dst + offset) = imm -BPF_MEM | BPF_B | BPF_STX 0x73 *(uint8_t *) (dst + offset) = src -BPF_MEM | BPF_H | BPF_STX 0x6b *(uint16_t *) (dst + offset) = src -BPF_MEM | BPF_W | BPF_STX 0x63 *(uint32_t *) (dst + offset) = src -BPF_MEM | BPF_DW | BPF_STX 0x7b *(uint64_t *) (dst + offset) = src -============================= ========= ================================== +============================= ========= ==================================== +BPF_MEM | BPF_B | BPF_LDX 0x71 dst = \*(uint8_t \*) (src + offset) +BPF_MEM | BPF_H | BPF_LDX 0x69 dst = \*(uint16_t \*) (src + offset) +BPF_MEM | BPF_W | BPF_LDX 0x61 dst = \*(uint32_t \*) (src + offset) +BPF_MEM | BPF_DW | BPF_LDX 0x79 dst = \*(uint64_t \*) (src + offset) +BPF_MEM | BPF_B | BPF_ST 0x72 \*(uint8_t \*) (dst + offset) = imm +BPF_MEM | BPF_H | BPF_ST 0x6a \*(uint16_t \*) (dst + offset) = imm +BPF_MEM | BPF_W | BPF_ST 0x62 \*(uint32_t \*) (dst + offset) = imm +BPF_MEM | BPF_DW | BPF_ST 0x7a \*(uint64_t \*) (dst + offset) = imm +BPF_MEM | BPF_B | BPF_STX 0x73 \*(uint8_t \*) (dst + offset) = src +BPF_MEM | BPF_H | BPF_STX 0x6b \*(uint16_t \*) (dst + offset) = src +BPF_MEM | BPF_W | BPF_STX 0x63 \*(uint32_t \*) (dst + offset) = src +BPF_MEM | BPF_DW | BPF_STX 0x7b \*(uint64_t \*) (dst + offset) = src +============================= ========= ==================================== Atomic operations ----------------- From 794b4fd93c7cb7007099f4c142d88c3a9587423c Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Thu, 22 Sep 2022 09:58:20 -0700 Subject: [PATCH 18/25] Fix jump opcode table format Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index 175ac84..e7d4fd4 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -265,9 +265,9 @@ otherwise identical operations. The 4-bit 'code' field encodes the operation as below, where PC is the program counter: -======== ===== === ========================== ============ +======== ===== === ========================== ======================== code value src description notes -======== ===== === ========================== ============ +======== ===== === ========================== ======================== BPF_JA 0x00 0x0 PC += offset BPF_JMP only BPF_JEQ 0x10 any PC += offset if dst == src BPF_JGT 0x20 any PC += offset if dst > src unsigned @@ -284,7 +284,7 @@ BPF_JLT 0xa0 any PC += offset if dst < src unsigned BPF_JLE 0xb0 any PC += offset if dst <= src unsigned BPF_JSLT 0xc0 any PC += offset if dst < src signed BPF_JSLE 0xd0 any PC += offset if dst <= src signed -======== ===== === =========================== ============ +======== ===== === ========================== ======================== Helper functions ~~~~~~~~~~~~~~~~ From 96a8094ef5e643b224a276685bc2a8f299a2ea72 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Thu, 22 Sep 2022 13:17:16 -0700 Subject: [PATCH 19/25] Fix Appendix rows for opcode 0x18 Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index e7d4fd4..bec655c 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -521,13 +521,13 @@ opcode src imm description referenc 0x15 0x0 any if dst == imm goto +offset `Jump instructions`_ 0x16 0x0 any if (uint32_t)dst == imm goto +offset `Jump instructions`_ 0x17 0x0 any dst -= imm `Arithmetic instructions`_ -0x18 0x0 0x00 dst = imm64 `64-bit immediate instructions`_ -0x18 0x1 0x00 dst = map_by_fd(imm) `64-bit immediate instructions`_ -0x18 0x2 0x00 dst = mva(map_by_fd(imm)) + next_imm `64-bit immediate instructions`_ -0x18 0x3 0x00 dst = variable_addr(imm) `64-bit immediate instructions`_ -0x18 0x4 0x00 dst = code_addr(imm) `64-bit immediate instructions`_ -0x18 0x5 0x00 dst = map_by_idx(imm) `64-bit immediate instructions`_ -0x18 0x6 0x00 dst = mva(map_by_idx(imm)) + next_imm `64-bit immediate instructions`_ +0x18 0x0 any dst = imm64 `64-bit immediate instructions`_ +0x18 0x1 any dst = map_by_fd(imm) `64-bit immediate instructions`_ +0x18 0x2 any dst = mva(map_by_fd(imm)) + next_imm `64-bit immediate instructions`_ +0x18 0x3 any dst = variable_addr(imm) `64-bit immediate instructions`_ +0x18 0x4 any dst = code_addr(imm) `64-bit immediate instructions`_ +0x18 0x5 any dst = map_by_idx(imm) `64-bit immediate instructions`_ +0x18 0x6 any dst = mva(map_by_idx(imm)) + next_imm `64-bit immediate instructions`_ 0x1c any 0x00 dst = (uint32_t)(dst - src) `Arithmetic instructions`_ 0x1d any 0x00 if dst == src goto +offset `Jump instructions`_ 0x1e any 0x00 if (uint32_t)dst == (uint32_t)src goto +offset `Jump instructions`_ From b786e4562b994b0b57759b8f66c5aa85c79c3cd3 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Thu, 22 Sep 2022 14:27:06 -0700 Subject: [PATCH 20/25] Fix modulo 0 result Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index bec655c..32cc9c5 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -171,7 +171,7 @@ BPF_AND 0x50 dst &= src BPF_LSH 0x60 dst <<= src BPF_RSH 0x70 dst >>= src BPF_NEG 0x80 dst = ~src -BPF_MOD 0x90 dst = (src != 0) ? (dst % src) : src +BPF_MOD 0x90 dst = (src != 0) ? (dst % src) : dst BPF_XOR 0xa0 dst ^= src BPF_MOV 0xb0 dst = src BPF_ARSH 0xc0 sign extending shift right @@ -185,7 +185,7 @@ meaning the 64-bit or 32-bit value will wrap. If eBPF program execution would result in division by zero, the destination register is instead set to zero. If execution would result in modulo by zero, -the destination register is instead set to the source value. +the destination register is instead left unchanged. Examples: @@ -605,11 +605,11 @@ opcode src imm description referenc 0x85 0x1 any call PC += offset `eBPF functions`_ 0x85 0x2 any call runtime function imm `Runtime functions`_ 0x87 0x0 0x00 dst = -dst `Arithmetic instructions`_ -0x94 0x0 any dst = (uint32_t)((imm != 0) ? (dst % imm) : imm) `Arithmetic instructions`_ +0x94 0x0 any dst = (uint32_t)((imm != 0) ? (dst % imm) : dst) `Arithmetic instructions`_ 0x95 0x0 0x00 return `Jump instructions`_ -0x97 0x0 any dst = (imm != 0) ? (dst % imm) : imm `Arithmetic instructions`_ -0x9c any 0x00 dst = (uint32_t)((src != 0) ? (dst % src) : src) `Arithmetic instructions`_ -0x9f any 0x00 dst = (src != 0) ? (dst % src) : src `Arithmetic instructions`_ +0x97 0x0 any dst = (imm != 0) ? (dst % imm) : dst `Arithmetic instructions`_ +0x9c any 0x00 dst = (uint32_t)((src != 0) ? (dst % src) : dst) `Arithmetic instructions`_ +0x9f any 0x00 dst = (src != 0) ? (dst % src) : dst `Arithmetic instructions`_ 0xa4 0x0 any dst = (uint32_t)(dst ^ imm) `Arithmetic instructions`_ 0xa5 0x0 any if dst < imm goto +offset `Jump instructions`_ 0xa6 0x0 any if (uint32_t)dst < imm goto +offset `Jump instructions`_ From ef22d47dfed816a6b6874d62c63e65ee9f5b69c7 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Thu, 22 Sep 2022 17:52:05 -0700 Subject: [PATCH 21/25] Fix 4-bit code field values in tables Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 52 +++++++++++++++--------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index 32cc9c5..f3c6c1e 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -109,9 +109,9 @@ The encoding of the 'opcode' field varies and can be determined from the three least significant bits (LSB) of the 'opcode' field which holds the "instruction class", as follows: -========= ===== =============================== ================= +========= ===== =============================== =================================== class value description reference -========= ===== =============================== ================= +========= ===== =============================== =================================== BPF_LD 0x00 non-standard load operations `Load and store instructions`_ BPF_LDX 0x01 load into register operations `Load and store instructions`_ BPF_ST 0x02 store from immediate operations `Load and store instructions`_ @@ -120,7 +120,7 @@ BPF_ALU 0x04 32-bit arithmetic operations `Arithmetic and jump instruct BPF_JMP 0x05 64-bit jump operations `Arithmetic and jump instructions`_ BPF_JMP32 0x06 32-bit jump operations `Arithmetic and jump instructions`_ BPF_ALU64 0x07 64-bit arithmetic operations `Arithmetic and jump instructions`_ -========= ===== =============================== ================= +========= ===== =============================== =================================== Arithmetic and jump instructions ================================ @@ -140,12 +140,12 @@ code source the source operand location, which unless otherwise specified is one of: - ====== ===== ======================================== + ====== ===== ========================================== source value description - ====== ===== ======================================== + ====== ===== ========================================== BPF_K 0x00 use 32-bit 'imm' value as source operand BPF_X 0x08 use 'src' register value as source operand - ====== ===== ======================================== + ====== ===== ========================================== instruction class the instruction class (see `Instruction classes`_) @@ -159,9 +159,9 @@ otherwise identical operations. The 4-bit 'code' field encodes the operation as follows: -======== ===== ================================================= +======== ===== ========================================================== code value description -======== ===== ================================================= +======== ===== ========================================================== BPF_ADD 0x00 dst += src BPF_SUB 0x10 dst -= src BPF_MUL 0x20 dst \*= src @@ -176,7 +176,7 @@ BPF_XOR 0xa0 dst ^= src BPF_MOV 0xb0 dst = src BPF_ARSH 0xc0 sign extending shift right BPF_END 0xd0 byte swap operations (see `Byte swap instructions`_ below) -======== ===== ================================================= +======== ===== ========================================================== where 'src' is the source operand value. @@ -268,22 +268,22 @@ The 4-bit 'code' field encodes the operation as below, where PC is the program c ======== ===== === ========================== ======================== code value src description notes ======== ===== === ========================== ======================== -BPF_JA 0x00 0x0 PC += offset BPF_JMP only -BPF_JEQ 0x10 any PC += offset if dst == src -BPF_JGT 0x20 any PC += offset if dst > src unsigned -BPF_JGE 0x30 any PC += offset if dst >= src unsigned -BPF_JSET 0x40 any PC += offset if dst & src -BPF_JNE 0x50 any PC += offset if dst != src -BPF_JSGT 0x60 any PC += offset if dst > src signed -BPF_JSGE 0x70 any PC += offset if dst >= src signed -BPF_CALL 0x80 0x0 call helper function imm see `Helper functions`_ -BPF_CALL 0x80 0x1 call PC += offset see `eBPF functions`_ -BPF_CALL 0x80 0x2 call runtime function imm see `Runtime functions`_ -BPF_EXIT 0x95 0x0 return BPF_JMP only -BPF_JLT 0xa0 any PC += offset if dst < src unsigned -BPF_JLE 0xb0 any PC += offset if dst <= src unsigned -BPF_JSLT 0xc0 any PC += offset if dst < src signed -BPF_JSLE 0xd0 any PC += offset if dst <= src signed +BPF_JA 0x0 0x0 PC += offset BPF_JMP only +BPF_JEQ 0x1 any PC += offset if dst == src +BPF_JGT 0x2 any PC += offset if dst > src unsigned +BPF_JGE 0x3 any PC += offset if dst >= src unsigned +BPF_JSET 0x4 any PC += offset if dst & src +BPF_JNE 0x5 any PC += offset if dst != src +BPF_JSGT 0x6 any PC += offset if dst > src signed +BPF_JSGE 0x7 any PC += offset if dst >= src signed +BPF_CALL 0x8 0x0 call helper function imm see `Helper functions`_ +BPF_CALL 0x8 0x1 call PC += offset see `eBPF functions`_ +BPF_CALL 0x8 0x2 call runtime function imm see `Runtime functions`_ +BPF_EXIT 0x9 0x0 return BPF_JMP only +BPF_JLT 0xa any PC += offset if dst < src unsigned +BPF_JLE 0xb any PC += offset if dst <= src unsigned +BPF_JSLT 0xc any PC += offset if dst < src signed +BPF_JSLE 0xd any PC += offset if dst <= src signed ======== ===== === ========================== ======================== Helper functions @@ -401,7 +401,7 @@ The 'imm' field is used to encode the actual atomic operation. Simple atomic operation use a subset of the values defined to encode arithmetic operations in the 'imm' field to encode the atomic operation: -======== ===== =========== +======== ===== =========== imm value description ======== ===== =========== BPF_ADD 0x00 atomic add From d491049dc6cf649e8ba28a6dbfe462e92e801746 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Thu, 22 Sep 2022 18:19:16 -0700 Subject: [PATCH 22/25] Fix URL Signed-off-by: Dave Thaler --- isa/kernel.org/linux-notes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isa/kernel.org/linux-notes.rst b/isa/kernel.org/linux-notes.rst index fac86f3..e7f7924 100644 --- a/isa/kernel.org/linux-notes.rst +++ b/isa/kernel.org/linux-notes.rst @@ -37,7 +37,7 @@ Linux uses BTF ids to identify variables. Legacy BPF Packet access instructions ===================================== -As mentioned in the `ISA standard documentation `_, +As mentioned in the `ISA standard documentation `_, Linux has special eBPF instructions for access to packet data that have been carried over from classic BPF to retain the performance of legacy socket filters running in the eBPF interpreter. From 3b9470afd789bc09adfb4c36301a850d3f628a5e Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Sat, 24 Sep 2022 11:27:48 -0700 Subject: [PATCH 23/25] Fix definition of modulo Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index f3c6c1e..e809e3f 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -211,10 +211,10 @@ where '(uint32_t)' indicates truncation to 32 bits. Also note that the modulo operation often varies by language when the dividend or divisor are negative, where Python, Ruby, etc. differ from C, Go, Java, etc. This specification requires that -modulo use the widely accepted mathematical definition given by Donald -Knuth and implemented in C, Go, etc.: +modulo use truncated division (where -13 % 3 == -1) as implemented +in C, Go, etc.: - a % n = a - n * floor(a / n) + a % n = a - n * trunc(a / n) Byte swap instructions ~~~~~~~~~~~~~~~~~~~~~~ From 5bd09abcf51edba91c02441e2eff80b3398e7671 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Sun, 25 Sep 2022 08:17:39 -0700 Subject: [PATCH 24/25] Fix formatting Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index e809e3f..af9dc0c 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -315,8 +315,8 @@ but otherwise the same considerations apply. eBPF functions ~~~~~~~~~~~~~~ eBPF functions are functions exposed by the same eBPF program as the caller, -and are referenced by offset from the call instruction, similar to 'BPF_JA'. -A 'BPF_EXIT' within the eBPF function will return to the caller. +and are referenced by offset from the call instruction, similar to ``BPF_JA``. +A ``BPF_EXIT`` within the eBPF function will return to the caller. Load and store instructions =========================== From 847b1cd359274c33344dc4a6bdc839f1058f2686 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Fri, 18 Nov 2022 13:35:12 -0800 Subject: [PATCH 25/25] Fix typo Signed-off-by: Dave Thaler --- isa/kernel.org/instruction-set.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isa/kernel.org/instruction-set.rst b/isa/kernel.org/instruction-set.rst index af9dc0c..0659345 100644 --- a/isa/kernel.org/instruction-set.rst +++ b/isa/kernel.org/instruction-set.rst @@ -620,7 +620,7 @@ opcode src imm description referenc 0xaf any 0x00 dst ^= src `Arithmetic instructions`_ 0xb4 0x0 any dst = (uint32_t) imm `Arithmetic instructions`_ 0xb5 0x0 any if dst <= imm goto +offset `Jump instructions`_ -0xa6 0x0 any if (uint32_t)dst <= imm goto +offset `Jump instructions`_ +0xb6 0x0 any if (uint32_t)dst <= imm goto +offset `Jump instructions`_ 0xb7 0x0 any dst = imm `Arithmetic instructions`_ 0xbc any 0x00 dst = (uint32_t) src `Arithmetic instructions`_ 0xbd any 0x00 if dst <= src goto +offset `Jump instructions`_