| /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ |
| /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ |
| #pragma once |
| |
| #ifndef PAGE_SIZE |
| #define PAGE_SIZE __PAGE_SIZE |
| /* |
| * for older kernels try sizeof(struct genradix_node) |
| * or flexible: |
| * static inline long __bpf_page_size(void) { |
| * return bpf_core_enum_value(enum page_size_enum___l, __PAGE_SIZE___l) ?: sizeof(struct genradix_node); |
| * } |
| * but generated code is not great. |
| */ |
| #endif |
| |
| #if defined(__BPF_FEATURE_ADDR_SPACE_CAST) && !defined(BPF_ARENA_FORCE_ASM) |
| #define __arena __attribute__((address_space(1))) |
| #define __arena_global __attribute__((address_space(1))) |
| #define cast_kern(ptr) /* nop for bpf prog. emitted by LLVM */ |
| #define cast_user(ptr) /* nop for bpf prog. emitted by LLVM */ |
| #else |
| |
| /* emit instruction: |
| * rX = rX .off = BPF_ADDR_SPACE_CAST .imm32 = (dst_as << 16) | src_as |
| * |
| * This is a workaround for LLVM compiler versions without |
| * __BPF_FEATURE_ADDR_SPACE_CAST that do not automatically cast between arena |
| * pointers and native kernel/userspace ones. In this case we explicitly do so |
| * with cast_kern() and cast_user(). E.g., in the Linux kernel tree, |
| * tools/testing/selftests/bpf includes tests that use these macros to implement |
| * linked lists and hashtables backed by arena memory. In sched_ext, we use |
| * cast_kern() and cast_user() for compatibility with older LLVM toolchains. |
| */ |
| #ifndef bpf_addr_space_cast |
| #define bpf_addr_space_cast(var, dst_as, src_as)\ |
| asm volatile(".byte 0xBF; \ |
| .ifc %[reg], r0; \ |
| .byte 0x00; \ |
| .endif; \ |
| .ifc %[reg], r1; \ |
| .byte 0x11; \ |
| .endif; \ |
| .ifc %[reg], r2; \ |
| .byte 0x22; \ |
| .endif; \ |
| .ifc %[reg], r3; \ |
| .byte 0x33; \ |
| .endif; \ |
| .ifc %[reg], r4; \ |
| .byte 0x44; \ |
| .endif; \ |
| .ifc %[reg], r5; \ |
| .byte 0x55; \ |
| .endif; \ |
| .ifc %[reg], r6; \ |
| .byte 0x66; \ |
| .endif; \ |
| .ifc %[reg], r7; \ |
| .byte 0x77; \ |
| .endif; \ |
| .ifc %[reg], r8; \ |
| .byte 0x88; \ |
| .endif; \ |
| .ifc %[reg], r9; \ |
| .byte 0x99; \ |
| .endif; \ |
| .short %[off]; \ |
| .long %[as]" \ |
| : [reg]"+r"(var) \ |
| : [off]"i"(BPF_ADDR_SPACE_CAST) \ |
| , [as]"i"((dst_as << 16) | src_as)); |
| #endif |
| |
| #define __arena |
| #define __arena_global SEC(".addr_space.1") |
| #define cast_kern(ptr) bpf_addr_space_cast(ptr, 0, 1) |
| #define cast_user(ptr) bpf_addr_space_cast(ptr, 1, 0) |
| #endif |
| |
| void __arena* bpf_arena_alloc_pages(void *map, void __arena *addr, __u32 page_cnt, |
| int node_id, __u64 flags) __ksym __weak; |
| void bpf_arena_free_pages(void *map, void __arena *ptr, __u32 page_cnt) __ksym __weak; |
| |
| /* |
| * Note that cond_break can only be portably used in the body of a breakable |
| * construct, whereas can_loop can be used anywhere. |
| */ |
| #ifdef TEST |
| #define can_loop true |
| #define __cond_break(expr) expr |
| #else |
| #ifdef __BPF_FEATURE_MAY_GOTO |
| #define can_loop \ |
| ({ __label__ l_break, l_continue; \ |
| bool ret = true; \ |
| asm volatile goto("may_goto %l[l_break]" \ |
| :::: l_break); \ |
| goto l_continue; \ |
| l_break: ret = false; \ |
| l_continue:; \ |
| ret; \ |
| }) |
| |
| #define __cond_break(expr) \ |
| ({ __label__ l_break, l_continue; \ |
| asm volatile goto("may_goto %l[l_break]" \ |
| :::: l_break); \ |
| goto l_continue; \ |
| l_break: expr; \ |
| l_continue:; \ |
| }) |
| #else |
| #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
| #define can_loop \ |
| ({ __label__ l_break, l_continue; \ |
| bool ret = true; \ |
| asm volatile goto("1:.byte 0xe5; \ |
| .byte 0; \ |
| .long ((%l[l_break] - 1b - 8) / 8) & 0xffff; \ |
| .short 0" \ |
| :::: l_break); \ |
| goto l_continue; \ |
| l_break: ret = false; \ |
| l_continue:; \ |
| ret; \ |
| }) |
| |
| #define __cond_break(expr) \ |
| ({ __label__ l_break, l_continue; \ |
| asm volatile goto("1:.byte 0xe5; \ |
| .byte 0; \ |
| .long ((%l[l_break] - 1b - 8) / 8) & 0xffff; \ |
| .short 0" \ |
| :::: l_break); \ |
| goto l_continue; \ |
| l_break: expr; \ |
| l_continue:; \ |
| }) |
| #else |
| #define can_loop \ |
| ({ __label__ l_break, l_continue; \ |
| bool ret = true; \ |
| asm volatile goto("1:.byte 0xe5; \ |
| .byte 0; \ |
| .long (((%l[l_break] - 1b - 8) / 8) & 0xffff) << 16; \ |
| .short 0" \ |
| :::: l_break); \ |
| goto l_continue; \ |
| l_break: ret = false; \ |
| l_continue:; \ |
| ret; \ |
| }) |
| |
| #define __cond_break(expr) \ |
| ({ __label__ l_break, l_continue; \ |
| asm volatile goto("1:.byte 0xe5; \ |
| .byte 0; \ |
| .long (((%l[l_break] - 1b - 8) / 8) & 0xffff) << 16; \ |
| .short 0" \ |
| :::: l_break); \ |
| goto l_continue; \ |
| l_break: expr; \ |
| l_continue:; \ |
| }) |
| #endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */ |
| #endif /* __BPF_FEATURE_MAY_GOTO */ |
| #endif /* TEST */ |
| |
| #define cond_break __cond_break(break) |
| #define cond_break_label(label) __cond_break(goto label) |
| |
| |
| void bpf_preempt_disable(void) __weak __ksym; |
| void bpf_preempt_enable(void) __weak __ksym; |