Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

eBPF.md: Add missing instructions and instruction variants (32-bit jumps, atomic instructions, call and lddw variants) #26

Open
wants to merge 12 commits into
base: master
Choose a base branch
from

Conversation

qmonnet
Copy link
Contributor

@qmonnet qmonnet commented Jan 28, 2019

Reflecting the recent addition of 32-bit jump instruction class support
to the Linux kernel [0], add the related instructions to the unofficial
spec to keep it up-to-date.

[0] merge commit ae575c8a9868 ("Merge branch 'jmp32-insns'")
Cc: @JiongWang

@qmonnet
Copy link
Contributor Author

qmonnet commented Jan 19, 2021

Now we also want atomic operations.
https://lore.kernel.org/bpf/[email protected]/t/#u

Copy link

@MJUPHPP MJUPHPP left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no

The jump-32bit instruction class added support for jumps with 32-bit
operands.

This is supported in the kernel since commit:
d405c7407a54 ("bpf: allocate 0x06 to new eBPF instruction class JMP32")
@qmonnet qmonnet changed the title eBPF.md: add Jump-32bit class instructions eBPF.md: Add missing instructions and instruction variants (32-bit jumps, atomic instructions, call and lddw variants) Aug 10, 2022
@qmonnet
Copy link
Contributor Author

qmonnet commented Aug 10, 2022

I updated this PR with more instructions and variants (Cc @dthaler).

The "load immediate" instruction can have a specific meaning for some
values of the source register. If it is set to BPF_PSEUDO_MAP_FD (1),
then the verifier considers the immediate as a file descriptor to a map,
and replaces by a pointer accordingly.

This is supported in the kernel since commit:
0246e64d9a5f ("bpf: handle pseudo BPF_LD_IMM64 insn")
In addition to BPF_PSEUDO_MAP (1), the source register of a "load
immediate" instruction can be set to BPF_PSEUDO_MAP_VALUE (2). In that
case, the verifier expects: a map file descriptor in the immediate field
of the first half of the 128-bit instruction, and an offset in the
immediate field of the second half of the instruction (remember that
lddw spans over two regular instruction fields, 16 bytes in total). It
uses this offset to load an address residing in the value of the first
entry of the map referended by the file descriptor, at the provided
offset within that value. Currently, only single-entry array maps are
supported. Maps with multiple entries might be supported in the future
by using the offset fields as indices within the map.

This is supported in the kernel since commit:
d8eca5bbb2be ("bpf: implement lookup-free direct value access for maps")
When the source register of a "load immediate" instruction is set to 3,
then the verifier considers the immediate as a BTF id to a kernel
variable, and replaces it by the relevant pointer.

This is supported in the kernel since commit:
4976b718c355 ("bpf: Introduce pseudo_btf_id")
When the source register of a "load immediate" instruction is set to 4,
the verifier considers the immediate value as an instruction offset for
a BPF function in the program. Once loaded into the destination
register, this function can be passed to the bpf_for_each_map_elem()
helper function and used as a callback.

This is supported in the kernel since commit:
69c087ba6225 ("bpf: Add bpf_for_each_map_elem() helper")
eBPF.md Outdated Show resolved Hide resolved
In addition to BPF_PSEUDO_MAP (1) and BPF_PSEUDO_MAP_VALUE (2), the
source register of a "load immediate" instruction can have other
map-related values:

  - When set to BPF_PSEUDO_MAP_IDX (5), the verifier expects a map index
    (not a file descriptor) as the immediate, and replaces it with a
    pointer to the related map.
  - When set to BPF_PSEUDO_MAP_VALUE_IDX (6), the verifier behaves like
    for BPF_PSEUDO_MAP_VALUE, except that it expects a map index instead
    of a file descriptor.

Both values are supported in the kernel since commit:
387544bfa291 ("bpf: Introduce fd_idx")
By default, the call instruction calls into a helper function, one of
the specific functions in the kernel that have been created for BPF
programs.

When the source register of a call instruction is set to BPF_PSEUDO_CALL
(1), the call refers to a BPF function instead, for which the offset is
passed in the immediate field.

This is supported in the kernel since commit:
cc8b0b92a169 ("bpf: introduce function calls (function boundaries)")
When the source register of a call instruction is set to
BPF_PSEUDO_KFUNC_CALL (2), then the call refers to a kernel function.
This is different from a helper function, in that the function is not
specific to BPF programs (but it must be explicitly marked as call-able
from BPF programs).

This is supported in the kernel since commit:
e6ac2450d6de ("bpf: Support bpf program calling kernel function")
Atomic add instructions have been available since the early days of
eBPF, although BPF_XADD has later been renamed into BPF_ATOMIC. Comes in
32 and 64 bits flavours.

This is supported in the kernel since commit:
bd4cf0ed331a ("net: filter: rework/optimize internal BPF interpreter's instruction set")
Atomic fetch add instructions are a variant of the "atomic"
instructions, when BPF_FETCH (1) and BPF_ADD (0) are added to the
immediate field.

This is supported in the kernel since commit:
5ca419f2864a ("bpf: Add BPF_FETCH field / create atomic_fetch_add instruction")
Atomic exchange and atomic compare-and-write are selected when the
immediate value for an atomic operation is set to BPF_XCHG (0xe0) |
BPF_FETCH (1) and BPF_CMPXCHG (0xf0) | BPF_FETCH (1), respectively.

This is supported in the kernel since commit:
5ffa25502b5a ("bpf: Add instructions for atomic_[cmp]xchg")
The instructions are selected when the immediate field of an atomic
instruction is set to BPF_OR (0x40), BPF_AND (0x50), or BPF_XOR (0xa0),
instead of BPF_ADD (0), and can possibly get the BPF_FETCH (1) flag as
well.

This is supported in the kernel since commit:
981f94c3e921 ("bpf: Add bitwise atomic instructions")
0xcd | jslt dst, src, +off | PC += off if dst < src (signed)
0xd5 | jsle dst, imm, +off | PC += off if dst <= imm (signed)
0xdd | jsle dst, src, +off | PC += off if dst <= src (signed)
0x85 (src = 0) | call imm | Helper function call

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we get different mnemonics for each of the call variants?

In bpf_conformance I was proposing:
call [modifier] imm

Where [modifier] is optional and can be one of:
helper -> src = 0
local -> src = 1
runtime -> src = 2

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback! I don't mind much either way, but let's see what syntax makes it to the Linux docs if the table gets updated, maybe? This PR has been sitting for nearly four years and I updated mostly to help Dave with the eBPF specs, at this point I doubt it will ever get merged.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's awesome. I didn't realize there was an official set of mnemonics as LLVM and GNU bintools seem to have wildly different disassembly outputs.

I just want to make sure the bpf_conformance tool has the "correct" ones.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there's anything official, but I know @dthaler intended to have the table merged to the kernel docs (Alexei pushed back initially, at least from having them in the official spec - Not sure where things are right now, I haven't been able to follow over the last weeks). If this happens, it would probably make the document in the current repo irrelevant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants