1*de68c051SAndrea Righi /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2*de68c051SAndrea Righi /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ 3*de68c051SAndrea Righi #pragma once 4*de68c051SAndrea Righi 5*de68c051SAndrea Righi #ifndef PAGE_SIZE 6*de68c051SAndrea Righi #define PAGE_SIZE __PAGE_SIZE 7*de68c051SAndrea Righi /* 8*de68c051SAndrea Righi * for older kernels try sizeof(struct genradix_node) 9*de68c051SAndrea Righi * or flexible: 10*de68c051SAndrea Righi * static inline long __bpf_page_size(void) { 11*de68c051SAndrea Righi * return bpf_core_enum_value(enum page_size_enum___l, __PAGE_SIZE___l) ?: sizeof(struct genradix_node); 12*de68c051SAndrea Righi * } 13*de68c051SAndrea Righi * but generated code is not great. 14*de68c051SAndrea Righi */ 15*de68c051SAndrea Righi #endif 16*de68c051SAndrea Righi 17*de68c051SAndrea Righi #if defined(__BPF_FEATURE_ADDR_SPACE_CAST) && !defined(BPF_ARENA_FORCE_ASM) 18*de68c051SAndrea Righi #define __arena __attribute__((address_space(1))) 19*de68c051SAndrea Righi #define __arena_global __attribute__((address_space(1))) 20*de68c051SAndrea Righi #define cast_kern(ptr) /* nop for bpf prog. emitted by LLVM */ 21*de68c051SAndrea Righi #define cast_user(ptr) /* nop for bpf prog. emitted by LLVM */ 22*de68c051SAndrea Righi #else 23*de68c051SAndrea Righi 24*de68c051SAndrea Righi /* emit instruction: 25*de68c051SAndrea Righi * rX = rX .off = BPF_ADDR_SPACE_CAST .imm32 = (dst_as << 16) | src_as 26*de68c051SAndrea Righi * 27*de68c051SAndrea Righi * This is a workaround for LLVM compiler versions without 28*de68c051SAndrea Righi * __BPF_FEATURE_ADDR_SPACE_CAST that do not automatically cast between arena 29*de68c051SAndrea Righi * pointers and native kernel/userspace ones. In this case we explicitly do so 30*de68c051SAndrea Righi * with cast_kern() and cast_user(). E.g., in the Linux kernel tree, 31*de68c051SAndrea Righi * tools/testing/selftests/bpf includes tests that use these macros to implement 32*de68c051SAndrea Righi * linked lists and hashtables backed by arena memory. In sched_ext, we use 33*de68c051SAndrea Righi * cast_kern() and cast_user() for compatibility with older LLVM toolchains. 34*de68c051SAndrea Righi */ 35*de68c051SAndrea Righi #ifndef bpf_addr_space_cast 36*de68c051SAndrea Righi #define bpf_addr_space_cast(var, dst_as, src_as)\ 37*de68c051SAndrea Righi asm volatile(".byte 0xBF; \ 38*de68c051SAndrea Righi .ifc %[reg], r0; \ 39*de68c051SAndrea Righi .byte 0x00; \ 40*de68c051SAndrea Righi .endif; \ 41*de68c051SAndrea Righi .ifc %[reg], r1; \ 42*de68c051SAndrea Righi .byte 0x11; \ 43*de68c051SAndrea Righi .endif; \ 44*de68c051SAndrea Righi .ifc %[reg], r2; \ 45*de68c051SAndrea Righi .byte 0x22; \ 46*de68c051SAndrea Righi .endif; \ 47*de68c051SAndrea Righi .ifc %[reg], r3; \ 48*de68c051SAndrea Righi .byte 0x33; \ 49*de68c051SAndrea Righi .endif; \ 50*de68c051SAndrea Righi .ifc %[reg], r4; \ 51*de68c051SAndrea Righi .byte 0x44; \ 52*de68c051SAndrea Righi .endif; \ 53*de68c051SAndrea Righi .ifc %[reg], r5; \ 54*de68c051SAndrea Righi .byte 0x55; \ 55*de68c051SAndrea Righi .endif; \ 56*de68c051SAndrea Righi .ifc %[reg], r6; \ 57*de68c051SAndrea Righi .byte 0x66; \ 58*de68c051SAndrea Righi .endif; \ 59*de68c051SAndrea Righi .ifc %[reg], r7; \ 60*de68c051SAndrea Righi .byte 0x77; \ 61*de68c051SAndrea Righi .endif; \ 62*de68c051SAndrea Righi .ifc %[reg], r8; \ 63*de68c051SAndrea Righi .byte 0x88; \ 64*de68c051SAndrea Righi .endif; \ 65*de68c051SAndrea Righi .ifc %[reg], r9; \ 66*de68c051SAndrea Righi .byte 0x99; \ 67*de68c051SAndrea Righi .endif; \ 68*de68c051SAndrea Righi .short %[off]; \ 69*de68c051SAndrea Righi .long %[as]" \ 70*de68c051SAndrea Righi : [reg]"+r"(var) \ 71*de68c051SAndrea Righi : [off]"i"(BPF_ADDR_SPACE_CAST) \ 72*de68c051SAndrea Righi , [as]"i"((dst_as << 16) | src_as)); 73*de68c051SAndrea Righi #endif 74*de68c051SAndrea Righi 75*de68c051SAndrea Righi #define __arena 76*de68c051SAndrea Righi #define __arena_global SEC(".addr_space.1") 77*de68c051SAndrea Righi #define cast_kern(ptr) bpf_addr_space_cast(ptr, 0, 1) 78*de68c051SAndrea Righi #define cast_user(ptr) bpf_addr_space_cast(ptr, 1, 0) 79*de68c051SAndrea Righi #endif 80*de68c051SAndrea Righi 81*de68c051SAndrea Righi void __arena* bpf_arena_alloc_pages(void *map, void __arena *addr, __u32 page_cnt, 82*de68c051SAndrea Righi int node_id, __u64 flags) __ksym __weak; 83*de68c051SAndrea Righi void bpf_arena_free_pages(void *map, void __arena *ptr, __u32 page_cnt) __ksym __weak; 84*de68c051SAndrea Righi 85*de68c051SAndrea Righi /* 86*de68c051SAndrea Righi * Note that cond_break can only be portably used in the body of a breakable 87*de68c051SAndrea Righi * construct, whereas can_loop can be used anywhere. 88*de68c051SAndrea Righi */ 89*de68c051SAndrea Righi #ifdef TEST 90*de68c051SAndrea Righi #define can_loop true 91*de68c051SAndrea Righi #define __cond_break(expr) expr 92*de68c051SAndrea Righi #else 93*de68c051SAndrea Righi #ifdef __BPF_FEATURE_MAY_GOTO 94*de68c051SAndrea Righi #define can_loop \ 95*de68c051SAndrea Righi ({ __label__ l_break, l_continue; \ 96*de68c051SAndrea Righi bool ret = true; \ 97*de68c051SAndrea Righi asm volatile goto("may_goto %l[l_break]" \ 98*de68c051SAndrea Righi :::: l_break); \ 99*de68c051SAndrea Righi goto l_continue; \ 100*de68c051SAndrea Righi l_break: ret = false; \ 101*de68c051SAndrea Righi l_continue:; \ 102*de68c051SAndrea Righi ret; \ 103*de68c051SAndrea Righi }) 104*de68c051SAndrea Righi 105*de68c051SAndrea Righi #define __cond_break(expr) \ 106*de68c051SAndrea Righi ({ __label__ l_break, l_continue; \ 107*de68c051SAndrea Righi asm volatile goto("may_goto %l[l_break]" \ 108*de68c051SAndrea Righi :::: l_break); \ 109*de68c051SAndrea Righi goto l_continue; \ 110*de68c051SAndrea Righi l_break: expr; \ 111*de68c051SAndrea Righi l_continue:; \ 112*de68c051SAndrea Righi }) 113*de68c051SAndrea Righi #else 114*de68c051SAndrea Righi #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 115*de68c051SAndrea Righi #define can_loop \ 116*de68c051SAndrea Righi ({ __label__ l_break, l_continue; \ 117*de68c051SAndrea Righi bool ret = true; \ 118*de68c051SAndrea Righi asm volatile goto("1:.byte 0xe5; \ 119*de68c051SAndrea Righi .byte 0; \ 120*de68c051SAndrea Righi .long ((%l[l_break] - 1b - 8) / 8) & 0xffff; \ 121*de68c051SAndrea Righi .short 0" \ 122*de68c051SAndrea Righi :::: l_break); \ 123*de68c051SAndrea Righi goto l_continue; \ 124*de68c051SAndrea Righi l_break: ret = false; \ 125*de68c051SAndrea Righi l_continue:; \ 126*de68c051SAndrea Righi ret; \ 127*de68c051SAndrea Righi }) 128*de68c051SAndrea Righi 129*de68c051SAndrea Righi #define __cond_break(expr) \ 130*de68c051SAndrea Righi ({ __label__ l_break, l_continue; \ 131*de68c051SAndrea Righi asm volatile goto("1:.byte 0xe5; \ 132*de68c051SAndrea Righi .byte 0; \ 133*de68c051SAndrea Righi .long ((%l[l_break] - 1b - 8) / 8) & 0xffff; \ 134*de68c051SAndrea Righi .short 0" \ 135*de68c051SAndrea Righi :::: l_break); \ 136*de68c051SAndrea Righi goto l_continue; \ 137*de68c051SAndrea Righi l_break: expr; \ 138*de68c051SAndrea Righi l_continue:; \ 139*de68c051SAndrea Righi }) 140*de68c051SAndrea Righi #else 141*de68c051SAndrea Righi #define can_loop \ 142*de68c051SAndrea Righi ({ __label__ l_break, l_continue; \ 143*de68c051SAndrea Righi bool ret = true; \ 144*de68c051SAndrea Righi asm volatile goto("1:.byte 0xe5; \ 145*de68c051SAndrea Righi .byte 0; \ 146*de68c051SAndrea Righi .long (((%l[l_break] - 1b - 8) / 8) & 0xffff) << 16; \ 147*de68c051SAndrea Righi .short 0" \ 148*de68c051SAndrea Righi :::: l_break); \ 149*de68c051SAndrea Righi goto l_continue; \ 150*de68c051SAndrea Righi l_break: ret = false; \ 151*de68c051SAndrea Righi l_continue:; \ 152*de68c051SAndrea Righi ret; \ 153*de68c051SAndrea Righi }) 154*de68c051SAndrea Righi 155*de68c051SAndrea Righi #define __cond_break(expr) \ 156*de68c051SAndrea Righi ({ __label__ l_break, l_continue; \ 157*de68c051SAndrea Righi asm volatile goto("1:.byte 0xe5; \ 158*de68c051SAndrea Righi .byte 0; \ 159*de68c051SAndrea Righi .long (((%l[l_break] - 1b - 8) / 8) & 0xffff) << 16; \ 160*de68c051SAndrea Righi .short 0" \ 161*de68c051SAndrea Righi :::: l_break); \ 162*de68c051SAndrea Righi goto l_continue; \ 163*de68c051SAndrea Righi l_break: expr; \ 164*de68c051SAndrea Righi l_continue:; \ 165*de68c051SAndrea Righi }) 166*de68c051SAndrea Righi #endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */ 167*de68c051SAndrea Righi #endif /* __BPF_FEATURE_MAY_GOTO */ 168*de68c051SAndrea Righi #endif /* TEST */ 169*de68c051SAndrea Righi 170*de68c051SAndrea Righi #define cond_break __cond_break(break) 171*de68c051SAndrea Righi #define cond_break_label(label) __cond_break(goto label) 172*de68c051SAndrea Righi 173*de68c051SAndrea Righi 174*de68c051SAndrea Righi void bpf_preempt_disable(void) __weak __ksym; 175*de68c051SAndrea Righi void bpf_preempt_enable(void) __weak __ksym; 176