176 lines
5.0 KiB
C
176 lines
5.0 KiB
C
|
|
/* 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;
|