summaryrefslogtreecommitdiff
path: root/tools/include
diff options
context:
space:
mode:
Diffstat (limited to 'tools/include')
-rw-r--r--tools/include/asm-generic/io.h28
-rw-r--r--tools/include/asm/barrier.h8
-rw-r--r--tools/include/linux/bitfield-fix-width.h236
-rw-r--r--tools/include/linux/bitfield.h49
-rw-r--r--tools/include/linux/compiler.h5
-rw-r--r--tools/include/linux/mm.h6
-rw-r--r--tools/include/linux/stddef.h10
-rw-r--r--tools/include/nolibc/Makefile19
-rw-r--r--tools/include/nolibc/arch-arm.h7
-rw-r--r--tools/include/nolibc/arch-hexagon.h159
-rw-r--r--tools/include/nolibc/arch-mips.h8
-rw-r--r--tools/include/nolibc/arch-parisc.h28
-rw-r--r--tools/include/nolibc/arch-powerpc.h7
-rw-r--r--tools/include/nolibc/arch-sh.h18
-rw-r--r--tools/include/nolibc/arch-x86.h2
-rw-r--r--tools/include/nolibc/arch.h7
-rw-r--r--tools/include/nolibc/compiler.h9
-rw-r--r--tools/include/nolibc/dirent.h25
-rw-r--r--tools/include/nolibc/err.h2
-rw-r--r--tools/include/nolibc/nolibc.h1
-rw-r--r--tools/include/nolibc/stdlib.h12
-rw-r--r--tools/include/nolibc/sys.h60
-rw-r--r--tools/include/nolibc/sys/select.h6
-rw-r--r--tools/include/nolibc/sys/sendfile.h41
-rw-r--r--tools/include/nolibc/types.h2
-rw-r--r--tools/include/nolibc/unistd.h4
-rw-r--r--tools/include/uapi/linux/bpf.h120
-rw-r--r--tools/include/uapi/linux/btf.h83
-rw-r--r--tools/include/uapi/linux/coredump.h149
-rw-r--r--tools/include/uapi/linux/netdev.h2
-rw-r--r--tools/include/uapi/linux/seccomp.h2
-rw-r--r--tools/include/uapi/linux/types.h2
32 files changed, 993 insertions, 124 deletions
diff --git a/tools/include/asm-generic/io.h b/tools/include/asm-generic/io.h
index e5a0b07ad452..0d89decdafb8 100644
--- a/tools/include/asm-generic/io.h
+++ b/tools/include/asm-generic/io.h
@@ -479,4 +479,32 @@ static inline void writesq(volatile void __iomem *addr, const void *buffer,
}
#endif
+/*
+ * ioread/iowrite for big-endian MMIO registers.
+ */
+
+#ifndef ioread32be
+#define ioread32be ioread32be
+static inline u32 ioread32be(const volatile void __iomem *addr)
+{
+ return bswap_32(readl(addr));
+}
+#endif
+
+#ifndef iowrite32be
+#define iowrite32be iowrite32be
+static inline void iowrite32be(u32 value, volatile void __iomem *addr)
+{
+ writel(bswap_32(value), addr);
+}
+#endif
+
+#ifndef iowrite64be
+#define iowrite64be iowrite64be
+static inline void iowrite64be(u64 value, volatile void __iomem *addr)
+{
+ writeq(bswap_64(value), addr);
+}
+#endif
+
#endif /* _TOOLS_ASM_GENERIC_IO_H */
diff --git a/tools/include/asm/barrier.h b/tools/include/asm/barrier.h
index 0c21678ac5e6..e7e0c7de5a2f 100644
--- a/tools/include/asm/barrier.h
+++ b/tools/include/asm/barrier.h
@@ -47,6 +47,14 @@
# define smp_mb() mb()
#endif
+#ifndef dma_rmb
+# define dma_rmb() rmb()
+#endif
+
+#ifndef dma_wmb
+# define dma_wmb() wmb()
+#endif
+
#ifndef smp_store_release
# define smp_store_release(p, v) \
do { \
diff --git a/tools/include/linux/bitfield-fix-width.h b/tools/include/linux/bitfield-fix-width.h
new file mode 100644
index 000000000000..8c2a0fa224e9
--- /dev/null
+++ b/tools/include/linux/bitfield-fix-width.h
@@ -0,0 +1,236 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _LINUX_BITFIELD_FIX_WIDTH_H
+#define _LINUX_BITFIELD_FIX_WIDTH_H
+
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+extern void __compiletime_error("value doesn't fit into mask")
+__field_overflow(void);
+
+extern void __compiletime_error("bad bitfield mask")
+__bad_mask(void);
+
+static __always_inline
+u64 field_multiplier(u64 field)
+{
+ if ((field | (field - 1)) & ((field | (field - 1)) + 1))
+ __bad_mask();
+ return field & -field;
+}
+
+static __always_inline
+u64 field_mask(u64 field)
+{
+ return field / field_multiplier(field);
+}
+
+#define field_max(field) ((typeof(field))field_mask(field))
+
+#define __assert_field(v, field) \
+ do { \
+ if (__builtin_constant_p(v) && \
+ ((v) & ~field_mask(field))) \
+ __field_overflow(); \
+ } while (0)
+
+static __always_inline
+__u8 u8_encode_bits(u8 v, u8 field)
+{
+ __assert_field(v, field);
+ return (v & field_mask(field)) * field_multiplier(field);
+}
+
+static __always_inline
+__u8 u8_replace_bits(__u8 old, u8 val, u8 field)
+{
+ return (old & ~field) | u8_encode_bits(val, field);
+}
+
+static __always_inline
+void u8p_replace_bits(__u8 *p, u8 val, u8 field)
+{
+ *p = (*p & ~field) | u8_encode_bits(val, field);
+}
+
+static __always_inline
+u8 u8_get_bits(__u8 v, u8 field)
+{
+ return (v & field) / field_multiplier(field);
+}
+
+static __always_inline
+__le16 le16_encode_bits(u16 v, u16 field)
+{
+ __assert_field(v, field);
+ return cpu_to_le16((v & field_mask(field)) * field_multiplier(field));
+}
+
+static __always_inline
+void le16p_replace_bits(__le16 *p, u16 val, u16 field)
+{
+ *p = (*p & ~cpu_to_le16(field)) | le16_encode_bits(val, field);
+}
+
+static __always_inline
+u16 le16_get_bits(__le16 v, u16 field)
+{
+ return (le16_to_cpu(v) & field) / field_multiplier(field);
+}
+
+static __always_inline
+__be16 be16_encode_bits(u16 v, u16 field)
+{
+ __assert_field(v, field);
+ return cpu_to_be16((v & field_mask(field)) * field_multiplier(field));
+}
+
+static __always_inline
+u16 be16_get_bits(__be16 v, u16 field)
+{
+ return (be16_to_cpu(v) & field) / field_multiplier(field);
+}
+
+static __always_inline
+__u16 u16_encode_bits(u16 v, u16 field)
+{
+ __assert_field(v, field);
+ return (v & field_mask(field)) * field_multiplier(field);
+}
+
+static __always_inline
+__u16 u16_replace_bits(__u16 old, u16 val, u16 field)
+{
+ return (old & ~field) | u16_encode_bits(val, field);
+}
+
+static __always_inline
+void u16p_replace_bits(__u16 *p, u16 val, u16 field)
+{
+ *p = (*p & ~field) | u16_encode_bits(val, field);
+}
+
+static __always_inline
+u16 u16_get_bits(__u16 v, u16 field)
+{
+ return (v & field) / field_multiplier(field);
+}
+
+static __always_inline
+__le32 le32_encode_bits(u32 v, u32 field)
+{
+ __assert_field(v, field);
+ return cpu_to_le32((v & field_mask(field)) * field_multiplier(field));
+}
+
+static __always_inline
+void le32p_replace_bits(__le32 *p, u32 val, u32 field)
+{
+ *p = (*p & ~cpu_to_le32(field)) | le32_encode_bits(val, field);
+}
+
+static __always_inline
+u32 le32_get_bits(__le32 v, u32 field)
+{
+ return (le32_to_cpu(v) & field) / field_multiplier(field);
+}
+
+static __always_inline
+__be32 be32_encode_bits(u32 v, u32 field)
+{
+ __assert_field(v, field);
+ return cpu_to_be32((v & field_mask(field)) * field_multiplier(field));
+}
+
+static __always_inline
+void be32p_replace_bits(__be32 *p, u32 val, u32 field)
+{
+ *p = (*p & ~cpu_to_be32(field)) | be32_encode_bits(val, field);
+}
+
+static __always_inline
+u32 be32_get_bits(__be32 v, u32 field)
+{
+ return (be32_to_cpu(v) & field) / field_multiplier(field);
+}
+
+static __always_inline
+__u32 u32_encode_bits(u32 v, u32 field)
+{
+ __assert_field(v, field);
+ return (v & field_mask(field)) * field_multiplier(field);
+}
+
+static __always_inline
+__u32 u32_replace_bits(__u32 old, u32 val, u32 field)
+{
+ return (old & ~field) | u32_encode_bits(val, field);
+}
+
+static __always_inline
+void u32p_replace_bits(__u32 *p, u32 val, u32 field)
+{
+ *p = (*p & ~field) | u32_encode_bits(val, field);
+}
+
+static __always_inline
+u32 u32_get_bits(__u32 v, u32 field)
+{
+ return (v & field) / field_multiplier(field);
+}
+
+static __always_inline
+__le64 le64_encode_bits(u64 v, u64 field)
+{
+ __assert_field(v, field);
+ return cpu_to_le64((v & field_mask(field)) * field_multiplier(field));
+}
+
+static __always_inline
+u64 le64_get_bits(__le64 v, u64 field)
+{
+ return (le64_to_cpu(v) & field) / field_multiplier(field);
+}
+
+static __always_inline
+__be64 be64_encode_bits(u64 v, u64 field)
+{
+ __assert_field(v, field);
+ return cpu_to_be64((v & field_mask(field)) * field_multiplier(field));
+}
+
+static __always_inline
+u64 be64_get_bits(__be64 v, u64 field)
+{
+ return (be64_to_cpu(v) & field) / field_multiplier(field);
+}
+
+static __always_inline
+__u64 u64_encode_bits(u64 v, u64 field)
+{
+ __assert_field(v, field);
+ return (v & field_mask(field)) * field_multiplier(field);
+}
+
+static __always_inline
+__u64 u64_replace_bits(__u64 old, u64 val, u64 field)
+{
+ return (old & ~field) | u64_encode_bits(val, field);
+}
+
+static __always_inline
+void u64p_replace_bits(__u64 *p, u64 val, u64 field)
+{
+ *p = (*p & ~field) | u64_encode_bits(val, field);
+}
+
+static __always_inline
+u64 u64_get_bits(__u64 v, u64 field)
+{
+ return (v & field) / field_multiplier(field);
+}
+
+#endif /* _LINUX_BITFIELD_FIX_WIDTH_H */
diff --git a/tools/include/linux/bitfield.h b/tools/include/linux/bitfield.h
index ddf81f24956b..4508cefabec9 100644
--- a/tools/include/linux/bitfield.h
+++ b/tools/include/linux/bitfield.h
@@ -9,7 +9,7 @@
#include <linux/build_bug.h>
#include <linux/kernel.h>
-#include <asm/byteorder.h>
+#include <linux/bitfield-fix-width.h>
/*
* Bitfield access macros
@@ -127,51 +127,4 @@
(typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \
})
-extern void __compiletime_error("value doesn't fit into mask")
-__field_overflow(void);
-extern void __compiletime_error("bad bitfield mask")
-__bad_mask(void);
-static __always_inline u64 field_multiplier(u64 field)
-{
- if ((field | (field - 1)) & ((field | (field - 1)) + 1))
- __bad_mask();
- return field & -field;
-}
-static __always_inline u64 field_mask(u64 field)
-{
- return field / field_multiplier(field);
-}
-#define field_max(field) ((typeof(field))field_mask(field))
-#define ____MAKE_OP(type,base,to,from) \
-static __always_inline __##type type##_encode_bits(base v, base field) \
-{ \
- if (__builtin_constant_p(v) && (v & ~field_mask(field))) \
- __field_overflow(); \
- return to((v & field_mask(field)) * field_multiplier(field)); \
-} \
-static __always_inline __##type type##_replace_bits(__##type old, \
- base val, base field) \
-{ \
- return (old & ~to(field)) | type##_encode_bits(val, field); \
-} \
-static __always_inline void type##p_replace_bits(__##type *p, \
- base val, base field) \
-{ \
- *p = (*p & ~to(field)) | type##_encode_bits(val, field); \
-} \
-static __always_inline base type##_get_bits(__##type v, base field) \
-{ \
- return (from(v) & field)/field_multiplier(field); \
-}
-#define __MAKE_OP(size) \
- ____MAKE_OP(le##size,u##size,cpu_to_le##size,le##size##_to_cpu) \
- ____MAKE_OP(be##size,u##size,cpu_to_be##size,be##size##_to_cpu) \
- ____MAKE_OP(u##size,u##size,,)
-____MAKE_OP(u8,u8,,)
-__MAKE_OP(16)
-__MAKE_OP(32)
-__MAKE_OP(64)
-#undef __MAKE_OP
-#undef ____MAKE_OP
-
#endif
diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h
index f2f54b038168..03ecf9086643 100644
--- a/tools/include/linux/compiler.h
+++ b/tools/include/linux/compiler.h
@@ -73,6 +73,11 @@
# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#endif
+/* Enforce static storage duration. */
+#define ASSERT_STATIC_STORAGE(name) \
+ static typeof(name) * const __always_unused \
+ name##_storage_check = &(name)
+
/*
* This returns a constant expression while determining if an argument is
* a constant expression, most importantly without evaluating the argument.
diff --git a/tools/include/linux/mm.h b/tools/include/linux/mm.h
index 84b5954f66c3..bce7616cd7c4 100644
--- a/tools/include/linux/mm.h
+++ b/tools/include/linux/mm.h
@@ -30,11 +30,7 @@ static inline void *phys_to_virt(unsigned long address)
#define virt_to_phys virt_to_phys
static inline phys_addr_t virt_to_phys(volatile void *address)
{
- return (phys_addr_t)address;
-}
-
-static inline void totalram_pages_inc(void)
-{
+ return __pa(address);
}
static inline void totalram_pages_add(long count)
diff --git a/tools/include/linux/stddef.h b/tools/include/linux/stddef.h
new file mode 100644
index 000000000000..99182ea4a141
--- /dev/null
+++ b/tools/include/linux/stddef.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _TOOLS_LINUX_STDDEF_H
+#define _TOOLS_LINUX_STDDEF_H
+
+#include_next <linux/stddef.h>
+
+#define DECLARE_FLEX_ARRAY(TYPE, NAME) \
+ __DECLARE_FLEX_ARRAY(TYPE, NAME)
+
+#endif /* _TOOLS_LINUX_STDDEF_H */
diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile
index 6d213d372bf8..0880be0f6ef5 100644
--- a/tools/include/nolibc/Makefile
+++ b/tools/include/nolibc/Makefile
@@ -17,7 +17,23 @@ endif
# it defaults to this nolibc directory.
OUTPUT ?= $(CURDIR)/
-architectures := alpha arm arm64 loongarch m68k mips openrisc parisc powerpc riscv s390 sh sparc x86
+architectures := \
+ alpha \
+ arm \
+ arm64 \
+ hexagon \
+ loongarch \
+ m68k \
+ mips \
+ openrisc \
+ parisc \
+ powerpc \
+ riscv \
+ s390 \
+ sh \
+ sparc \
+ x86 \
+
arch_files := arch.h $(addsuffix .h, $(addprefix arch-, $(architectures)))
all_files := \
alloca.h \
@@ -59,6 +75,7 @@ all_files := \
sys/reboot.h \
sys/resource.h \
sys/select.h \
+ sys/sendfile.h \
sys/stat.h \
sys/syscall.h \
sys/sysmacros.h \
diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h
index b88686fb19c4..b5b3456c75cb 100644
--- a/tools/include/nolibc/arch-arm.h
+++ b/tools/include/nolibc/arch-arm.h
@@ -196,11 +196,6 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_prote
}
#endif /* NOLIBC_NO_RUNTIME */
-static __attribute__((unused))
-int _sys_ftruncate64(int fd, uint32_t length0, uint32_t length1)
-{
- return __nolibc_syscall4(__NR_ftruncate64, fd, 0, length0, length1);
-}
-#define _sys_ftruncate64 _sys_ftruncate64
+#define __NOLIBC_PAD_64BIT_SYSCALL_ARGUMENT_PAIR
#endif /* _NOLIBC_ARCH_ARM_H */
diff --git a/tools/include/nolibc/arch-hexagon.h b/tools/include/nolibc/arch-hexagon.h
new file mode 100644
index 000000000000..68f73529a6dd
--- /dev/null
+++ b/tools/include/nolibc/arch-hexagon.h
@@ -0,0 +1,159 @@
+/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
+/*
+ * hexagon specific definitions for NOLIBC
+ * Copyright (C) 2026 Thomas Weißschuh <linux@weissschuh.net>
+ */
+
+#ifndef _NOLIBC_ARCH_HEXAGON_H
+#define _NOLIBC_ARCH_HEXAGON_H
+
+#include <linux/unistd.h>
+
+#include "compiler.h"
+#include "crt.h"
+
+/*
+ * Syscalls for hexagon:
+ * - syscall number is passed in r6
+ * - arguments are in r0, r1, r2, r3, r4, r5
+ * - the system call is performed by calling trap0(#1)
+ * - syscall return value is in r0
+ */
+
+#define _NOLIBC_SYSCALL_CLOBBERLIST "memory"
+
+#define __nolibc_syscall0(num) \
+({ \
+ register long _num __asm__ ("r6") = (num); \
+ register long _arg1 __asm__ ("r0"); \
+ \
+ __asm__ volatile ( \
+ "trap0(#1)\n" \
+ : "=r"(_arg1) \
+ : "r"(_num) \
+ : _NOLIBC_SYSCALL_CLOBBERLIST \
+ ); \
+ _arg1; \
+})
+
+#define __nolibc_syscall1(num, arg1) \
+({ \
+ register long _num __asm__ ("r6") = (num); \
+ register long _arg1 __asm__ ("r0") = (long)(arg1); \
+ \
+ __asm__ volatile ( \
+ "trap0(#1)\n" \
+ : "+r"(_arg1) \
+ : "r"(_num) \
+ : _NOLIBC_SYSCALL_CLOBBERLIST \
+ ); \
+ _arg1; \
+})
+
+#define __nolibc_syscall2(num, arg1, arg2) \
+({ \
+ register long _num __asm__ ("r6") = (num); \
+ register long _arg1 __asm__ ("r0") = (long)(arg1); \
+ register long _arg2 __asm__ ("r1") = (long)(arg2); \
+ \
+ __asm__ volatile ( \
+ "trap0(#1)\n" \
+ : "+r"(_arg1) \
+ : "r"(_arg2), \
+ "r"(_num) \
+ : _NOLIBC_SYSCALL_CLOBBERLIST \
+ ); \
+ _arg1; \
+})
+
+#define __nolibc_syscall3(num, arg1, arg2, arg3) \
+({ \
+ register long _num __asm__ ("r6") = (num); \
+ register long _arg1 __asm__ ("r0") = (long)(arg1); \
+ register long _arg2 __asm__ ("r1") = (long)(arg2); \
+ register long _arg3 __asm__ ("r2") = (long)(arg3); \
+ \
+ __asm__ volatile ( \
+ "trap0(#1)\n" \
+ : "+r"(_arg1) \
+ : "r"(_arg2), "r"(_arg3), \
+ "r"(_num) \
+ : _NOLIBC_SYSCALL_CLOBBERLIST \
+ ); \
+ _arg1; \
+})
+
+#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \
+({ \
+ register long _num __asm__ ("r6") = (num); \
+ register long _arg1 __asm__ ("r0") = (long)(arg1); \
+ register long _arg2 __asm__ ("r1") = (long)(arg2); \
+ register long _arg3 __asm__ ("r2") = (long)(arg3); \
+ register long _arg4 __asm__ ("r3") = (long)(arg4); \
+ \
+ __asm__ volatile ( \
+ "trap0(#1)\n" \
+ : "+r"(_arg1) \
+ : "r"(_arg2), "r"(_arg3), "r"(_arg4), \
+ "r"(_num) \
+ : _NOLIBC_SYSCALL_CLOBBERLIST \
+ ); \
+ _arg1; \
+})
+
+#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
+({ \
+ register long _num __asm__ ("r6") = (num); \
+ register long _arg1 __asm__ ("r0") = (long)(arg1); \
+ register long _arg2 __asm__ ("r1") = (long)(arg2); \
+ register long _arg3 __asm__ ("r2") = (long)(arg3); \
+ register long _arg4 __asm__ ("r3") = (long)(arg4); \
+ register long _arg5 __asm__ ("r4") = (long)(arg5); \
+ \
+ __asm__ volatile ( \
+ "trap0(#1)\n" \
+ : "+r"(_arg1) \
+ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
+ "r"(_num) \
+ : _NOLIBC_SYSCALL_CLOBBERLIST \
+ ); \
+ _arg1; \
+})
+
+#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
+({ \
+ register long _num __asm__ ("r6") = (num); \
+ register long _arg1 __asm__ ("r0") = (long)(arg1); \
+ register long _arg2 __asm__ ("r1") = (long)(arg2); \
+ register long _arg3 __asm__ ("r2") = (long)(arg3); \
+ register long _arg4 __asm__ ("r3") = (long)(arg4); \
+ register long _arg5 __asm__ ("r4") = (long)(arg5); \
+ register long _arg6 __asm__ ("r5") = (long)(arg6); \
+ \
+ __asm__ volatile ( \
+ "trap0(#1)\n" \
+ : "+r"(_arg1) \
+ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \
+ "r"(_num) \
+ : _NOLIBC_SYSCALL_CLOBBERLIST \
+ ); \
+ _arg1; \
+})
+
+#ifndef NOLIBC_NO_RUNTIME
+/* startup code */
+void __attribute__((weak, noreturn))
+__nolibc_entrypoint __nolibc_no_stack_protector
+_start(void)
+{
+ __asm__ volatile (
+ "r0 = sp\n" /* save stack pointer to r0, as arg1 of _start_c */
+ "call _start_c\n" /* transfer to c runtime */
+ );
+ __nolibc_entrypoint_epilogue();
+}
+#endif /* NOLIBC_NO_RUNTIME */
+
+#define __NOLIBC_PAD_64BIT_SYSCALL_ARGUMENT_PAIR
+
+#endif /* _NOLIBC_ARCH_HEXAGON_H */
diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h
index 26ad413cec62..c0da0cc309ce 100644
--- a/tools/include/nolibc/arch-mips.h
+++ b/tools/include/nolibc/arch-mips.h
@@ -72,6 +72,7 @@
#define _NOLIBC_SYSCALL_STACK_UNRESERVE
#define _NOLIBC_SYSCALL_REG register long long
+#define __NOLIBC_BITS_PER_SYSCALL_ARG 64
#endif /* _ABIO32 */
@@ -286,12 +287,7 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_prote
#endif /* NOLIBC_NO_RUNTIME */
#if defined(_ABIO32)
-static __attribute__((unused))
-int _sys_ftruncate64(int fd, uint32_t length0, uint32_t length1)
-{
- return __nolibc_syscall4(__NR_ftruncate64, fd, 0, length0, length1);
-}
-#define _sys_ftruncate64 _sys_ftruncate64
+#define __NOLIBC_PAD_64BIT_SYSCALL_ARGUMENT_PAIR
#endif
#endif /* _NOLIBC_ARCH_MIPS_H */
diff --git a/tools/include/nolibc/arch-parisc.h b/tools/include/nolibc/arch-parisc.h
index 417043ecbc53..bf57ba16055c 100644
--- a/tools/include/nolibc/arch-parisc.h
+++ b/tools/include/nolibc/arch-parisc.h
@@ -7,9 +7,7 @@
#ifndef _NOLIBC_ARCH_PARISC_H
#define _NOLIBC_ARCH_PARISC_H
-#if defined(__LP64__)
-#error 64-bit not supported
-#endif
+#include <linux/unistd.h>
#include "compiler.h"
#include "crt.h"
@@ -167,9 +165,15 @@
void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
{
__asm__ volatile (
+#ifdef __LP64__
+ ".import __gp\n" /* Set up the dp register */
+ "ldil L%__gp, %dp\n"
+ "ldo R%__gp(%dp), %dp\n"
+#else
".import $global$\n" /* Set up the dp register */
"ldil L%$global$, %dp\n"
- "ldo R%$global$(%r27), %dp\n"
+ "ldo R%$global$(%dp), %dp\n"
+#endif
"b _start_c\n" /* Call _start_c, the load below is executed first */
@@ -182,4 +186,20 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_prote
}
#endif /* NOLIBC_NO_RUNTIME */
+#ifdef __LP64__
+/*
+ * This override is normally only meant for 32-bit architectures.
+ * But parisc 64-bit has __NR_ftruncate64, so this path is taken.
+ * Add an unused second argument to satisfy the calling convention.
+ */
+static __attribute__((unused))
+int _sys_ftruncate64(int fd, uint64_t length, uint64_t unused)
+{
+ (void)unused;
+
+ return __nolibc_syscall2(__NR_ftruncate64, fd, length);
+}
+#define _sys_ftruncate64 _sys_ftruncate64
+#endif
+
#endif /* _NOLIBC_ARCH_PARISC_H */
diff --git a/tools/include/nolibc/arch-powerpc.h b/tools/include/nolibc/arch-powerpc.h
index dbe2e5205aaa..a4711638cb66 100644
--- a/tools/include/nolibc/arch-powerpc.h
+++ b/tools/include/nolibc/arch-powerpc.h
@@ -222,12 +222,7 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_prote
#endif /* NOLIBC_NO_RUNTIME */
#if !defined(__powerpc64__)
-static __attribute__((unused))
-int _sys_ftruncate64(int fd, uint32_t length0, uint32_t length1)
-{
- return __nolibc_syscall4(__NR_ftruncate64, fd, 0, length0, length1);
-}
-#define _sys_ftruncate64 _sys_ftruncate64
+#define __NOLIBC_PAD_64BIT_SYSCALL_ARGUMENT_PAIR
#endif
#endif /* _NOLIBC_ARCH_POWERPC_H */
diff --git a/tools/include/nolibc/arch-sh.h b/tools/include/nolibc/arch-sh.h
index a32378fd621f..996cfbe1bee3 100644
--- a/tools/include/nolibc/arch-sh.h
+++ b/tools/include/nolibc/arch-sh.h
@@ -10,6 +10,8 @@
#include "compiler.h"
#include "crt.h"
+#include <linux/unistd.h>
+
/*
* Syscalls for SuperH:
* - registers are 32bit wide
@@ -161,4 +163,20 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_prote
}
#endif /* NOLIBC_NO_RUNTIME */
+static __attribute__((unused))
+ssize_t _sys_pread(int fd, void *buf, size_t count, off_t offset)
+{
+ return __nolibc_syscall6(__NR_pread64, fd, buf, count, 0,
+ __NOLIBC_LLARGPART(offset, 0), __NOLIBC_LLARGPART(offset, 1));
+}
+#define _sys_pread _sys_pread
+
+static __attribute__((unused))
+ssize_t _sys_pwrite(int fd, const void *buf, size_t count, off_t offset)
+{
+ return __nolibc_syscall6(__NR_pwrite64, fd, buf, count, 0,
+ __NOLIBC_LLARGPART(offset, 0), __NOLIBC_LLARGPART(offset, 1));
+}
+#define _sys_pwrite _sys_pwrite
+
#endif /* _NOLIBC_ARCH_SH_H */
diff --git a/tools/include/nolibc/arch-x86.h b/tools/include/nolibc/arch-x86.h
index 577e9b682eb3..0638f9316749 100644
--- a/tools/include/nolibc/arch-x86.h
+++ b/tools/include/nolibc/arch-x86.h
@@ -386,5 +386,7 @@ __asm__ (
".popsection\n"
);
+#define __NOLIBC_BITS_PER_SYSCALL_ARG 64
+
#endif /* !defined(__x86_64__) */
#endif /* _NOLIBC_ARCH_X86_H */
diff --git a/tools/include/nolibc/arch.h b/tools/include/nolibc/arch.h
index 06cc2dbe7a33..79ed5900f2a7 100644
--- a/tools/include/nolibc/arch.h
+++ b/tools/include/nolibc/arch.h
@@ -34,8 +34,15 @@
#include "arch-parisc.h"
#elif defined(__alpha__)
#include "arch-alpha.h"
+#elif defined(__hexagon__)
+#include "arch-hexagon.h"
#else
#error Unsupported Architecture
#endif
+
+#ifndef __NOLIBC_BITS_PER_SYSCALL_ARG
+#define __NOLIBC_BITS_PER_SYSCALL_ARG __BITS_PER_LONG
+#endif
+
#endif /* _NOLIBC_ARCH_H */
diff --git a/tools/include/nolibc/compiler.h b/tools/include/nolibc/compiler.h
index f2d7a81d0d7c..375c45ce81c8 100644
--- a/tools/include/nolibc/compiler.h
+++ b/tools/include/nolibc/compiler.h
@@ -90,4 +90,13 @@
# define __nolibc_no_sanitize_undefined
#endif
+/*
+ * Helper for 32-bit machines where a 64-bit syscall arg needs to be split into
+ * two 32-bit parts while making sure the order of the low/high parts are correct
+ * for the endianness:
+ * __NOLIBC_LLARGPART(x, 0), __NOLIBC_LLARGPART(x, 1)
+ */
+#define __NOLIBC_LLARGPART(_arg, _part) \
+ (((union { long long ll; long l[2]; }) { .ll = _arg }).l[_part])
+
#endif /* _NOLIBC_COMPILER_H */
diff --git a/tools/include/nolibc/dirent.h b/tools/include/nolibc/dirent.h
index 4e02ef25e72d..19857369de2a 100644
--- a/tools/include/nolibc/dirent.h
+++ b/tools/include/nolibc/dirent.h
@@ -30,10 +30,23 @@ typedef struct {
static __attribute__((unused))
DIR *fdopendir(int fd)
{
+ struct stat buf;
+ int ret;
+
if (fd < 0) {
SET_ERRNO(EBADF);
return NULL;
}
+
+ ret = fstat(fd, &buf);
+ if (ret < 0)
+ return NULL;
+
+ if (!S_ISDIR(buf.st_mode)) {
+ SET_ERRNO(ENOTDIR);
+ return NULL;
+ }
+
return (DIR *)(intptr_t)~fd;
}
@@ -42,10 +55,11 @@ DIR *opendir(const char *name)
{
int fd;
- fd = open(name, O_RDONLY);
+ fd = open(name, O_RDONLY | O_DIRECTORY);
if (fd == -1)
return NULL;
- return fdopendir(fd);
+
+ return (DIR *)(intptr_t)~fd;
}
static __attribute__((unused))
@@ -67,6 +81,7 @@ int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
struct linux_dirent64 *ldir = (void *)buf;
intptr_t i = (intptr_t)dirp;
int fd, ret;
+ off_t off;
if (i >= 0)
return EBADF;
@@ -86,9 +101,9 @@ int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
* readdir() can only return one entry at a time.
* Make sure the non-returned ones are not skipped.
*/
- ret = _sys_lseek(fd, ldir->d_off, SEEK_SET);
- if (ret < 0)
- return -ret;
+ off = _sys_lseek(fd, ldir->d_off, SEEK_SET);
+ if (off < 0)
+ return -off;
entry->d_ino = ldir->d_ino;
/* the destination should always be big enough */
diff --git a/tools/include/nolibc/err.h b/tools/include/nolibc/err.h
index e22ae87a7289..61978d537ed8 100644
--- a/tools/include/nolibc/err.h
+++ b/tools/include/nolibc/err.h
@@ -60,7 +60,7 @@ void verr(int eval, const char *fmt, va_list args)
static __attribute__((noreturn, unused))
void verrx(int eval, const char *fmt, va_list args)
{
- warnx(fmt, args);
+ vwarnx(fmt, args);
exit(eval);
}
diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h
index faa94f247281..352a207bbedc 100644
--- a/tools/include/nolibc/nolibc.h
+++ b/tools/include/nolibc/nolibc.h
@@ -106,6 +106,7 @@
#include "sys/reboot.h"
#include "sys/resource.h"
#include "sys/select.h"
+#include "sys/sendfile.h"
#include "sys/stat.h"
#include "sys/syscall.h"
#include "sys/sysmacros.h"
diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h
index 1816c2368b68..1c5a914c0f23 100644
--- a/tools/include/nolibc/stdlib.h
+++ b/tools/include/nolibc/stdlib.h
@@ -130,9 +130,11 @@ void *malloc(size_t len)
{
struct nolibc_heap *heap;
- /* Always allocate memory with size multiple of 4096. */
- len = sizeof(*heap) + len;
- len = (len + 4095UL) & -4096UL;
+ if (__builtin_expect(__builtin_add_overflow(len, sizeof(*heap), &len), 0)) {
+ SET_ERRNO(ENOMEM);
+ return NULL;
+ }
+
heap = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE,
-1, 0);
if (__builtin_expect(heap == MAP_FAILED, 0))
@@ -143,7 +145,7 @@ void *malloc(size_t len)
}
static __attribute__((unused))
-void *calloc(size_t size, size_t nmemb)
+void *calloc(size_t nmemb, size_t size)
{
size_t x;
@@ -230,7 +232,7 @@ int _nolibc_u64toa_base(uint64_t in, char *buffer, unsigned int base, uint64_t r
/* Generate least significant digit first */
do {
-#if defined(__SIZEOF_INT128__) && !defined(__mips__) && !defined(__sparc__)
+#if defined(__SIZEOF_INT128__) && !defined(__mips__) && !defined(__sparc__) && !defined(__hppa__)
q = ((unsigned __int128)in * recip) >> 64;
#else
uint64_t p = (uint32_t)in * (recip >> 32);
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
index 548f94d96ed2..b63fa6c618c5 100644
--- a/tools/include/nolibc/sys.h
+++ b/tools/include/nolibc/sys.h
@@ -71,16 +71,6 @@ static __inline__ int __nolibc_enosys(const char *syscall, ...)
#endif
-/*
- * Helper for 32-bit machines where a 64-bit syscall arg needs to be split into
- * two 32-bit parts while making sure the order of the low/high parts are correct
- * for the endianness:
- * __NOLIBC_LLARGPART(x, 0), __NOLIBC_LLARGPART(x, 1)
- */
-#define __NOLIBC_LLARGPART(_arg, _part) \
- (((union { long long ll; long l[2]; }) { .ll = _arg }).l[_part])
-
-
/* Functions in this file only describe syscalls. They're declared static so
* that the compiler usually decides to inline them while still being allowed
* to pass a pointer to one of their instances. Each syscall exists in two
@@ -756,6 +746,56 @@ int pivot_root(const char *new, const char *old)
/*
+ * ssize_t pread(int fd, void *buf, size_t count, off_t offset);
+ * ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
+ */
+
+#ifndef _sys_pread
+static __attribute__((unused))
+ssize_t _sys_pread(int fd, void *buf, size_t count, off_t offset)
+{
+#if __NOLIBC_BITS_PER_SYSCALL_ARG == 64
+ return __nolibc_syscall4(__NR_pread64, fd, buf, count, offset);
+#elif defined(__NOLIBC_PAD_64BIT_SYSCALL_ARGUMENT_PAIR)
+ return __nolibc_syscall6(__NR_pread64, fd, buf, count, 0,
+ __NOLIBC_LLARGPART(offset, 0), __NOLIBC_LLARGPART(offset, 1));
+#else
+ return __nolibc_syscall5(__NR_pread64, fd, buf, count,
+ __NOLIBC_LLARGPART(offset, 0), __NOLIBC_LLARGPART(offset, 1));
+#endif
+}
+#endif /* _sys_pread */
+
+static __attribute__((unused))
+ssize_t pread(int fd, void *buf, size_t count, off_t offset)
+{
+ return __sysret(_sys_pread(fd, buf, count, offset));
+}
+
+#ifndef _sys_pwrite
+static __attribute__((unused))
+ssize_t _sys_pwrite(int fd, const void *buf, size_t count, off_t offset)
+{
+#if __NOLIBC_BITS_PER_SYSCALL_ARG == 64
+ return __nolibc_syscall4(__NR_pwrite64, fd, buf, count, offset);
+#elif defined(__NOLIBC_PAD_64BIT_SYSCALL_ARGUMENT_PAIR)
+ return __nolibc_syscall6(__NR_pwrite64, fd, buf, count, 0,
+ __NOLIBC_LLARGPART(offset, 0), __NOLIBC_LLARGPART(offset, 1));
+#else
+ return __nolibc_syscall5(__NR_pwrite64, fd, buf, count,
+ __NOLIBC_LLARGPART(offset, 0), __NOLIBC_LLARGPART(offset, 1));
+#endif
+}
+#endif /* _sys_pwrite */
+
+static __attribute__((unused))
+ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
+{
+ return __sysret(_sys_pwrite(fd, buf, count, offset));
+}
+
+
+/*
* ssize_t read(int fd, void *buf, size_t count);
*/
diff --git a/tools/include/nolibc/sys/select.h b/tools/include/nolibc/sys/select.h
index 6d65d9ef3d6a..f299c79939f5 100644
--- a/tools/include/nolibc/sys/select.h
+++ b/tools/include/nolibc/sys/select.h
@@ -26,7 +26,7 @@ typedef struct {
int __fd = (fd); \
if (__fd >= 0) \
__set->fds[__fd / FD_SETIDXMASK] &= \
- ~(1U << (__fd & FD_SETBITMASK)); \
+ ~(1UL << (__fd & FD_SETBITMASK)); \
} while (0)
#define FD_SET(fd, set) do { \
@@ -34,7 +34,7 @@ typedef struct {
int __fd = (fd); \
if (__fd >= 0) \
__set->fds[__fd / FD_SETIDXMASK] |= \
- 1 << (__fd & FD_SETBITMASK); \
+ 1UL << (__fd & FD_SETBITMASK); \
} while (0)
#define FD_ISSET(fd, set) ({ \
@@ -43,7 +43,7 @@ typedef struct {
int __r = 0; \
if (__fd >= 0) \
__r = !!(__set->fds[__fd / FD_SETIDXMASK] & \
-1U << (__fd & FD_SETBITMASK)); \
+1UL << (__fd & FD_SETBITMASK)); \
__r; \
})
diff --git a/tools/include/nolibc/sys/sendfile.h b/tools/include/nolibc/sys/sendfile.h
new file mode 100644
index 000000000000..ac7d85847718
--- /dev/null
+++ b/tools/include/nolibc/sys/sendfile.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
+/*
+ * sendfile for NOLIBC
+ * Copyright (C) 2026 Daniel Palmer <daniel@thingy.jp>
+ */
+
+/* make sure to include all global symbols */
+#include "../nolibc.h"
+
+#ifndef _NOLIBC_SYS_SENDFILE_H
+#define _NOLIBC_SYS_SENDFILE_H
+
+#include "../sys.h"
+#include <linux/unistd.h>
+
+/*
+ * ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
+ */
+
+static __attribute__((unused))
+ssize_t _sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
+{
+ __nolibc_static_assert(sizeof(*offset) == sizeof(__kernel_loff_t));
+
+#ifdef __NR_sendfile64
+ /* 32-bit applications use sendfile64 so offset is treated as a __kernel_loff_t */
+ return __nolibc_syscall4(__NR_sendfile64, out_fd, in_fd, offset, count);
+#else
+ __nolibc_static_assert(sizeof(*offset) == sizeof(__kernel_off_t));
+
+ return __nolibc_syscall4(__NR_sendfile, out_fd, in_fd, offset, count);
+#endif
+}
+
+static __attribute__((unused))
+ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
+{
+ return __sysret(_sys_sendfile(out_fd, in_fd, offset, count));
+}
+
+#endif /* _NOLIBC_SYS_SENDFILE_H */
diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h
index 8f3cb18df7f1..4373bd8a5b5f 100644
--- a/tools/include/nolibc/types.h
+++ b/tools/include/nolibc/types.h
@@ -119,7 +119,7 @@ struct timeval {
#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
#define WIFEXITED(status) (((status) & 0x7f) == 0)
#define WTERMSIG(status) ((status) & 0x7f)
-#define WIFSIGNALED(status) ((status) - 1 < 0xff)
+#define WIFSIGNALED(status) ((status) - 1U < 0xff)
/* standard exit() codes */
#define EXIT_SUCCESS 0
diff --git a/tools/include/nolibc/unistd.h b/tools/include/nolibc/unistd.h
index a264a20da13d..939d4e05a55d 100644
--- a/tools/include/nolibc/unistd.h
+++ b/tools/include/nolibc/unistd.h
@@ -52,7 +52,11 @@ int access(const char *path, int amode)
static __attribute__((unused))
int _sys_ftruncate64(int fd, uint32_t length0, uint32_t length1)
{
+#if defined(__NOLIBC_PAD_64BIT_SYSCALL_ARGUMENT_PAIR)
+ return __nolibc_syscall4(__NR_ftruncate64, fd, 0, length0, length1);
+#else
return __nolibc_syscall3(__NR_ftruncate64, fd, length0, length1);
+#endif
}
#define _sys_ftruncate64 _sys_ftruncate64
#endif
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 732b35cc08d1..8d7228834305 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -56,6 +56,19 @@
enum bpf_cond_pseudo_jmp {
BPF_MAY_GOTO = 0,
+ /*
+ * Follows a call of a bpf subprog. Taken when the subprog left with
+ * BPF_EXIT that has src_reg == BPF_UNWIND_EXIT.
+ */
+ BPF_UNWIND_GOTO = 1,
+};
+
+enum bpf_pseudo_exit {
+ /*
+ * When bpf_exit->src_reg == BPF_UNWIND_EXIT, it's the same as bpf_exit,
+ * except that BPF_UNWIND_GOTO after the call is taken.
+ */
+ BPF_UNWIND_EXIT = 1,
};
/* Register numbers */
@@ -936,6 +949,33 @@ union bpf_iter_link_info {
* 0 on success or -1 if an error occurred (in which case,
* *errno* is set appropriately).
*
+ * BPF_PROG_STREAM_OPEN
+ * Description
+ * Open a file descriptor for one of the BPF streams associated
+ * with the program identified by *prog_fd*. The stream is selected
+ * by *stream_id*.
+ *
+ * The returned file descriptor supports **read**\ (2) and
+ * **poll**\ (2). Reads block while the stream is empty unless
+ * **BPF_F_STREAM_NONBLOCK** is specified in *flags*. A non-blocking
+ * read of an empty stream fails with **EAGAIN**.
+ *
+ * **poll**\ (2) reports **POLLIN** when data is available and
+ * **POLLHUP** once the program has been freed, that is, after every
+ * reference to it, including links and other file descriptors, has
+ * been dropped. Hangup may lag the final release because program
+ * teardown is deferred. Buffered data remains readable after
+ * **POLLHUP** and a read returns zero after all such data has been
+ * consumed.
+ *
+ * The file descriptor is read-only and has the close-on-exec flag
+ * set. It is not seekable and **lseek**\ (2) fails with **ESPIPE**.
+ * *flags* may only contain **BPF_F_STREAM_NONBLOCK**.
+ *
+ * Return
+ * A new file descriptor (a nonnegative integer), or -1 if an
+ * error occurred (in which case, *errno* is set appropriately).
+ *
* NOTES
* eBPF objects (maps and programs) can be shared between processes.
*
@@ -993,6 +1033,7 @@ enum bpf_cmd {
BPF_TOKEN_CREATE,
BPF_PROG_STREAM_READ_BY_FD,
BPF_PROG_ASSOC_STRUCT_OPS,
+ BPF_PROG_STREAM_OPEN,
__MAX_BPF_CMD,
BPF_COMMON_ATTRS = 1 << 16, /* Indicate carrying syscall common attrs. */
};
@@ -1524,6 +1565,11 @@ enum {
BPF_STREAM_STDERR = 2,
};
+/* flags for BPF_PROG_STREAM_OPEN command */
+enum {
+ BPF_F_STREAM_NONBLOCK = (1U << 0),
+};
+
union bpf_attr {
struct { /* anonymous struct used by BPF_MAP_CREATE command */
__u32 map_type; /* one of enum bpf_map_type */
@@ -1756,7 +1802,7 @@ union bpf_attr {
__u32 prog_cnt;
__u32 count;
};
- __u32 :32;
+ __u32 type_id;
/* output: per-program attach_flags.
* not allowed to be set during effective query.
*/
@@ -1950,6 +1996,12 @@ union bpf_attr {
__u32 flags;
} prog_assoc_struct_ops;
+ struct {
+ __u32 prog_fd;
+ __u32 stream_id;
+ __u32 flags;
+ } prog_stream_open;
+
} __attribute__((aligned(8)));
/* The description below is an attempt at providing documentation to eBPF
@@ -4867,15 +4919,18 @@ union bpf_attr {
* The non-negative copied *buf* length equal to or less than
* *size* on success, or a negative error in case of failure.
*
- * long bpf_load_hdr_opt(struct bpf_sock_ops *skops, void *searchby_res, u32 len, u64 flags)
+ * long bpf_load_hdr_opt(void *ctx, void *searchby_res, u32 len, u64 flags)
* Description
* Load header option. Support reading a particular TCP header
- * option for bpf program (**BPF_PROG_TYPE_SOCK_OPS**).
+ * option for bpf program (**BPF_PROG_TYPE_SOCK_OPS**). For the
+ * **bpf_tcp_ops** struct_ops, this helper can be called from the
+ * **parse_hdr**\ () and **write_hdr_opt**\ () operators.
*
- * If *flags* is 0, it will search the option from the
- * *skops*\ **->skb_data**. The comment in **struct bpf_sock_ops**
- * has details on what skb_data contains under different
- * *skops*\ **->op**.
+ * If *flags* is 0, it will search the option from the packet
+ * associated with the current operation. For
+ * **BPF_PROG_TYPE_SOCK_OPS**, the comment in
+ * **struct bpf_sock_ops** has details on what skb_data
+ * contains under different *op*.
*
* The first byte of the *searchby_res* specifies the
* kind that it wants to search.
@@ -4908,6 +4963,8 @@ union bpf_attr {
*
* * **BPF_LOAD_HDR_OPT_TCP_SYN** to search from the
* saved_syn packet or the just-received syn packet.
+ * Not supported by the **bpf_tcp_ops** struct_ops, which
+ * rejects all flags.
*
* Return
* > 0 when found, the header option is copied to *searchby_res*.
@@ -4928,9 +4985,9 @@ union bpf_attr {
* packet.
*
* **-EPERM** if the helper cannot be used under the current
- * *skops*\ **->op**.
+ * operation.
*
- * long bpf_store_hdr_opt(struct bpf_sock_ops *skops, const void *from, u32 len, u64 flags)
+ * long bpf_store_hdr_opt(void *ctx, const void *from, u32 len, u64 flags)
* Description
* Store header option. The data will be copied
* from buffer *from* with length *len* to the TCP header.
@@ -4946,7 +5003,9 @@ union bpf_attr {
* by searching the same option in the outgoing skb.
*
* This helper can only be called during
- * **BPF_SOCK_OPS_WRITE_HDR_OPT_CB**.
+ * **BPF_SOCK_OPS_WRITE_HDR_OPT_CB**, or from the
+ * **write_hdr_opt**\ () operator of the **bpf_tcp_ops**
+ * struct_ops.
*
* Return
* 0 on success, or negative error in case of failure:
@@ -4961,9 +5020,9 @@ union bpf_attr {
* **-EFAULT** on failure to parse the existing header options.
*
* **-EPERM** if the helper cannot be used under the current
- * *skops*\ **->op**.
+ * operation.
*
- * long bpf_reserve_hdr_opt(struct bpf_sock_ops *skops, u32 len, u64 flags)
+ * long bpf_reserve_hdr_opt(void *ctx, u32 len, u64 flags)
* Description
* Reserve *len* bytes for the bpf header option. The
* space will be used by **bpf_store_hdr_opt**\ () later in
@@ -4973,7 +5032,9 @@ union bpf_attr {
* the total number of bytes will be reserved.
*
* This helper can only be called during
- * **BPF_SOCK_OPS_HDR_OPT_LEN_CB**.
+ * **BPF_SOCK_OPS_HDR_OPT_LEN_CB**, or from the
+ * **hdr_opt_len**\ () operator of the **bpf_tcp_ops**
+ * struct_ops.
*
* Return
* 0 on success, or negative error in case of failure:
@@ -4983,7 +5044,7 @@ union bpf_attr {
* **-ENOSPC** if there is not enough space in the header.
*
* **-EPERM** if the helper cannot be used under the current
- * *skops*\ **->op**.
+ * operation.
*
* void *bpf_inode_storage_get(struct bpf_map *map, void *inode, void *value, u64 flags)
* Description
@@ -6890,6 +6951,8 @@ struct bpf_link_info {
} xdp;
struct {
__u32 map_id;
+ __u32 :32;
+ __u64 cgroup_id;
} struct_ops;
struct {
__u32 pf;
@@ -7284,6 +7347,31 @@ enum {
*/
};
+/*
+ * Most callbacks of struct bpf_tcp_ops are placed in the slow
+ * path (e.g., one-shot connection setup or unlikely events like
+ * timers) and are invoked simply by defining non-NULL callbacks.
+ *
+ * Callbacks in the fast path, however, would incur noticeable
+ * overhead even when set to NULL, so they are disabled by default
+ * and must be explicitly enabled per socket via bpf_tcp_ops_set_flags().
+ *
+ * The flags are per-socket and shared by all effective bpf_tcp_ops
+ * programs.
+ */
+enum {
+ /* .rtt() */
+ BPF_TCP_OPS_FLAG_RTT = (1 << 0),
+ /* .parse_hdr() */
+ BPF_TCP_OPS_FLAG_PARSE_HDR_OPT_ALL = (1 << 1),
+ BPF_TCP_OPS_FLAG_PARSE_HDR_OPT_UNKNOWN = (1 << 2),
+ /* .hdr_opt_len() and .write_hdr_opt() */
+ BPF_TCP_OPS_FLAG_WRITE_HDR_OPT = (1 << 3),
+ /* .enqueue_rcvq() and .dequeue_rcvq() */
+ BPF_TCP_OPS_FLAG_RCVQ = (1 << 4),
+ BPF_TCP_OPS_FLAG_ALL = (1 << 5) - 1,
+};
+
/* List of TCP states. There is a build check in net/ipv4/tcp.c to detect
* changes between the TCP and BPF versions. Ideally this should never happen.
* If it does, we need to add code to convert them before calling
@@ -7600,6 +7688,10 @@ struct bpf_task_work {
__u64 __opaque;
} __attribute__((aligned(8)));
+struct bpf_rcu_head {
+ __u64 __opaque[6];
+} __attribute__((aligned(8)));
+
struct bpf_wq {
__u64 __opaque[2];
} __attribute__((aligned(8)));
diff --git a/tools/include/uapi/linux/btf.h b/tools/include/uapi/linux/btf.h
index 618167cab4e6..11d65871d163 100644
--- a/tools/include/uapi/linux/btf.h
+++ b/tools/include/uapi/linux/btf.h
@@ -54,8 +54,8 @@ struct btf_type {
* decl_tag and type_tag
*/
__u32 info;
- /* "size" is used by INT, ENUM, STRUCT, UNION, DATASEC and ENUM64.
- * "size" tells the size of the type it is describing.
+ /* "size" is used by INT, ENUM, STRUCT, UNION, DATASEC, ENUM64
+ * and LOC_PARAM. "size" tells the size of the type it is describing.
*
* "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
* FUNC, FUNC_PROTO, VAR, DECL_TAG and TYPE_TAG.
@@ -92,7 +92,9 @@ enum {
BTF_KIND_DECL_TAG = 17, /* Decl Tag */
BTF_KIND_TYPE_TAG = 18, /* Type Tag */
BTF_KIND_ENUM64 = 19, /* Enumeration up to 64-bit values */
-
+ BTF_KIND_LOC_PARAM = 20, /* Location parameter information */
+ BTF_KIND_LOC_PROTO = 21, /* Location prototype for site */
+ BTF_KIND_LOCSEC = 22, /* Location section */
NR_BTF_KINDS,
BTF_KIND_MAX = NR_BTF_KINDS - 1,
};
@@ -212,4 +214,79 @@ struct btf_enum64 {
__u32 val_hi32;
};
+/*
+ * BTF_KIND_LOC_PARAM is followed by a single "struct btf_loc_param"
+ * that contains flags specifying the contents of the vlen-specified
+ * number of 4-byte values that follow.
+ */
+struct btf_loc_param {
+ __u32 flags;
+ __u32 values[];
+};
+
+/*
+ * The combination of size, vlen and flags gives us the means to interpret
+ * the following vlen-specified set of 4-byte values:
+ *
+ * - a BTF_LOC_PARAM_CONST is a constant value; combination
+ * of size, vlen and _SIGNED flag determines it. If the value requires
+ * 64 bits it is stored in {lo,hi} order.
+ * - a BTF_LOC_PARAM_ADDR|BTF_LOC_PARAM_CONST is an address that should be
+ * normalized with respect to kernel/module base address.
+ * - a BTF_LOC_PARAM_REG with vlen 1 is a simple register number;
+ * with vlen 2 it is a multi-register parameter. Register numbers are
+ * numbers derived from DW_OP_reg values, i.e. 0 is DW_OP_reg0; since
+ * DW_OP_fbreg has its own special DW_OP_value and DW_OP_regx can refer
+ * to an arbitrary register number, we reserve BTF_LOC_PARAM_FBREG for
+ * the frame base register to avoid collisions.
+ * - a _REG | OFFSET describes an address without dereferencing it.
+ * - a _REG | DEREF with vlen 1 dereferences the value in the register
+ * number specified.
+ * - a REG | DEREF | OFFSET with vlen > 1 specifies the register number
+ * in the first 4-byte value and the offset in the remainder.
+ * In the case of REG and OFFSET combinations, the OFFSET has the width
+ * of the value words while the type size describes the represented parameter,
+ * so for example a REG | DEREF | OFFSET with size 8 and vlen 2 would be
+ * an 8-byte register dereference with signed 4-byte offset, since the vlen 2
+ * values consist of a register value and the signed value.
+ */
+enum btf_loc_param_flags {
+ BTF_LOC_PARAM_SIGNED = 0x1,
+ BTF_LOC_PARAM_CONST = 0x2,
+ BTF_LOC_PARAM_ADDR = 0x4,
+ BTF_LOC_PARAM_REG = 0x8,
+ BTF_LOC_PARAM_DEREF = 0x10,
+ BTF_LOC_PARAM_OFFSET = 0x20,
+};
+
+enum {
+ BTF_LOC_PARAM_FBREG = 0xffffffff
+};
+
+/*
+ * BTF_KIND_LOC_PROTO specifies location prototypes; i.e. how locations relate
+ * to parameters; a struct btf_type of BTF_KIND_LOC_PROTO is followed by a
+ * vlen-specified number of __u32 BTF type ids which specify the associated
+ * BTF_KIND_LOC_PARAM for each function parameter associated with the
+ * location. The type should either be 0 (no location info) or point at
+ * a BTF_KIND_LOC_PARAM.
+ */
+
+/*
+ * BTF_KIND_LOCSEC consists of vlen-specified number of "struct btf_loc"
+ * containing location site-specific information for a specific ELF section;
+ * for example locations in ".text" are in a LOCSEC named "inline.text".
+ *
+ * - function (func)
+ * - location prototype type id (loc_proto)
+ * - address offset (offset) relative to the runtime base address of the
+ * ELF section associated with the LOCSEC
+ */
+
+struct btf_loc {
+ __u32 func;
+ __u32 loc_proto;
+ __u32 offset;
+};
+
#endif /* _UAPI__LINUX_BTF_H__ */
diff --git a/tools/include/uapi/linux/coredump.h b/tools/include/uapi/linux/coredump.h
index dc3789b78af0..6d0c53b534ea 100644
--- a/tools/include/uapi/linux/coredump.h
+++ b/tools/include/uapi/linux/coredump.h
@@ -11,12 +11,53 @@
* @COREDUMP_USERSPACE: userspace writes coredump
* @COREDUMP_REJECT: don't generate coredump
* @COREDUMP_WAIT: wait for coredump server
+ * @COREDUMP_RECORDS: send the coredump as a sequence of records instead of
+ * as a plain byte stream, see struct coredump_record_header;
+ * requires COREDUMP_KERNEL
+ * @COREDUMP_SPARSE: describe the holes in the coredump as zero records
+ * instead of transferring them; requires COREDUMP_RECORDS
+ * @COREDUMP_MEMORY_TYPES: dump the memory types in
+ * coredump_ack->memory_types instead of the ones
+ * the task selected; requires COREDUMP_KERNEL
*/
enum {
COREDUMP_KERNEL = (1ULL << 0),
COREDUMP_USERSPACE = (1ULL << 1),
COREDUMP_REJECT = (1ULL << 2),
COREDUMP_WAIT = (1ULL << 3),
+ COREDUMP_RECORDS = (1ULL << 4),
+ COREDUMP_SPARSE = (1ULL << 5),
+ COREDUMP_MEMORY_TYPES = (1ULL << 6),
+};
+
+/**
+ * coredump memory types
+ * @COREDUMP_MEMORY_ANON_PRIVATE: anonymous private memory
+ * @COREDUMP_MEMORY_ANON_SHARED: anonymous shared memory
+ * @COREDUMP_MEMORY_FILE_PRIVATE: file-backed private memory
+ * @COREDUMP_MEMORY_FILE_SHARED: file-backed shared memory
+ * @COREDUMP_MEMORY_ELF_HEADERS: the first page of a file-backed private
+ * mapping that starts an ELF file
+ * @COREDUMP_MEMORY_HUGETLB_PRIVATE: hugetlb private memory
+ * @COREDUMP_MEMORY_HUGETLB_SHARED: hugetlb shared memory
+ * @COREDUMP_MEMORY_DAX_PRIVATE: DAX private memory
+ * @COREDUMP_MEMORY_DAX_SHARED: DAX shared memory
+ *
+ * A bitmask of memory types a coredump may request to be included. New
+ * memory type bits must ensure that they do not steal memory from an
+ * existing one so a coredump server will continue to get the same
+ * coredumps even if a new bit is introduced.
+ */
+enum {
+ COREDUMP_MEMORY_ANON_PRIVATE = (1ULL << 0),
+ COREDUMP_MEMORY_ANON_SHARED = (1ULL << 1),
+ COREDUMP_MEMORY_FILE_PRIVATE = (1ULL << 2),
+ COREDUMP_MEMORY_FILE_SHARED = (1ULL << 3),
+ COREDUMP_MEMORY_ELF_HEADERS = (1ULL << 4),
+ COREDUMP_MEMORY_HUGETLB_PRIVATE = (1ULL << 5),
+ COREDUMP_MEMORY_HUGETLB_SHARED = (1ULL << 6),
+ COREDUMP_MEMORY_DAX_PRIVATE = (1ULL << 7),
+ COREDUMP_MEMORY_DAX_SHARED = (1ULL << 8),
};
/**
@@ -24,17 +65,19 @@ enum {
* @size: size of struct coredump_req
* @size_ack: known size of struct coredump_ack on this kernel
* @mask: supported features
+ * @memory_types: the memory types the task selected
+ * @memory_types_mask: the memory types this kernel knows
*
* When a coredump happens the kernel will connect to the coredump
* socket and send a coredump request to the coredump server. The @size
* member is set to the size of struct coredump_req and provides a hint
* to userspace how much data can be read. Userspace may use MSG_PEEK to
* peek the size of struct coredump_req and then choose to consume it in
- * one go. Userspace may also simply read a COREDUMP_ACK_SIZE_VER0
+ * one go. Userspace may also simply read a COREDUMP_REQ_SIZE_VER0
* request. If the size the kernel sends is larger userspace simply
* discards any remaining data.
*
- * The coredump_req->mask member is set to the currently know features.
+ * The coredump_req->mask member is set to the currently known features.
* Userspace may only set coredump_ack->mask to the bits raised by the
* kernel in coredump_req->mask.
*
@@ -42,15 +85,27 @@ enum {
* struct coredump_ack the kernel knows. Userspace may only send up to
* coredump_req->size_ack bytes to the kernel and must set
* coredump_ack->size accordingly.
+ *
+ * @memory_types is set to the default memory types that are included in
+ * the coredump. This can be overridden by raising bits in
+ * coredump_ack->memory_types.
+ *
+ * @memory_types_mask contains a bitmask of all memory types the kernel
+ * knows about. A coredump server may only raise bits in
+ * coredump_ack->memory_types that are raised in
+ * coredump_req->memory_types_mask.
*/
struct coredump_req {
__u32 size;
__u32 size_ack;
__u64 mask;
+ __u64 memory_types;
+ __u64 memory_types_mask;
};
enum {
COREDUMP_REQ_SIZE_VER0 = 16U, /* size of first published struct */
+ COREDUMP_REQ_SIZE_VER1 = 32U, /* memory_types and memory_types_mask added */
};
/**
@@ -58,6 +113,8 @@ enum {
* @size: size of the struct
* @spare: unused
* @mask: features kernel is supposed to use
+ * @memory_types: memory types to dump, only with COREDUMP_MEMORY_TYPES
+ * in @mask
*
* The @size member must be set to the size of struct coredump_ack. It
* may never exceed what the kernel returned in coredump_req->size_ack
@@ -67,15 +124,30 @@ enum {
* The @mask member must be set to the features the coredump server
* wants the kernel to use. Only bits the kernel returned in
* coredump_req->mask may be set.
+ *
+ * If COREDUMP_MEMORY_TYPES is raised in @mask the kernel dumps the
+ * memory types set in the @memory_types mask. Zero is valid and dumps
+ * no memory apart from the mappings that are always dumped.
+ *
+ * Note that memory a task excluded via MADV_DONTDUMP is always left
+ * out. A coredump server wanting to add or drop memory types instead of
+ * outright replacing it should simply copy coredump_req->memory_types
+ * and then mask off or raise types as needed.
+ *
+ * Note that @memory_types must be zero if COREDUMP_MEMORY_TYPES isn't
+ * raised. COREDUMP_MEMORY_TYPES requires COREDUMP_KERNEL and an ack of
+ * at least COREDUMP_ACK_SIZE_VER1 bytes.
*/
struct coredump_ack {
__u32 size;
__u32 spare;
__u64 mask;
+ __u64 memory_types;
};
enum {
COREDUMP_ACK_SIZE_VER0 = 16U, /* size of first published struct */
+ COREDUMP_ACK_SIZE_VER1 = 24U, /* memory_types added */
};
/**
@@ -83,11 +155,12 @@ enum {
*
* The kernel will place a single byte on the coredump socket. The
* markers notify userspace whether the coredump ack succeeded or
- * failed.
+ * failed. After any marker other than COREDUMP_MARK_REQACK the kernel
+ * closes the connection and no coredump is generated.
*
* @COREDUMP_MARK_MINSIZE: the provided coredump_ack size was too small
* @COREDUMP_MARK_MAXSIZE: the provided coredump_ack size was too big
- * @COREDUMP_MARK_UNSUPPORTED: the provided coredump_ack mask was invalid
+ * @COREDUMP_MARK_UNSUPPORTED: the provided coredump_ack mask or memory types were invalid
* @COREDUMP_MARK_CONFLICTING: the provided coredump_ack mask has conflicting options
* @COREDUMP_MARK_REQACK: the coredump request and ack was successful
* @__COREDUMP_MARK_MAX: the maximum coredump mark value
@@ -101,4 +174,72 @@ enum coredump_mark {
__COREDUMP_MARK_MAX = (1U << 31),
};
+/**
+ * enum coredump_record_type - Type of a coredump record
+ *
+ * @COREDUMP_RECORD_DATA: the header is followed by ->len bytes of data
+ * @COREDUMP_RECORD_END: the coredump ends here, the header is not followed
+ * by any data and no further record is sent
+ * @COREDUMP_RECORD_ZERO: the header stands for ->len zero bytes and is not
+ * followed by any data
+ * @__COREDUMP_RECORD_TYPE_MAX: the maximum coredump record type value
+ */
+enum coredump_record_type {
+ COREDUMP_RECORD_DATA = 0U,
+ COREDUMP_RECORD_END = 1U,
+ COREDUMP_RECORD_ZERO = 2U,
+ __COREDUMP_RECORD_TYPE_MAX = (1U << 31),
+};
+
+/**
+ * struct coredump_record_header - header of a coredump record
+ * @size: size of struct coredump_record_header
+ * @type: one of enum coredump_record_type
+ * @flags: modifiers for this record
+ * @offset: offset in the coredump this record starts at
+ * @len: number of coredump bytes this record accounts for
+ *
+ * If the coredump server raises COREDUMP_RECORDS in coredump_ack->mask
+ * the kernel doesn't send the coredump as a plain byte stream. It sends
+ * a sequence of records instead. A COREDUMP_RECORD_DATA record is
+ * followed by @len bytes of actual coredump data. A
+ * COREDUMP_RECORD_ZERO record is followed by nothing and stands for
+ * @len zero bytes. A server that didn't raise COREDUMP_SPARSE never
+ * sees a zero record. Records arrive in order and leave no gaps. So
+ * @offset is the sum of the @len of all records before it.
+ *
+ * The last record is a COREDUMP_RECORD_END record. It is followed by
+ * nothing. Its @len is zero. Its @offset is the size of the coredump.
+ * The kernel only sends it once it has written the whole coredump. A
+ * server that hits end-of-file without having seen an end record must
+ * treat the coredump as incomplete.
+ *
+ * The @size member is set to the size of struct coredump_record_header
+ * the kernel knows and lets the header grow later. It comes first so it
+ * can be peeked. Userspace must consume @size bytes and discard
+ * anything beyond what it knows. It must refuse a @size smaller than
+ * COREDUMP_RECORD_HEADER_SIZE_VER0. @size covers the header alone.
+ * @offset and @len count coredump bytes.
+ *
+ * The @flags member carries modifiers that change how the record is to
+ * be interpreted. No flag is defined yet. Userspace must refuse a
+ * record carrying a flag or a type it doesn't know. Every new record
+ * type is raised in coredump_req->mask as a feature of its own. A
+ * server only ever sees the types it asked for.
+ *
+ * COREDUMP_RECORDS must be combined with COREDUMP_KERNEL, and
+ * COREDUMP_SPARSE with COREDUMP_RECORDS.
+ */
+struct coredump_record_header {
+ __u32 size;
+ __u32 type;
+ __u64 flags;
+ __u64 offset;
+ __u64 len;
+};
+
+enum {
+ COREDUMP_RECORD_HEADER_SIZE_VER0 = 32U, /* size of first published struct */
+};
+
#endif /* _UAPI_LINUX_COREDUMP_H */
diff --git a/tools/include/uapi/linux/netdev.h b/tools/include/uapi/linux/netdev.h
index 35ff083221c7..9026e0414fbe 100644
--- a/tools/include/uapi/linux/netdev.h
+++ b/tools/include/uapi/linux/netdev.h
@@ -58,7 +58,7 @@ enum netdev_xdp_rx_metadata {
* enum netdev_xsk_flags
* @NETDEV_XSK_FLAGS_TX_TIMESTAMP: HW timestamping egress packets is supported
* by the driver.
- * @NETDEV_XSK_FLAGS_TX_CHECKSUM: L3 checksum HW offload is supported by the
+ * @NETDEV_XSK_FLAGS_TX_CHECKSUM: L4 checksum HW offload is supported by the
* driver.
* @NETDEV_XSK_FLAGS_TX_LAUNCH_TIME_FIFO: Launch time HW offload is supported
* by the driver.
diff --git a/tools/include/uapi/linux/seccomp.h b/tools/include/uapi/linux/seccomp.h
index dbfc9b37fcae..3a0ee0551261 100644
--- a/tools/include/uapi/linux/seccomp.h
+++ b/tools/include/uapi/linux/seccomp.h
@@ -25,6 +25,8 @@
#define SECCOMP_FILTER_FLAG_TSYNC_ESRCH (1UL << 4)
/* Received notifications wait in killable state (only respond to fatal signals) */
#define SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV (1UL << 5)
+/* Restart syscalls interrupted before their notification is received */
+#define SECCOMP_FILTER_FLAG_RESTART_BEFORE_RECV (1UL << 6)
/*
* All BPF programs must return a 32-bit value.
diff --git a/tools/include/uapi/linux/types.h b/tools/include/uapi/linux/types.h
index 85aa327245c6..6acf2059085a 100644
--- a/tools/include/uapi/linux/types.h
+++ b/tools/include/uapi/linux/types.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _UAPI_LINUX_TYPES_H
#define _UAPI_LINUX_TYPES_H