diff options
Diffstat (limited to 'tools/include')
33 files changed, 1080 insertions, 1019 deletions
diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h index 9d36c8ce1fe7..1684216e826a 100644 --- a/tools/include/linux/compiler.h +++ b/tools/include/linux/compiler.h @@ -42,6 +42,18 @@ # define __always_inline inline __attribute__((always_inline)) #endif +#ifndef __always_unused +#define __always_unused __attribute__((__unused__)) +#endif + +#ifndef __noreturn +#define __noreturn __attribute__((__noreturn__)) +#endif + +#ifndef unreachable +#define unreachable() __builtin_unreachable() +#endif + #ifndef noinline #define noinline #endif @@ -190,4 +202,10 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s #define ___PASTE(a, b) a##b #define __PASTE(a, b) ___PASTE(a, b) +#ifndef OPTIMIZER_HIDE_VAR +/* Make the optimizer believe the variable can be manipulated arbitrarily. */ +#define OPTIMIZER_HIDE_VAR(var) \ + __asm__ ("" : "=r" (var) : "0" (var)) +#endif + #endif /* _TOOLS_LINUX_COMPILER_H */ diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile index 64d67b080744..909b6eb500fe 100644 --- a/tools/include/nolibc/Makefile +++ b/tools/include/nolibc/Makefile @@ -27,6 +27,7 @@ nolibc_arch := $(patsubst arm64,aarch64,$(ARCH)) arch_file := arch-$(nolibc_arch).h all_files := \ compiler.h \ + crt.h \ ctype.h \ errno.h \ nolibc.h \ diff --git a/tools/include/nolibc/arch-aarch64.h b/tools/include/nolibc/arch-aarch64.h index 11f294a406b7..6c33c46848e3 100644 --- a/tools/include/nolibc/arch-aarch64.h +++ b/tools/include/nolibc/arch-aarch64.h @@ -8,34 +8,7 @@ #define _NOLIBC_ARCH_AARCH64_H #include "compiler.h" - -/* The struct returned by the newfstatat() syscall. Differs slightly from the - * x86_64's stat one by field ordering, so be careful. - */ -struct sys_stat_struct { - unsigned long st_dev; - unsigned long st_ino; - unsigned int st_mode; - unsigned int st_nlink; - unsigned int st_uid; - unsigned int st_gid; - - unsigned long st_rdev; - unsigned long __pad1; - long st_size; - int st_blksize; - int __pad2; - - long st_blocks; - long st_atime; - unsigned long st_atime_nsec; - long st_mtime; - - unsigned long st_mtime_nsec; - long st_ctime; - unsigned long st_ctime_nsec; - unsigned int __unused[2]; -}; +#include "crt.h" /* Syscalls for AARCH64 : * - registers are 64-bit @@ -56,8 +29,8 @@ struct sys_stat_struct { ({ \ register long _num __asm__ ("x8") = (num); \ register long _arg1 __asm__ ("x0"); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_num) \ @@ -70,8 +43,8 @@ struct sys_stat_struct { ({ \ register long _num __asm__ ("x8") = (num); \ register long _arg1 __asm__ ("x0") = (long)(arg1); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_arg1), \ @@ -86,8 +59,8 @@ struct sys_stat_struct { register long _num __asm__ ("x8") = (num); \ register long _arg1 __asm__ ("x0") = (long)(arg1); \ register long _arg2 __asm__ ("x1") = (long)(arg2); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_arg1), "r"(_arg2), \ @@ -103,8 +76,8 @@ struct sys_stat_struct { register long _arg1 __asm__ ("x0") = (long)(arg1); \ register long _arg2 __asm__ ("x1") = (long)(arg2); \ register long _arg3 __asm__ ("x2") = (long)(arg3); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ @@ -121,8 +94,8 @@ struct sys_stat_struct { register long _arg2 __asm__ ("x1") = (long)(arg2); \ register long _arg3 __asm__ ("x2") = (long)(arg3); \ register long _arg4 __asm__ ("x3") = (long)(arg4); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "svc #0\n" \ : "=r"(_arg1) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ @@ -140,8 +113,8 @@ struct sys_stat_struct { register long _arg3 __asm__ ("x2") = (long)(arg3); \ register long _arg4 __asm__ ("x3") = (long)(arg4); \ register long _arg5 __asm__ ("x4") = (long)(arg5); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "svc #0\n" \ : "=r" (_arg1) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ @@ -160,8 +133,8 @@ struct sys_stat_struct { register long _arg4 __asm__ ("x3") = (long)(arg4); \ register long _arg5 __asm__ ("x4") = (long)(arg5); \ register long _arg6 __asm__ ("x5") = (long)(arg6); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "svc #0\n" \ : "=r" (_arg1) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ @@ -171,33 +144,13 @@ struct sys_stat_struct { _arg1; \ }) -char **environ __attribute__((weak)); -const unsigned long *_auxv __attribute__((weak)); - /* startup code */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) +void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) { __asm__ volatile ( -#ifdef _NOLIBC_STACKPROTECTOR - "bl __stack_chk_init\n" /* initialize stack protector */ -#endif - "ldr x0, [sp]\n" /* argc (x0) was in the stack */ - "add x1, sp, 8\n" /* argv (x1) = sp */ - "lsl x2, x0, 3\n" /* envp (x2) = 8*argc ... */ - "add x2, x2, 8\n" /* + 8 (skip null) */ - "add x2, x2, x1\n" /* + argv */ - "adrp x3, environ\n" /* x3 = &environ (high bits) */ - "str x2, [x3, #:lo12:environ]\n" /* store envp into environ */ - "mov x4, x2\n" /* search for auxv (follows NULL after last env) */ - "0:\n" - "ldr x5, [x4], 8\n" /* x5 = *x4; x4 += 8 */ - "cbnz x5, 0b\n" /* and stop at NULL after last env */ - "adrp x3, _auxv\n" /* x3 = &_auxv (high bits) */ - "str x4, [x3, #:lo12:_auxv]\n" /* store x4 into _auxv */ - "and sp, x1, -16\n" /* sp must be 16-byte aligned in the callee */ - "bl main\n" /* main() returns the status code, we'll exit with it. */ - "mov x8, 93\n" /* NR_exit == 93 */ - "svc #0\n" + "mov x0, sp\n" /* save stack pointer to x0, as arg1 of _start_c */ + "and sp, x0, -16\n" /* sp must be 16-byte aligned in the callee */ + "bl _start_c\n" /* transfer to c runtime */ ); __builtin_unreachable(); } diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h index ca4c66987497..cae4afa7c1c7 100644 --- a/tools/include/nolibc/arch-arm.h +++ b/tools/include/nolibc/arch-arm.h @@ -8,43 +8,7 @@ #define _NOLIBC_ARCH_ARM_H #include "compiler.h" - -/* The struct returned by the stat() syscall, 32-bit only, the syscall returns - * exactly 56 bytes (stops before the unused array). In big endian, the format - * differs as devices are returned as short only. - */ -struct sys_stat_struct { -#if defined(__ARMEB__) - unsigned short st_dev; - unsigned short __pad1; -#else - unsigned long st_dev; -#endif - unsigned long st_ino; - unsigned short st_mode; - unsigned short st_nlink; - unsigned short st_uid; - unsigned short st_gid; - -#if defined(__ARMEB__) - unsigned short st_rdev; - unsigned short __pad2; -#else - unsigned long st_rdev; -#endif - unsigned long st_size; - unsigned long st_blksize; - unsigned long st_blocks; - - unsigned long st_atime; - unsigned long st_atime_nsec; - unsigned long st_mtime; - unsigned long st_mtime_nsec; - - unsigned long st_ctime; - unsigned long st_ctime_nsec; - unsigned long __unused[2]; -}; +#include "crt.h" /* Syscalls for ARM in ARM or Thumb modes : * - registers are 32-bit @@ -90,8 +54,8 @@ struct sys_stat_struct { ({ \ register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ register long _arg1 __asm__ ("r0"); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -107,8 +71,8 @@ struct sys_stat_struct { ({ \ register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ register long _arg1 __asm__ ("r0") = (long)(arg1); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -125,8 +89,8 @@ struct sys_stat_struct { register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ register long _arg1 __asm__ ("r0") = (long)(arg1); \ register long _arg2 __asm__ ("r1") = (long)(arg2); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -144,8 +108,8 @@ struct sys_stat_struct { register long _arg1 __asm__ ("r0") = (long)(arg1); \ register long _arg2 __asm__ ("r1") = (long)(arg2); \ register long _arg3 __asm__ ("r2") = (long)(arg3); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -164,8 +128,8 @@ struct sys_stat_struct { register long _arg2 __asm__ ("r1") = (long)(arg2); \ register long _arg3 __asm__ ("r2") = (long)(arg3); \ register long _arg4 __asm__ ("r3") = (long)(arg4); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -185,8 +149,8 @@ struct sys_stat_struct { register long _arg3 __asm__ ("r2") = (long)(arg3); \ register long _arg4 __asm__ ("r3") = (long)(arg4); \ register long _arg5 __asm__ ("r4") = (long)(arg5); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -207,8 +171,8 @@ struct sys_stat_struct { register long _arg4 __asm__ ("r3") = (long)(arg4); \ register long _arg5 __asm__ ("r4") = (long)(arg5); \ register long _arg6 __asm__ ("r5") = (long)(arg6); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ _NOLIBC_THUMB_SET_R7 \ "svc #0\n" \ _NOLIBC_THUMB_RESTORE_R7 \ @@ -220,49 +184,14 @@ struct sys_stat_struct { _arg1; \ }) - -char **environ __attribute__((weak)); -const unsigned long *_auxv __attribute__((weak)); - /* startup code */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) +void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) { __asm__ volatile ( -#ifdef _NOLIBC_STACKPROTECTOR - "bl __stack_chk_init\n" /* initialize stack protector */ -#endif - "pop {%r0}\n" /* argc was in the stack */ - "mov %r1, %sp\n" /* argv = sp */ - - "add %r2, %r0, $1\n" /* envp = (argc + 1) ... */ - "lsl %r2, %r2, $2\n" /* * 4 ... */ - "add %r2, %r2, %r1\n" /* + argv */ - "ldr %r3, 1f\n" /* r3 = &environ (see below) */ - "str %r2, [r3]\n" /* store envp into environ */ - - "mov r4, r2\n" /* search for auxv (follows NULL after last env) */ - "0:\n" - "mov r5, r4\n" /* r5 = r4 */ - "add r4, r4, #4\n" /* r4 += 4 */ - "ldr r5,[r5]\n" /* r5 = *r5 = *(r4-4) */ - "cmp r5, #0\n" /* and stop at NULL after last env */ - "bne 0b\n" - "ldr %r3, 2f\n" /* r3 = &_auxv (low bits) */ - "str r4, [r3]\n" /* store r4 into _auxv */ - - "mov %r3, $8\n" /* AAPCS : sp must be 8-byte aligned in the */ - "neg %r3, %r3\n" /* callee, and bl doesn't push (lr=pc) */ - "and %r3, %r3, %r1\n" /* so we do sp = r1(=sp) & r3(=-8); */ - "mov %sp, %r3\n" - - "bl main\n" /* main() returns the status code, we'll exit with it. */ - "movs r7, $1\n" /* NR_exit == 1 */ - "svc $0x00\n" - ".align 2\n" /* below are the pointers to a few variables */ - "1:\n" - ".word environ\n" - "2:\n" - ".word _auxv\n" + "mov %r0, sp\n" /* save stack pointer to %r0, as arg1 of _start_c */ + "and ip, %r0, #-8\n" /* sp must be 8-byte aligned in the callee */ + "mov sp, ip\n" + "bl _start_c\n" /* transfer to c runtime */ ); __builtin_unreachable(); } diff --git a/tools/include/nolibc/arch-i386.h b/tools/include/nolibc/arch-i386.h index 3d672d925e9e..64415b9fac77 100644 --- a/tools/include/nolibc/arch-i386.h +++ b/tools/include/nolibc/arch-i386.h @@ -8,32 +8,7 @@ #define _NOLIBC_ARCH_I386_H #include "compiler.h" - -/* The struct returned by the stat() syscall, 32-bit only, the syscall returns - * exactly 56 bytes (stops before the unused array). - */ -struct sys_stat_struct { - unsigned long st_dev; - unsigned long st_ino; - unsigned short st_mode; - unsigned short st_nlink; - unsigned short st_uid; - unsigned short st_gid; - - unsigned long st_rdev; - unsigned long st_size; - unsigned long st_blksize; - unsigned long st_blocks; - - unsigned long st_atime; - unsigned long st_atime_nsec; - unsigned long st_mtime; - unsigned long st_mtime_nsec; - - unsigned long st_ctime; - unsigned long st_ctime_nsec; - unsigned long __unused[2]; -}; +#include "crt.h" /* Syscalls for i386 : * - mostly similar to x86_64 @@ -57,8 +32,8 @@ struct sys_stat_struct { ({ \ long _ret; \ register long _num __asm__ ("eax") = (num); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "0"(_num) \ @@ -72,8 +47,8 @@ struct sys_stat_struct { long _ret; \ register long _num __asm__ ("eax") = (num); \ register long _arg1 __asm__ ("ebx") = (long)(arg1); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "r"(_arg1), \ @@ -89,8 +64,8 @@ struct sys_stat_struct { register long _num __asm__ ("eax") = (num); \ register long _arg1 __asm__ ("ebx") = (long)(arg1); \ register long _arg2 __asm__ ("ecx") = (long)(arg2); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "r"(_arg1), "r"(_arg2), \ @@ -107,8 +82,8 @@ struct sys_stat_struct { register long _arg1 __asm__ ("ebx") = (long)(arg1); \ register long _arg2 __asm__ ("ecx") = (long)(arg2); \ register long _arg3 __asm__ ("edx") = (long)(arg3); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ @@ -126,8 +101,8 @@ struct sys_stat_struct { register long _arg2 __asm__ ("ecx") = (long)(arg2); \ register long _arg3 __asm__ ("edx") = (long)(arg3); \ register long _arg4 __asm__ ("esi") = (long)(arg4); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ @@ -146,8 +121,8 @@ struct sys_stat_struct { register long _arg3 __asm__ ("edx") = (long)(arg3); \ register long _arg4 __asm__ ("esi") = (long)(arg4); \ register long _arg5 __asm__ ("edi") = (long)(arg5); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "int $0x80\n" \ : "=a" (_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ @@ -180,9 +155,6 @@ struct sys_stat_struct { _eax; \ }) -char **environ __attribute__((weak)); -const unsigned long *_auxv __attribute__((weak)); - /* startup code */ /* * i386 System V ABI mandates: @@ -190,33 +162,15 @@ const unsigned long *_auxv __attribute__((weak)); * 2) The deepest stack frame should be set to zero * */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) +void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) { __asm__ volatile ( -#ifdef _NOLIBC_STACKPROTECTOR - "call __stack_chk_init\n" /* initialize stack protector */ -#endif - "pop %eax\n" /* argc (first arg, %eax) */ - "mov %esp, %ebx\n" /* argv[] (second arg, %ebx) */ - "lea 4(%ebx,%eax,4),%ecx\n" /* then a NULL then envp (third arg, %ecx) */ - "mov %ecx, environ\n" /* save environ */ - "xor %ebp, %ebp\n" /* zero the stack frame */ - "mov %ecx, %edx\n" /* search for auxv (follows NULL after last env) */ - "0:\n" - "add $4, %edx\n" /* search for auxv using edx, it follows the */ - "cmp -4(%edx), %ebp\n" /* ... NULL after last env (ebp is zero here) */ - "jnz 0b\n" - "mov %edx, _auxv\n" /* save it into _auxv */ - "and $-16, %esp\n" /* x86 ABI : esp must be 16-byte aligned before */ - "sub $4, %esp\n" /* the call instruction (args are aligned) */ - "push %ecx\n" /* push all registers on the stack so that we */ - "push %ebx\n" /* support both regparm and plain stack modes */ - "push %eax\n" - "call main\n" /* main() returns the status code in %eax */ - "mov %eax, %ebx\n" /* retrieve exit code (32-bit int) */ - "movl $1, %eax\n" /* NR_exit == 1 */ - "int $0x80\n" /* exit now */ - "hlt\n" /* ensure it does not */ + "xor %ebp, %ebp\n" /* zero the stack frame */ + "mov %esp, %eax\n" /* save stack pointer to %eax, as arg1 of _start_c */ + "and $-16, %esp\n" /* last pushed argument must be 16-byte aligned */ + "push %eax\n" /* push arg1 on stack to support plain stack modes too */ + "call _start_c\n" /* transfer to c runtime */ + "hlt\n" /* ensure it does not return */ ); __builtin_unreachable(); } diff --git a/tools/include/nolibc/arch-loongarch.h b/tools/include/nolibc/arch-loongarch.h index ad3f266e7093..bf98f6220195 100644 --- a/tools/include/nolibc/arch-loongarch.h +++ b/tools/include/nolibc/arch-loongarch.h @@ -8,6 +8,7 @@ #define _NOLIBC_ARCH_LOONGARCH_H #include "compiler.h" +#include "crt.h" /* Syscalls for LoongArch : * - stack is 16-byte aligned @@ -22,18 +23,19 @@ * On LoongArch, select() is not implemented so we have to use pselect6(). */ #define __ARCH_WANT_SYS_PSELECT6 +#define _NOLIBC_SYSCALL_CLOBBERLIST \ + "memory", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8" #define my_syscall0(num) \ ({ \ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0"); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "=r"(_arg1) \ : "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -43,12 +45,11 @@ register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -59,13 +60,12 @@ register long _arg1 __asm__ ("a0") = (long)(arg1); \ register long _arg2 __asm__ ("a1") = (long)(arg2); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_arg2), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -77,13 +77,12 @@ register long _arg2 __asm__ ("a1") = (long)(arg2); \ register long _arg3 __asm__ ("a2") = (long)(arg3); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -96,13 +95,12 @@ register long _arg3 __asm__ ("a2") = (long)(arg3); \ register long _arg4 __asm__ ("a3") = (long)(arg4); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -116,13 +114,12 @@ register long _arg4 __asm__ ("a3") = (long)(arg4); \ register long _arg5 __asm__ ("a4") = (long)(arg5); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) @@ -137,67 +134,29 @@ register long _arg5 __asm__ ("a4") = (long)(arg5); \ register long _arg6 __asm__ ("a5") = (long)(arg6); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "syscall 0\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ "r"(_num) \ - : "memory", "$t0", "$t1", "$t2", "$t3", \ - "$t4", "$t5", "$t6", "$t7", "$t8" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg1; \ }) -char **environ __attribute__((weak)); -const unsigned long *_auxv __attribute__((weak)); - #if __loongarch_grlen == 32 -#define LONGLOG "2" -#define SZREG "4" -#define REG_L "ld.w" -#define LONG_S "st.w" -#define LONG_ADD "add.w" -#define LONG_ADDI "addi.w" -#define LONG_SLL "slli.w" #define LONG_BSTRINS "bstrins.w" #else /* __loongarch_grlen == 64 */ -#define LONGLOG "3" -#define SZREG "8" -#define REG_L "ld.d" -#define LONG_S "st.d" -#define LONG_ADD "add.d" -#define LONG_ADDI "addi.d" -#define LONG_SLL "slli.d" #define LONG_BSTRINS "bstrins.d" #endif /* startup code */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) +void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) { __asm__ volatile ( -#ifdef _NOLIBC_STACKPROTECTOR - "bl __stack_chk_init\n" /* initialize stack protector */ -#endif - REG_L " $a0, $sp, 0\n" /* argc (a0) was in the stack */ - LONG_ADDI " $a1, $sp, "SZREG"\n" /* argv (a1) = sp + SZREG */ - LONG_SLL " $a2, $a0, "LONGLOG"\n" /* envp (a2) = SZREG*argc ... */ - LONG_ADDI " $a2, $a2, "SZREG"\n" /* + SZREG (skip null) */ - LONG_ADD " $a2, $a2, $a1\n" /* + argv */ - - "move $a3, $a2\n" /* iterate a3 over envp to find auxv (after NULL) */ - "0:\n" /* do { */ - REG_L " $a4, $a3, 0\n" /* a4 = *a3; */ - LONG_ADDI " $a3, $a3, "SZREG"\n" /* a3 += sizeof(void*); */ - "bne $a4, $zero, 0b\n" /* } while (a4); */ - "la.pcrel $a4, _auxv\n" /* a4 = &_auxv */ - LONG_S " $a3, $a4, 0\n" /* store a3 into _auxv */ - - "la.pcrel $a3, environ\n" /* a3 = &environ */ - LONG_S " $a2, $a3, 0\n" /* store envp(a2) into environ */ - LONG_BSTRINS " $sp, $zero, 3, 0\n" /* sp must be 16-byte aligned */ - "bl main\n" /* main() returns the status code, we'll exit with it. */ - "li.w $a7, 93\n" /* NR_exit == 93 */ - "syscall 0\n" + "move $a0, $sp\n" /* save stack pointer to $a0, as arg1 of _start_c */ + LONG_BSTRINS " $sp, $zero, 3, 0\n" /* $sp must be 16-byte aligned */ + "bl _start_c\n" /* transfer to c runtime */ ); __builtin_unreachable(); } diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h index db24e0837a39..4ab6fa54beee 100644 --- a/tools/include/nolibc/arch-mips.h +++ b/tools/include/nolibc/arch-mips.h @@ -8,34 +8,7 @@ #define _NOLIBC_ARCH_MIPS_H #include "compiler.h" - -/* The struct returned by the stat() syscall. 88 bytes are returned by the - * syscall. - */ -struct sys_stat_struct { - unsigned int st_dev; - long st_pad1[3]; - unsigned long st_ino; - unsigned int st_mode; - unsigned int st_nlink; - unsigned int st_uid; - unsigned int st_gid; - unsigned int st_rdev; - long st_pad2[2]; - long st_size; - long st_pad3; - - long st_atime; - long st_atime_nsec; - long st_mtime; - long st_mtime_nsec; - - long st_ctime; - long st_ctime_nsec; - long st_blksize; - long st_blocks; - long st_pad4[14]; -}; +#include "crt.h" /* Syscalls for MIPS ABI O32 : * - WARNING! there's always a delayed slot! @@ -57,19 +30,22 @@ struct sys_stat_struct { * don't have to experience issues with register constraints. */ +#define _NOLIBC_SYSCALL_CLOBBERLIST \ + "memory", "cc", "at", "v1", "hi", "lo", \ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" + #define my_syscall0(num) \ ({ \ register long _num __asm__ ("v0") = (num); \ register long _arg4 __asm__ ("a3"); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ "addiu $sp, $sp, 32\n" \ : "=r"(_num), "=r"(_arg4) \ : "r"(_num) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg4 ? -_num : _num; \ }) @@ -79,16 +55,15 @@ struct sys_stat_struct { register long _num __asm__ ("v0") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ register long _arg4 __asm__ ("a3"); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ "addiu $sp, $sp, 32\n" \ : "=r"(_num), "=r"(_arg4) \ : "0"(_num), \ "r"(_arg1) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg4 ? -_num : _num; \ }) @@ -99,16 +74,15 @@ struct sys_stat_struct { register long _arg1 __asm__ ("a0") = (long)(arg1); \ register long _arg2 __asm__ ("a1") = (long)(arg2); \ register long _arg4 __asm__ ("a3"); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ "addiu $sp, $sp, 32\n" \ : "=r"(_num), "=r"(_arg4) \ : "0"(_num), \ "r"(_arg1), "r"(_arg2) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg4 ? -_num : _num; \ }) @@ -120,16 +94,15 @@ struct sys_stat_struct { register long _arg2 __asm__ ("a1") = (long)(arg2); \ register long _arg3 __asm__ ("a2") = (long)(arg3); \ register long _arg4 __asm__ ("a3"); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ "addiu $sp, $sp, 32\n" \ : "=r"(_num), "=r"(_arg4) \ : "0"(_num), \ "r"(_arg1), "r"(_arg2), "r"(_arg3) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg4 ? -_num : _num; \ }) @@ -141,16 +114,15 @@ struct sys_stat_struct { register long _arg2 __asm__ ("a1") = (long)(arg2); \ register long _arg3 __asm__ ("a2") = (long)(arg3); \ register long _arg4 __asm__ ("a3") = (long)(arg4); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "syscall\n" \ "addiu $sp, $sp, 32\n" \ : "=r" (_num), "=r"(_arg4) \ : "0"(_num), \ "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg4 ? -_num : _num; \ }) @@ -163,65 +135,58 @@ struct sys_stat_struct { register long _arg3 __asm__ ("a2") = (long)(arg3); \ register long _arg4 __asm__ ("a3") = (long)(arg4); \ register long _arg5 = (long)(arg5); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "addiu $sp, $sp, -32\n" \ "sw %7, 16($sp)\n" \ - "syscall\n " \ + "syscall\n" \ "addiu $sp, $sp, 32\n" \ : "=r" (_num), "=r"(_arg4) \ : "0"(_num), \ "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5) \ - : "memory", "cc", "at", "v1", "hi", "lo", \ - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ ); \ _arg4 ? -_num : _num; \ }) -char **environ __attribute__((weak)); -const unsigned long *_auxv __attribute__((weak)); +#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + register long _num __asm__ ("v0") = (num); \ + register long _arg1 __asm__ ("a0") = (long)(arg1); \ + register long _arg2 __asm__ ("a1") = (long)(arg2); \ + register long _arg3 __asm__ ("a2") = (long)(arg3); \ + register long _arg4 __asm__ ("a3") = (long)(arg4); \ + register long _arg5 = (long)(arg5); \ + register long _arg6 = (long)(arg6); \ + \ + __asm__ volatile ( \ + "addiu $sp, $sp, -32\n" \ + "sw %7, 16($sp)\n" \ + "sw %8, 20($sp)\n" \ + "syscall\n" \ + "addiu $sp, $sp, 32\n" \ + : "=r" (_num), "=r"(_arg4) \ + : "0"(_num), \ + "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "r"(_arg6) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _arg4 ? -_num : _num; \ +}) /* startup code, note that it's called __start on MIPS */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector __start(void) +void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector __start(void) { __asm__ volatile ( - /*".set nomips16\n"*/ ".set push\n" - ".set noreorder\n" + ".set noreorder\n" ".option pic0\n" -#ifdef _NOLIBC_STACKPROTECTOR - "jal __stack_chk_init\n" /* initialize stack protector */ - "nop\n" /* delayed slot */ -#endif - /*".ent __start\n"*/ - /*"__start:\n"*/ - "lw $a0,($sp)\n" /* argc was in the stack */ - "addiu $a1, $sp, 4\n" /* argv = sp + 4 */ - "sll $a2, $a0, 2\n" /* a2 = argc * 4 */ - "add $a2, $a2, $a1\n" /* envp = argv + 4*argc ... */ - "addiu $a2, $a2, 4\n" /* ... + 4 */ - "lui $a3, %hi(environ)\n" /* load environ into a3 (hi) */ - "addiu $a3, %lo(environ)\n" /* load environ into a3 (lo) */ - "sw $a2,($a3)\n" /* store envp(a2) into environ */ - - "move $t0, $a2\n" /* iterate t0 over envp, look for NULL */ - "0:" /* do { */ - "lw $a3, ($t0)\n" /* a3=*(t0); */ - "bne $a3, $0, 0b\n" /* } while (a3); */ - "addiu $t0, $t0, 4\n" /* delayed slot: t0+=4; */ - "lui $a3, %hi(_auxv)\n" /* load _auxv into a3 (hi) */ - "addiu $a3, %lo(_auxv)\n" /* load _auxv into a3 (lo) */ - "sw $t0, ($a3)\n" /* store t0 into _auxv */ - - "li $t0, -8\n" - "and $sp, $sp, $t0\n" /* sp must be 8-byte aligned */ - "addiu $sp,$sp,-16\n" /* the callee expects to save a0..a3 there! */ - "jal main\n" /* main() returns the status code, we'll exit with it. */ - "nop\n" /* delayed slot */ - "move $a0, $v0\n" /* retrieve 32-bit exit code from v0 */ - "li $v0, 4001\n" /* NR_exit == 4001 */ - "syscall\n" - /*".end __start\n"*/ + "move $a0, $sp\n" /* save stack pointer to $a0, as arg1 of _start_c */ + "li $t0, -8\n" + "and $sp, $sp, $t0\n" /* $sp must be 8-byte aligned */ + "addiu $sp, $sp, -16\n" /* the callee expects to save a0..a3 there */ + "jal _start_c\n" /* transfer to c runtime */ + " nop\n" /* delayed slot */ ".set pop\n" ); __builtin_unreachable(); diff --git a/tools/include/nolibc/arch-powerpc.h b/tools/include/nolibc/arch-powerpc.h new file mode 100644 index 000000000000..ac212e6185b2 --- /dev/null +++ b/tools/include/nolibc/arch-powerpc.h @@ -0,0 +1,221 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * PowerPC specific definitions for NOLIBC + * Copyright (C) 2023 Zhangjin Wu <falcon@tinylab.org> + */ + +#ifndef _NOLIBC_ARCH_POWERPC_H +#define _NOLIBC_ARCH_POWERPC_H + +#include "compiler.h" +#include "crt.h" + +/* Syscalls for PowerPC : + * - stack is 16-byte aligned + * - syscall number is passed in r0 + * - arguments are in r3, r4, r5, r6, r7, r8, r9 + * - the system call is performed by calling "sc" + * - syscall return comes in r3, and the summary overflow bit is checked + * to know if an error occurred, in which case errno is in r3. + * - the arguments are cast to long and assigned into the target + * registers which are then simply passed as registers to the asm code, + * so that we don't have to experience issues with register constraints. + */ + +#define _NOLIBC_SYSCALL_CLOBBERLIST \ + "memory", "cr0", "r12", "r11", "r10", "r9" + +#define my_syscall0(num) \ +({ \ + register long _ret __asm__ ("r3"); \ + register long _num __asm__ ("r0") = (num); \ + \ + __asm__ volatile ( \ + " sc\n" \ + " bns+ 1f\n" \ + " neg %0, %0\n" \ + "1:\n" \ + : "=r"(_ret), "+r"(_num) \ + : \ + : _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6", "r5", "r4" \ + ); \ + _ret; \ +}) + +#define my_syscall1(num, arg1) \ +({ \ + register long _ret __asm__ ("r3"); \ + register long _num __asm__ ("r0") = (num); \ + register long _arg1 __asm__ ("r3") = (long)(arg1); \ + \ + __asm__ volatile ( \ + " sc\n" \ + " bns+ 1f\n" \ + " neg %0, %0\n" \ + "1:\n" \ + : "=r"(_ret), "+r"(_num) \ + : "0"(_arg1) \ + : _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6", "r5", "r4" \ + ); \ + _ret; \ +}) + + +#define my_syscall2(num, arg1, arg2) \ +({ \ + register long _ret __asm__ ("r3"); \ + register long _num __asm__ ("r0") = (num); \ + register long _arg1 __asm__ ("r3") = (long)(arg1); \ + register long _arg2 __asm__ ("r4") = (long)(arg2); \ + \ + __asm__ volatile ( \ + " sc\n" \ + " bns+ 1f\n" \ + " neg %0, %0\n" \ + "1:\n" \ + : "=r"(_ret), "+r"(_num), "+r"(_arg2) \ + : "0"(_arg1) \ + : _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6", "r5" \ + ); \ + _ret; \ +}) + + +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + register long _ret __asm__ ("r3"); \ + register long _num __asm__ ("r0") = (num); \ + register long _arg1 __asm__ ("r3") = (long)(arg1); \ + register long _arg2 __asm__ ("r4") = (long)(arg2); \ + register long _arg3 __asm__ ("r5") = (long)(arg3); \ + \ + __asm__ volatile ( \ + " sc\n" \ + " bns+ 1f\n" \ + " neg %0, %0\n" \ + "1:\n" \ + : "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3) \ + : "0"(_arg1) \ + : _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6" \ + ); \ + _ret; \ +}) + + +#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + register long _ret __asm__ ("r3"); \ + register long _num __asm__ ("r0") = (num); \ + register long _arg1 __asm__ ("r3") = (long)(arg1); \ + register long _arg2 __asm__ ("r4") = (long)(arg2); \ + register long _arg3 __asm__ ("r5") = (long)(arg3); \ + register long _arg4 __asm__ ("r6") = (long)(arg4); \ + \ + __asm__ volatile ( \ + " sc\n" \ + " bns+ 1f\n" \ + " neg %0, %0\n" \ + "1:\n" \ + : "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3), \ + "+r"(_arg4) \ + : "0"(_arg1) \ + : _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7" \ + ); \ + _ret; \ +}) + + +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + register long _ret __asm__ ("r3"); \ + register long _num __asm__ ("r0") = (num); \ + register long _arg1 __asm__ ("r3") = (long)(arg1); \ + register long _arg2 __asm__ ("r4") = (long)(arg2); \ + register long _arg3 __asm__ ("r5") = (long)(arg3); \ + register long _arg4 __asm__ ("r6") = (long)(arg4); \ + register long _arg5 __asm__ ("r7") = (long)(arg5); \ + \ + __asm__ volatile ( \ + " sc\n" \ + " bns+ 1f\n" \ + " neg %0, %0\n" \ + "1:\n" \ + : "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3), \ + "+r"(_arg4), "+r"(_arg5) \ + : "0"(_arg1) \ + : _NOLIBC_SYSCALL_CLOBBERLIST, "r8" \ + ); \ + _ret; \ +}) + +#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + register long _ret __asm__ ("r3"); \ + register long _num __asm__ ("r0") = (num); \ + register long _arg1 __asm__ ("r3") = (long)(arg1); \ + register long _arg2 __asm__ ("r4") = (long)(arg2); \ + register long _arg3 __asm__ ("r5") = (long)(arg3); \ + register long _arg4 __asm__ ("r6") = (long)(arg4); \ + register long _arg5 __asm__ ("r7") = (long)(arg5); \ + register long _arg6 __asm__ ("r8") = (long)(arg6); \ + \ + __asm__ volatile ( \ + " sc\n" \ + " bns+ 1f\n" \ + " neg %0, %0\n" \ + "1:\n" \ + : "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3), \ + "+r"(_arg4), "+r"(_arg5), "+r"(_arg6) \ + : "0"(_arg1) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _ret; \ +}) + +#ifndef __powerpc64__ +/* FIXME: For 32-bit PowerPC, with newer gcc compilers (e.g. gcc 13.1.0), + * "omit-frame-pointer" fails with __attribute__((no_stack_protector)) but + * works with __attribute__((__optimize__("-fno-stack-protector"))) + */ +#ifdef __no_stack_protector +#undef __no_stack_protector +#define __no_stack_protector __attribute__((__optimize__("-fno-stack-protector"))) +#endif +#endif /* !__powerpc64__ */ + +/* startup code */ +void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) +{ +#ifdef __powerpc64__ +#if _CALL_ELF == 2 + /* with -mabi=elfv2, save TOC/GOT pointer to r2 + * r12 is global entry pointer, we use it to compute TOC from r12 + * https://www.llvm.org/devmtg/2014-04/PDFs/Talks/Euro-LLVM-2014-Weigand.pdf + * https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.pdf + */ + __asm__ volatile ( + "addis 2, 12, .TOC. - _start@ha\n" + "addi 2, 2, .TOC. - _start@l\n" + ); +#endif /* _CALL_ELF == 2 */ + + __asm__ volatile ( + "mr 3, 1\n" /* save stack pointer to r3, as arg1 of _start_c */ + "clrrdi 1, 1, 4\n" /* align the stack to 16 bytes */ + "li 0, 0\n" /* zero the frame pointer */ + "stdu 1, -32(1)\n" /* the initial stack frame */ + "bl _start_c\n" /* transfer to c runtime */ + ); +#else + __asm__ volatile ( + "mr 3, 1\n" /* save stack pointer to r3, as arg1 of _start_c */ + "clrrwi 1, 1, 4\n" /* align the stack to 16 bytes */ + "li 0, 0\n" /* zero the frame pointer */ + "stwu 1, -16(1)\n" /* the initial stack frame */ + "bl _start_c\n" /* transfer to c runtime */ + ); +#endif + __builtin_unreachable(); +} + +#endif /* _NOLIBC_ARCH_POWERPC_H */ diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h index a2e8564e66d6..950cc2283fd7 100644 --- a/tools/include/nolibc/arch-riscv.h +++ b/tools/include/nolibc/arch-riscv.h @@ -8,41 +8,7 @@ #define _NOLIBC_ARCH_RISCV_H #include "compiler.h" - -struct sys_stat_struct { - unsigned long st_dev; /* Device. */ - unsigned long st_ino; /* File serial number. */ - unsigned int st_mode; /* File mode. */ - unsigned int st_nlink; /* Link count. */ - unsigned int st_uid; /* User ID of the file's owner. */ - unsigned int st_gid; /* Group ID of the file's group. */ - unsigned long st_rdev; /* Device number, if device. */ - unsigned long __pad1; - long st_size; /* Size of file, in bytes. */ - int st_blksize; /* Optimal block size for I/O. */ - int __pad2; - long st_blocks; /* Number 512-byte blocks allocated. */ - long st_atime; /* Time of last access. */ - unsigned long st_atime_nsec; - long st_mtime; /* Time of last modification. */ - unsigned long st_mtime_nsec; - long st_ctime; /* Time of last status change. */ - unsigned long st_ctime_nsec; - unsigned int __unused4; - unsigned int __unused5; -}; - -#if __riscv_xlen == 64 -#define PTRLOG "3" -#define SZREG "8" -#define REG_L "ld" -#define REG_S "sd" -#elif __riscv_xlen == 32 -#define PTRLOG "2" -#define SZREG "4" -#define REG_L "lw" -#define REG_S "sw" -#endif +#include "crt.h" /* Syscalls for RISCV : * - stack is 16-byte aligned @@ -63,7 +29,7 @@ struct sys_stat_struct { register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0"); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n\t" \ : "=r"(_arg1) \ : "r"(_num) \ @@ -77,7 +43,7 @@ struct sys_stat_struct { register long _num __asm__ ("a7") = (num); \ register long _arg1 __asm__ ("a0") = (long)(arg1); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_num) \ @@ -92,7 +58,7 @@ struct sys_stat_struct { register long _arg1 __asm__ ("a0") = (long)(arg1); \ register long _arg2 __asm__ ("a1") = (long)(arg2); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_arg2), \ @@ -109,7 +75,7 @@ struct sys_stat_struct { register long _arg2 __asm__ ("a1") = (long)(arg2); \ register long _arg3 __asm__ ("a2") = (long)(arg3); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n\t" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), \ @@ -127,7 +93,7 @@ struct sys_stat_struct { register long _arg3 __asm__ ("a2") = (long)(arg3); \ register long _arg4 __asm__ ("a3") = (long)(arg4); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ @@ -146,7 +112,7 @@ struct sys_stat_struct { register long _arg4 __asm__ ("a3") = (long)(arg4); \ register long _arg5 __asm__ ("a4") = (long)(arg5); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ @@ -166,7 +132,7 @@ struct sys_stat_struct { register long _arg5 __asm__ ("a4") = (long)(arg5); \ register long _arg6 __asm__ ("a5") = (long)(arg6); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "ecall\n" \ : "+r"(_arg1) \ : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ @@ -176,40 +142,17 @@ struct sys_stat_struct { _arg1; \ }) -char **environ __attribute__((weak)); -const unsigned long *_auxv __attribute__((weak)); - /* startup code */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) +void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) { __asm__ volatile ( ".option push\n" ".option norelax\n" - "lla gp, __global_pointer$\n" + "lla gp, __global_pointer$\n" ".option pop\n" -#ifdef _NOLIBC_STACKPROTECTOR - "call __stack_chk_init\n" /* initialize stack protector */ -#endif - REG_L" a0, 0(sp)\n" /* argc (a0) was in the stack */ - "add a1, sp, "SZREG"\n" /* argv (a1) = sp */ - "slli a2, a0, "PTRLOG"\n" /* envp (a2) = SZREG*argc ... */ - "add a2, a2, "SZREG"\n" /* + SZREG (skip null) */ - "add a2,a2,a1\n" /* + argv */ - - "add a3, a2, zero\n" /* iterate a3 over envp to find auxv (after NULL) */ - "0:\n" /* do { */ - REG_L" a4, 0(a3)\n" /* a4 = *a3; */ - "add a3, a3, "SZREG"\n" /* a3 += sizeof(void*); */ - "bne a4, zero, 0b\n" /* } while (a4); */ - "lui a4, %hi(_auxv)\n" /* a4 = &_auxv (high bits) */ - REG_S" a3, %lo(_auxv)(a4)\n" /* store a3 into _auxv */ - - "lui a3, %hi(environ)\n" /* a3 = &environ (high bits) */ - REG_S" a2,%lo(environ)(a3)\n"/* store envp(a2) into environ */ - "andi sp,a1,-16\n" /* sp must be 16-byte aligned */ - "call main\n" /* main() returns the status code, we'll exit with it. */ - "li a7, 93\n" /* NR_exit == 93 */ - "ecall\n" + "mv a0, sp\n" /* save stack pointer to a0, as arg1 of _start_c */ + "andi sp, a0, -16\n" /* sp must be 16-byte aligned */ + "call _start_c\n" /* transfer to c runtime */ ); __builtin_unreachable(); } diff --git a/tools/include/nolibc/arch-s390.h b/tools/include/nolibc/arch-s390.h index 516dff5bff8b..5d60fd43f883 100644 --- a/tools/include/nolibc/arch-s390.h +++ b/tools/include/nolibc/arch-s390.h @@ -9,31 +9,7 @@ #include <asm/unistd.h> #include "compiler.h" - -/* The struct returned by the stat() syscall, equivalent to stat64(). The - * syscall returns 116 bytes and stops in the middle of __unused. - */ - -struct sys_stat_struct { - unsigned long st_dev; - unsigned long st_ino; - unsigned long st_nlink; - unsigned int st_mode; - unsigned int st_uid; - unsigned int st_gid; - unsigned int __pad1; - unsigned long st_rdev; - unsigned long st_size; - unsigned long st_atime; - unsigned long st_atime_nsec; - unsigned long st_mtime; - unsigned long st_mtime_nsec; - unsigned long st_ctime; - unsigned long st_ctime_nsec; - unsigned long st_blksize; - long st_blocks; - unsigned long __unused[3]; -}; +#include "crt.h" /* Syscalls for s390: * - registers are 64-bit @@ -52,7 +28,7 @@ struct sys_stat_struct { register long _num __asm__ ("1") = (num); \ register long _rc __asm__ ("2"); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "=d"(_rc) \ : "d"(_num) \ @@ -66,7 +42,7 @@ struct sys_stat_struct { register long _num __asm__ ("1") = (num); \ register long _arg1 __asm__ ("2") = (long)(arg1); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "+d"(_arg1) \ : "d"(_num) \ @@ -81,7 +57,7 @@ struct sys_stat_struct { register long _arg1 __asm__ ("2") = (long)(arg1); \ register long _arg2 __asm__ ("3") = (long)(arg2); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "+d"(_arg1) \ : "d"(_arg2), "d"(_num) \ @@ -97,7 +73,7 @@ struct sys_stat_struct { register long _arg2 __asm__ ("3") = (long)(arg2); \ register long _arg3 __asm__ ("4") = (long)(arg3); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "+d"(_arg1) \ : "d"(_arg2), "d"(_arg3), "d"(_num) \ @@ -114,7 +90,7 @@ struct sys_stat_struct { register long _arg3 __asm__ ("4") = (long)(arg3); \ register long _arg4 __asm__ ("5") = (long)(arg4); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "+d"(_arg1) \ : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_num) \ @@ -132,7 +108,7 @@ struct sys_stat_struct { register long _arg4 __asm__ ("5") = (long)(arg4); \ register long _arg5 __asm__ ("6") = (long)(arg5); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "+d"(_arg1) \ : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \ @@ -152,7 +128,7 @@ struct sys_stat_struct { register long _arg5 __asm__ ("6") = (long)(arg5); \ register long _arg6 __asm__ ("7") = (long)(arg6); \ \ - __asm__ volatile ( \ + __asm__ volatile ( \ "svc 0\n" \ : "+d"(_arg1) \ : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \ @@ -162,41 +138,14 @@ struct sys_stat_struct { _arg1; \ }) -char **environ __attribute__((weak)); -const unsigned long *_auxv __attribute__((weak)); - /* startup code */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) +void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) { __asm__ volatile ( - "lg %r2,0(%r15)\n" /* argument count */ - "la %r3,8(%r15)\n" /* argument pointers */ - - "xgr %r0,%r0\n" /* r0 will be our NULL value */ - /* search for envp */ - "lgr %r4,%r3\n" /* start at argv */ - "0:\n" - "clg %r0,0(%r4)\n" /* entry zero? */ - "la %r4,8(%r4)\n" /* advance pointer */ - "jnz 0b\n" /* no -> test next pointer */ - /* yes -> r4 now contains start of envp */ - "larl %r1,environ\n" - "stg %r4,0(%r1)\n" - - /* search for auxv */ - "lgr %r5,%r4\n" /* start at envp */ - "1:\n" - "clg %r0,0(%r5)\n" /* entry zero? */ - "la %r5,8(%r5)\n" /* advance pointer */ - "jnz 1b\n" /* no -> test next pointer */ - "larl %r1,_auxv\n" /* yes -> store value in _auxv */ - "stg %r5,0(%r1)\n" - - "aghi %r15,-160\n" /* allocate new stackframe */ - "xc 0(8,%r15),0(%r15)\n" /* clear backchain */ - "brasl %r14,main\n" /* ret value of main is arg to exit */ - "lghi %r1,1\n" /* __NR_exit */ - "svc 0\n" + "lgr %r2, %r15\n" /* save stack pointer to %r2, as arg1 of _start_c */ + "aghi %r15, -160\n" /* allocate new stackframe */ + "xc 0(8,%r15), 0(%r15)\n" /* clear backchain */ + "brasl %r14, _start_c\n" /* transfer to c runtime */ ); __builtin_unreachable(); } diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h index 6fc4d8392742..e5ccb926c903 100644 --- a/tools/include/nolibc/arch-x86_64.h +++ b/tools/include/nolibc/arch-x86_64.h @@ -8,33 +8,7 @@ #define _NOLIBC_ARCH_X86_64_H #include "compiler.h" - -/* The struct returned by the stat() syscall, equivalent to stat64(). The - * syscall returns 116 bytes and stops in the middle of __unused. - */ -struct sys_stat_struct { - unsigned long st_dev; - unsigned long st_ino; - unsigned long st_nlink; - unsigned int st_mode; - unsigned int st_uid; - - unsigned int st_gid; - unsigned int __pad0; - unsigned long st_rdev; - long st_size; - long st_blksize; - - long st_blocks; - unsigned long st_atime; - unsigned long st_atime_nsec; - unsigned long st_mtime; - - unsigned long st_mtime_nsec; - unsigned long st_ctime; - unsigned long st_ctime_nsec; - long __unused[3]; -}; +#include "crt.h" /* Syscalls for x86_64 : * - registers are 64-bit @@ -59,8 +33,8 @@ struct sys_stat_struct { ({ \ long _ret; \ register long _num __asm__ ("rax") = (num); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "0"(_num) \ @@ -74,8 +48,8 @@ struct sys_stat_struct { long _ret; \ register long _num __asm__ ("rax") = (num); \ register long _arg1 __asm__ ("rdi") = (long)(arg1); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), \ @@ -91,8 +65,8 @@ struct sys_stat_struct { register long _num __asm__ ("rax") = (num); \ register long _arg1 __asm__ ("rdi") = (long)(arg1); \ register long _arg2 __asm__ ("rsi") = (long)(arg2); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), "r"(_arg2), \ @@ -109,8 +83,8 @@ struct sys_stat_struct { register long _arg1 __asm__ ("rdi") = (long)(arg1); \ register long _arg2 __asm__ ("rsi") = (long)(arg2); \ register long _arg3 __asm__ ("rdx") = (long)(arg3); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ @@ -128,8 +102,8 @@ struct sys_stat_struct { register long _arg2 __asm__ ("rsi") = (long)(arg2); \ register long _arg3 __asm__ ("rdx") = (long)(arg3); \ register long _arg4 __asm__ ("r10") = (long)(arg4); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ @@ -148,8 +122,8 @@ struct sys_stat_struct { register long _arg3 __asm__ ("rdx") = (long)(arg3); \ register long _arg4 __asm__ ("r10") = (long)(arg4); \ register long _arg5 __asm__ ("r8") = (long)(arg5); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ @@ -169,8 +143,8 @@ struct sys_stat_struct { register long _arg4 __asm__ ("r10") = (long)(arg4); \ register long _arg5 __asm__ ("r8") = (long)(arg5); \ register long _arg6 __asm__ ("r9") = (long)(arg6); \ - \ - __asm__ volatile ( \ + \ + __asm__ volatile ( \ "syscall\n" \ : "=a"(_ret) \ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ @@ -180,9 +154,6 @@ struct sys_stat_struct { _ret; \ }) -char **environ __attribute__((weak)); -const unsigned long *_auxv __attribute__((weak)); - /* startup code */ /* * x86-64 System V ABI mandates: @@ -190,29 +161,14 @@ const unsigned long *_auxv __attribute__((weak)); * 2) The deepest stack frame should be zero (the %rbp). * */ -void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) +void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) { __asm__ volatile ( -#ifdef _NOLIBC_STACKPROTECTOR - "call __stack_chk_init\n" /* initialize stack protector */ -#endif - "pop %rdi\n" /* argc (first arg, %rdi) */ - "mov %rsp, %rsi\n" /* argv[] (second arg, %rsi) */ - "lea 8(%rsi,%rdi,8),%rdx\n" /* then a NULL then envp (third arg, %rdx) */ - "mov %rdx, environ\n" /* save environ */ - "xor %ebp, %ebp\n" /* zero the stack frame */ - "mov %rdx, %rax\n" /* search for auxv (follows NULL after last env) */ - "0:\n" - "add $8, %rax\n" /* search for auxv using rax, it follows the */ - "cmp -8(%rax), %rbp\n" /* ... NULL after last env (rbp is zero here) */ - "jnz 0b\n" - "mov %rax, _auxv\n" /* save it into _auxv */ - "and $-16, %rsp\n" /* x86 ABI : esp must be 16-byte aligned before call */ - "call main\n" /* main() returns the status code, we'll exit with it. */ - "mov %eax, %edi\n" /* retrieve exit code (32 bit) */ - "mov $60, %eax\n" /* NR_exit == 60 */ - "syscall\n" /* really exit */ - "hlt\n" /* ensure it does not return */ + "xor %ebp, %ebp\n" /* zero the stack frame */ + "mov %rsp, %rdi\n" /* save stack pointer to %rdi, as arg1 of _start_c */ + "and $-16, %rsp\n" /* %rsp must be 16-byte aligned before call */ + "call _start_c\n" /* transfer to c runtime */ + "hlt\n" /* ensure it does not return */ ); __builtin_unreachable(); } diff --git a/tools/include/nolibc/arch.h b/tools/include/nolibc/arch.h index 82b43935650f..e276fb0680af 100644 --- a/tools/include/nolibc/arch.h +++ b/tools/include/nolibc/arch.h @@ -25,6 +25,8 @@ #include "arch-aarch64.h" #elif defined(__mips__) && defined(_ABIO32) #include "arch-mips.h" +#elif defined(__powerpc__) +#include "arch-powerpc.h" #elif defined(__riscv) #include "arch-riscv.h" #elif defined(__s390x__) diff --git a/tools/include/nolibc/crt.h b/tools/include/nolibc/crt.h new file mode 100644 index 000000000000..a5f33fef1672 --- /dev/null +++ b/tools/include/nolibc/crt.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * C Run Time support for NOLIBC + * Copyright (C) 2023 Zhangjin Wu <falcon@tinylab.org> + */ + +#ifndef _NOLIBC_CRT_H +#define _NOLIBC_CRT_H + +char **environ __attribute__((weak)); +const unsigned long *_auxv __attribute__((weak)); + +static void __stack_chk_init(void); +static void exit(int); + +void _start_c(long *sp) +{ + long argc; + char **argv; + char **envp; + const unsigned long *auxv; + /* silence potential warning: conflicting types for 'main' */ + int _nolibc_main(int, char **, char **) __asm__ ("main"); + + /* initialize stack protector */ + __stack_chk_init(); + + /* + * sp : argc <-- argument count, required by main() + * argv: argv[0] <-- argument vector, required by main() + * argv[1] + * ... + * argv[argc-1] + * null + * environ: environ[0] <-- environment variables, required by main() and getenv() + * environ[1] + * ... + * null + * _auxv: _auxv[0] <-- auxiliary vector, required by getauxval() + * _auxv[1] + * ... + * null + */ + + /* assign argc and argv */ + argc = *sp; + argv = (void *)(sp + 1); + + /* find environ */ + environ = envp = argv + argc + 1; + + /* find _auxv */ + for (auxv = (void *)envp; *auxv++;) + ; + _auxv = auxv; + + /* go to application */ + exit(_nolibc_main(argc, argv, envp)); +} + +#endif /* _NOLIBC_CRT_H */ diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 05a228a6ee78..1f8d821000ac 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -13,11 +13,10 @@ * Syscalls are split into 3 levels: * - The lower level is the arch-specific syscall() definition, consisting in * assembly code in compound expressions. These are called my_syscall0() to - * my_syscall6() depending on the number of arguments. The MIPS - * implementation is limited to 5 arguments. All input arguments are cast - * to a long stored in a register. These expressions always return the - * syscall's return value as a signed long value which is often either a - * pointer or the negated errno value. + * my_syscall6() depending on the number of arguments. All input arguments + * are castto a long stored in a register. These expressions always return + * the syscall's return value as a signed long value which is often either + * a pointer or the negated errno value. * * - The second level is mostly architecture-independent. It is made of * static functions called sys_<name>() which rely on my_syscallN() diff --git a/tools/include/nolibc/stackprotector.h b/tools/include/nolibc/stackprotector.h index 88f7b2d098ff..13f1d0e60387 100644 --- a/tools/include/nolibc/stackprotector.h +++ b/tools/include/nolibc/stackprotector.h @@ -37,14 +37,15 @@ void __stack_chk_fail_local(void) __attribute__((weak,section(".data.nolibc_stack_chk"))) uintptr_t __stack_chk_guard; -__attribute__((weak,section(".text.nolibc_stack_chk"))) __no_stack_protector -void __stack_chk_init(void) +static __no_stack_protector void __stack_chk_init(void) { my_syscall3(__NR_getrandom, &__stack_chk_guard, sizeof(__stack_chk_guard), 0); /* a bit more randomness in case getrandom() fails, ensure the guard is never 0 */ if (__stack_chk_guard != (uintptr_t) &__stack_chk_guard) __stack_chk_guard ^= (uintptr_t) &__stack_chk_guard; } +#else /* !defined(_NOLIBC_STACKPROTECTOR) */ +static void __stack_chk_init(void) {} #endif /* defined(_NOLIBC_STACKPROTECTOR) */ #endif /* _NOLIBC_STACKPROTECTOR_H */ diff --git a/tools/include/nolibc/stdint.h b/tools/include/nolibc/stdint.h index 4b282435a59a..6665e272e213 100644 --- a/tools/include/nolibc/stdint.h +++ b/tools/include/nolibc/stdint.h @@ -15,7 +15,7 @@ typedef unsigned int uint32_t; typedef signed int int32_t; typedef unsigned long long uint64_t; typedef signed long long int64_t; -typedef unsigned long size_t; +typedef __SIZE_TYPE__ size_t; typedef signed long ssize_t; typedef unsigned long uintptr_t; typedef signed long intptr_t; diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 0eef91daf289..cae402c11e57 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -21,6 +21,11 @@ #define EOF (-1) #endif +/* Buffering mode used by setvbuf. */ +#define _IOFBF 0 /* Fully buffered. */ +#define _IOLBF 1 /* Line buffered. */ +#define _IONBF 2 /* No buffering. */ + /* just define FILE as a non-empty type. The value of the pointer gives * the FD: FILE=~fd for fd>=0 or NULL for fd<0. This way positive FILE * are immediately identified as abnormal entries (i.e. possible copies @@ -350,6 +355,28 @@ void perror(const char *msg) fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno); } +static __attribute__((unused)) +int setvbuf(FILE *stream __attribute__((unused)), + char *buf __attribute__((unused)), + int mode, + size_t size __attribute__((unused))) +{ + /* + * nolibc does not support buffering so this is a nop. Just check mode + * is valid as required by the spec. + */ + switch (mode) { + case _IOFBF: + case _IOLBF: + case _IONBF: + break; + default: + return EOF; + } + + return 0; +} + /* make sure to include all global symbols */ #include "nolibc.h" diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index 902162f80337..bacfd35c5156 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -83,11 +83,10 @@ void free(void *ptr) * declared as a char **, and must be terminated by a NULL (it is recommended * to set this variable to the "envp" argument of main()). If the requested * environment variable exists its value is returned otherwise NULL is - * returned. getenv() is forcefully inlined so that the reference to "environ" - * will be dropped if unused, even at -O0. + * returned. */ static __attribute__((unused)) -char *_getenv(const char *name, char **environ) +char *getenv(const char *name) { int idx, i; @@ -102,13 +101,6 @@ char *_getenv(const char *name, char **environ) return NULL; } -static __inline__ __attribute__((unused,always_inline)) -char *getenv(const char *name) -{ - extern char **environ; - return _getenv(name, environ); -} - static __attribute__((unused)) unsigned long getauxval(unsigned long type) { diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h index 856249a11890..fdb6bd6c0e2f 100644 --- a/tools/include/nolibc/sys.h +++ b/tools/include/nolibc/sys.h @@ -21,7 +21,6 @@ #include <linux/auxvec.h> #include <linux/fcntl.h> /* for O_* and AT_* */ #include <linux/stat.h> /* for statx() */ -#include <linux/reboot.h> /* for LINUX_REBOOT_* */ #include <linux/prctl.h> #include "arch.h" @@ -29,6 +28,22 @@ #include "types.h" +/* Syscall return helper: takes the syscall value in argument and checks for an + * error in it. This may only be used with signed returns (int or long), but + * not with pointers. An error is any value < 0. When an error is encountered, + * -ret is set into errno and -1 is returned. Otherwise the returned value is + * passed as-is with its type preserved. + */ + +#define __sysret(arg) \ +({ \ + __typeof__(arg) __sysret_arg = (arg); \ + (__sysret_arg < 0) /* error ? */ \ + ? (({ SET_ERRNO(-__sysret_arg); }), -1) /* ret -1 with errno = -arg */ \ + : __sysret_arg; /* return original value */ \ +}) + + /* 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 @@ -78,10 +93,10 @@ int brk(void *addr) static __attribute__((unused)) void *sbrk(intptr_t inc) { - void *ret; - /* first call to find current end */ - if ((ret = sys_brk(0)) && (sys_brk(ret + inc) == ret + inc)) + void *ret = sys_brk(0); + + if (ret && sys_brk(ret + inc) == ret + inc) return ret + inc; SET_ERRNO(ENOMEM); @@ -102,13 +117,7 @@ int sys_chdir(const char *path) static __attribute__((unused)) int chdir(const char *path) { - int ret = sys_chdir(path); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_chdir(path)); } @@ -124,20 +133,14 @@ int sys_chmod(const char *path, mode_t mode) #elif defined(__NR_chmod) return my_syscall2(__NR_chmod, path, mode); #else -#error Neither __NR_fchmodat nor __NR_chmod defined, cannot implement sys_chmod() + return -ENOSYS; #endif } static __attribute__((unused)) int chmod(const char *path, mode_t mode) { - int ret = sys_chmod(path, mode); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_chmod(path, mode)); } @@ -153,20 +156,14 @@ int sys_chown(const char *path, uid_t owner, gid_t group) #elif defined(__NR_chown) return my_syscall3(__NR_chown, path, owner, group); #else -#error Neither __NR_fchownat nor __NR_chown defined, cannot implement sys_chown() + return -ENOSYS; #endif } static __attribute__((unused)) int chown(const char *path, uid_t owner, gid_t group) { - int ret = sys_chown(path, owner, group); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_chown(path, owner, group)); } @@ -183,13 +180,7 @@ int sys_chroot(const char *path) static __attribute__((unused)) int chroot(const char *path) { - int ret = sys_chroot(path); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_chroot(path)); } @@ -206,13 +197,7 @@ int sys_close(int fd) static __attribute__((unused)) int close(int fd) { - int ret = sys_close(fd); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_close(fd)); } @@ -229,13 +214,7 @@ int sys_dup(int fd) static __attribute__((unused)) int dup(int fd) { - int ret = sys_dup(fd); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_dup(fd)); } @@ -251,20 +230,14 @@ int sys_dup2(int old, int new) #elif defined(__NR_dup2) return my_syscall2(__NR_dup2, old, new); #else -#error Neither __NR_dup3 nor __NR_dup2 defined, cannot implement sys_dup2() + return -ENOSYS; #endif } static __attribute__((unused)) int dup2(int old, int new) { - int ret = sys_dup2(old, new); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_dup2(old, new)); } @@ -282,13 +255,7 @@ int sys_dup3(int old, int new, int flags) static __attribute__((unused)) int dup3(int old, int new, int flags) { - int ret = sys_dup3(old, new, flags); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_dup3(old, new, flags)); } #endif @@ -306,13 +273,7 @@ int sys_execve(const char *filename, char *const argv[], char *const envp[]) static __attribute__((unused)) int execve(const char *filename, char *const argv[], char *const envp[]) { - int ret = sys_execve(filename, argv, envp); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_execve(filename, argv, envp)); } @@ -351,7 +312,7 @@ pid_t sys_fork(void) #elif defined(__NR_fork) return my_syscall0(__NR_fork); #else -#error Neither __NR_clone nor __NR_fork defined, cannot implement sys_fork() + return -ENOSYS; #endif } #endif @@ -359,13 +320,7 @@ pid_t sys_fork(void) static __attribute__((unused)) pid_t fork(void) { - pid_t ret = sys_fork(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_fork()); } @@ -382,13 +337,7 @@ int sys_fsync(int fd) static __attribute__((unused)) int fsync(int fd) { - int ret = sys_fsync(fd); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_fsync(fd)); } @@ -405,13 +354,7 @@ int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) static __attribute__((unused)) int getdents64(int fd, struct linux_dirent64 *dirp, int count) { - int ret = sys_getdents64(fd, dirp, count); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_getdents64(fd, dirp, count)); } @@ -449,13 +392,7 @@ pid_t sys_getpgid(pid_t pid) static __attribute__((unused)) pid_t getpgid(pid_t pid) { - pid_t ret = sys_getpgid(pid); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_getpgid(pid)); } @@ -529,21 +466,13 @@ pid_t gettid(void) static unsigned long getauxval(unsigned long key); /* - * long getpagesize(void); + * int getpagesize(void); */ static __attribute__((unused)) -long getpagesize(void) +int getpagesize(void) { - long ret; - - ret = getauxval(AT_PAGESZ); - if (!ret) { - SET_ERRNO(ENOENT); - return -1; - } - - return ret; + return __sysret((int)getauxval(AT_PAGESZ) ?: -ENOENT); } @@ -554,19 +483,17 @@ long getpagesize(void) static __attribute__((unused)) int sys_gettimeofday(struct timeval *tv, struct timezone *tz) { +#ifdef __NR_gettimeofday return my_syscall2(__NR_gettimeofday, tv, tz); +#else + return -ENOSYS; +#endif } static __attribute__((unused)) int gettimeofday(struct timeval *tv, struct timezone *tz) { - int ret = sys_gettimeofday(tv, tz); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_gettimeofday(tv, tz)); } @@ -604,13 +531,7 @@ int sys_ioctl(int fd, unsigned long req, void *value) static __attribute__((unused)) int ioctl(int fd, unsigned long req, void *value) { - int ret = sys_ioctl(fd, req, value); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_ioctl(fd, req, value)); } /* @@ -626,13 +547,7 @@ int sys_kill(pid_t pid, int signal) static __attribute__((unused)) int kill(pid_t pid, int signal) { - int ret = sys_kill(pid, signal); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_kill(pid, signal)); } @@ -648,20 +563,14 @@ int sys_link(const char *old, const char *new) #elif defined(__NR_link) return my_syscall2(__NR_link, old, new); #else -#error Neither __NR_linkat nor __NR_link defined, cannot implement sys_link() + return -ENOSYS; #endif } static __attribute__((unused)) int link(const char *old, const char *new) { - int ret = sys_link(old, new); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_link(old, new)); } @@ -672,19 +581,17 @@ int link(const char *old, const char *new) static __attribute__((unused)) off_t sys_lseek(int fd, off_t offset, int whence) { +#ifdef __NR_lseek return my_syscall3(__NR_lseek, fd, offset, whence); +#else + return -ENOSYS; +#endif } static __attribute__((unused)) off_t lseek(int fd, off_t offset, int whence) { - off_t ret = sys_lseek(fd, offset, whence); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_lseek(fd, offset, whence)); } @@ -700,20 +607,36 @@ int sys_mkdir(const char *path, mode_t mode) #elif defined(__NR_mkdir) return my_syscall2(__NR_mkdir, path, mode); #else -#error Neither __NR_mkdirat nor __NR_mkdir defined, cannot implement sys_mkdir() + return -ENOSYS; #endif } static __attribute__((unused)) int mkdir(const char *path, mode_t mode) { - int ret = sys_mkdir(path, mode); + return __sysret(sys_mkdir(path, mode)); +} - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; +/* + * int rmdir(const char *path); + */ + +static __attribute__((unused)) +int sys_rmdir(const char *path) +{ +#ifdef __NR_rmdir + return my_syscall1(__NR_rmdir, path); +#elif defined(__NR_unlinkat) + return my_syscall3(__NR_unlinkat, AT_FDCWD, path, AT_REMOVEDIR); +#else + return -ENOSYS; +#endif +} + +static __attribute__((unused)) +int rmdir(const char *path) +{ + return __sysret(sys_rmdir(path)); } @@ -729,42 +652,21 @@ long sys_mknod(const char *path, mode_t mode, dev_t dev) #elif defined(__NR_mknod) return my_syscall3(__NR_mknod, path, mode, dev); #else -#error Neither __NR_mknodat nor __NR_mknod defined, cannot implement sys_mknod() + return -ENOSYS; #endif } static __attribute__((unused)) int mknod(const char *path, mode_t mode, dev_t dev) { - int ret = sys_mknod(path, mode, dev); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_mknod(path, mode, dev)); } -#ifndef MAP_SHARED -#define MAP_SHARED 0x01 /* Share changes */ -#define MAP_PRIVATE 0x02 /* Changes are private */ -#define MAP_SHARED_VALIDATE 0x03 /* share + validate extension flags */ -#endif - -#ifndef MAP_FAILED -#define MAP_FAILED ((void *)-1) -#endif - #ifndef sys_mmap static __attribute__((unused)) void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { -#ifndef my_syscall6 - /* Function not implemented. */ - return (void *)-ENOSYS; -#else - int n; #if defined(__NR_mmap2) @@ -775,10 +677,14 @@ void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, #endif return (void *)my_syscall6(n, addr, length, prot, flags, fd, offset); -#endif } #endif +/* Note that on Linux, MAP_FAILED is -1 so we can use the generic __sysret() + * which returns -1 upon error and still satisfy user land that checks for + * MAP_FAILED. + */ + static __attribute__((unused)) void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { @@ -800,13 +706,7 @@ int sys_munmap(void *addr, size_t length) static __attribute__((unused)) int munmap(void *addr, size_t length) { - int ret = sys_munmap(addr, length); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_munmap(addr, length)); } /* @@ -826,13 +726,7 @@ int mount(const char *src, const char *tgt, const char *fst, unsigned long flags, const void *data) { - int ret = sys_mount(src, tgt, fst, flags, data); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_mount(src, tgt, fst, flags, data)); } @@ -848,7 +742,7 @@ int sys_open(const char *path, int flags, mode_t mode) #elif defined(__NR_open) return my_syscall3(__NR_open, path, flags, mode); #else -#error Neither __NR_openat nor __NR_open defined, cannot implement sys_open() + return -ENOSYS; #endif } @@ -856,7 +750,6 @@ static __attribute__((unused)) int open(const char *path, int flags, ...) { mode_t mode = 0; - int ret; if (flags & O_CREAT) { va_list args; @@ -866,13 +759,31 @@ int open(const char *path, int flags, ...) va_end(args); } - ret = sys_open(path, flags, mode); + return __sysret(sys_open(path, flags, mode)); +} - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + +/* + * int pipe2(int pipefd[2], int flags); + * int pipe(int pipefd[2]); + */ + +static __attribute__((unused)) +int sys_pipe2(int pipefd[2], int flags) +{ + return my_syscall2(__NR_pipe2, pipefd, flags); +} + +static __attribute__((unused)) +int pipe2(int pipefd[2], int flags) +{ + return __sysret(sys_pipe2(pipefd, flags)); +} + +static __attribute__((unused)) +int pipe(int pipefd[2]) +{ + return pipe2(pipefd, 0); } @@ -892,13 +803,7 @@ static __attribute__((unused)) int prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { - int ret = sys_prctl(option, arg2, arg3, arg4, arg5); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_prctl(option, arg2, arg3, arg4, arg5)); } @@ -915,13 +820,7 @@ int sys_pivot_root(const char *new, const char *old) static __attribute__((unused)) int pivot_root(const char *new, const char *old) { - int ret = sys_pivot_root(new, old); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_pivot_root(new, old)); } @@ -943,20 +842,14 @@ int sys_poll(struct pollfd *fds, int nfds, int timeout) #elif defined(__NR_poll) return my_syscall3(__NR_poll, fds, nfds, timeout); #else -#error Neither __NR_ppoll nor __NR_poll defined, cannot implement sys_poll() + return -ENOSYS; #endif } static __attribute__((unused)) int poll(struct pollfd *fds, int nfds, int timeout) { - int ret = sys_poll(fds, nfds, timeout); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_poll(fds, nfds, timeout)); } @@ -973,13 +866,7 @@ ssize_t sys_read(int fd, void *buf, size_t count) static __attribute__((unused)) ssize_t read(int fd, void *buf, size_t count) { - ssize_t ret = sys_read(fd, buf, count); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_read(fd, buf, count)); } @@ -997,13 +884,7 @@ ssize_t sys_reboot(int magic1, int magic2, int cmd, void *arg) static __attribute__((unused)) int reboot(int cmd) { - int ret = sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, 0); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, 0)); } @@ -1020,13 +901,7 @@ int sys_sched_yield(void) static __attribute__((unused)) int sched_yield(void) { - int ret = sys_sched_yield(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_sched_yield()); } @@ -1059,20 +934,14 @@ int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeva #endif return my_syscall5(__NR__newselect, nfds, rfds, wfds, efds, timeout); #else -#error None of __NR_select, __NR_pselect6, nor __NR__newselect defined, cannot implement sys_select() + return -ENOSYS; #endif } static __attribute__((unused)) int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) { - int ret = sys_select(nfds, rfds, wfds, efds, timeout); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_select(nfds, rfds, wfds, efds, timeout)); } @@ -1089,13 +958,7 @@ int sys_setpgid(pid_t pid, pid_t pgid) static __attribute__((unused)) int setpgid(pid_t pid, pid_t pgid) { - int ret = sys_setpgid(pid, pgid); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_setpgid(pid, pgid)); } @@ -1112,55 +975,41 @@ pid_t sys_setsid(void) static __attribute__((unused)) pid_t setsid(void) { - pid_t ret = sys_setsid(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_setsid()); } -#if defined(__NR_statx) /* * int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf); + * int stat(const char *path, struct stat *buf); */ static __attribute__((unused)) int sys_statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf) { +#ifdef __NR_statx return my_syscall5(__NR_statx, fd, path, flags, mask, buf); +#else + return -ENOSYS; +#endif } static __attribute__((unused)) int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf) { - int ret = sys_statx(fd, path, flags, mask, buf); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_statx(fd, path, flags, mask, buf)); } -#endif -/* - * int stat(const char *path, struct stat *buf); - * Warning: the struct stat's layout is arch-dependent. - */ -#if defined(__NR_statx) && !defined(__NR_newfstatat) && !defined(__NR_stat) -/* - * Maybe we can just use statx() when available for all architectures? - */ static __attribute__((unused)) -int sys_stat(const char *path, struct stat *buf) +int stat(const char *path, struct stat *buf) { struct statx statx; long ret; - ret = sys_statx(AT_FDCWD, path, AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx); + ret = __sysret(sys_statx(AT_FDCWD, path, AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx)); + if (ret == -1) + return ret; + buf->st_dev = ((statx.stx_dev_minor & 0xff) | (statx.stx_dev_major << 8) | ((statx.stx_dev_minor & ~0xff) << 12)); @@ -1181,53 +1030,8 @@ int sys_stat(const char *path, struct stat *buf) buf->st_mtim.tv_nsec = statx.stx_mtime.tv_nsec; buf->st_ctim.tv_sec = statx.stx_ctime.tv_sec; buf->st_ctim.tv_nsec = statx.stx_ctime.tv_nsec; - return ret; -} -#else -static __attribute__((unused)) -int sys_stat(const char *path, struct stat *buf) -{ - struct sys_stat_struct stat; - long ret; - -#ifdef __NR_newfstatat - /* only solution for arm64 */ - ret = my_syscall4(__NR_newfstatat, AT_FDCWD, path, &stat, 0); -#elif defined(__NR_stat) - ret = my_syscall2(__NR_stat, path, &stat); -#else -#error Neither __NR_newfstatat nor __NR_stat defined, cannot implement sys_stat() -#endif - buf->st_dev = stat.st_dev; - buf->st_ino = stat.st_ino; - buf->st_mode = stat.st_mode; - buf->st_nlink = stat.st_nlink; - buf->st_uid = stat.st_uid; - buf->st_gid = stat.st_gid; - buf->st_rdev = stat.st_rdev; - buf->st_size = stat.st_size; - buf->st_blksize = stat.st_blksize; - buf->st_blocks = stat.st_blocks; - buf->st_atim.tv_sec = stat.st_atime; - buf->st_atim.tv_nsec = stat.st_atime_nsec; - buf->st_mtim.tv_sec = stat.st_mtime; - buf->st_mtim.tv_nsec = stat.st_mtime_nsec; - buf->st_ctim.tv_sec = stat.st_ctime; - buf->st_ctim.tv_nsec = stat.st_ctime_nsec; - return ret; -} -#endif -static __attribute__((unused)) -int stat(const char *path, struct stat *buf) -{ - int ret = sys_stat(path, buf); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return 0; } @@ -1243,20 +1047,14 @@ int sys_symlink(const char *old, const char *new) #elif defined(__NR_symlink) return my_syscall2(__NR_symlink, old, new); #else -#error Neither __NR_symlinkat nor __NR_symlink defined, cannot implement sys_symlink() + return -ENOSYS; #endif } static __attribute__((unused)) int symlink(const char *old, const char *new) { - int ret = sys_symlink(old, new); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_symlink(old, new)); } @@ -1290,13 +1088,7 @@ int sys_umount2(const char *path, int flags) static __attribute__((unused)) int umount2(const char *path, int flags) { - int ret = sys_umount2(path, flags); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_umount2(path, flags)); } @@ -1312,20 +1104,14 @@ int sys_unlink(const char *path) #elif defined(__NR_unlink) return my_syscall1(__NR_unlink, path); #else -#error Neither __NR_unlinkat nor __NR_unlink defined, cannot implement sys_unlink() + return -ENOSYS; #endif } static __attribute__((unused)) int unlink(const char *path) { - int ret = sys_unlink(path); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_unlink(path)); } @@ -1338,44 +1124,30 @@ int unlink(const char *path) static __attribute__((unused)) pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage) { +#ifdef __NR_wait4 return my_syscall4(__NR_wait4, pid, status, options, rusage); +#else + return -ENOSYS; +#endif } static __attribute__((unused)) pid_t wait(int *status) { - pid_t ret = sys_wait4(-1, status, 0, NULL); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_wait4(-1, status, 0, NULL)); } static __attribute__((unused)) pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage) { - pid_t ret = sys_wait4(pid, status, options, rusage); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_wait4(pid, status, options, rusage)); } static __attribute__((unused)) pid_t waitpid(pid_t pid, int *status, int options) { - pid_t ret = sys_wait4(pid, status, options, NULL); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_wait4(pid, status, options, NULL)); } @@ -1392,13 +1164,7 @@ ssize_t sys_write(int fd, const void *buf, size_t count) static __attribute__((unused)) ssize_t write(int fd, const void *buf, size_t count) { - ssize_t ret = sys_write(fd, buf, count); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_write(fd, buf, count)); } @@ -1415,13 +1181,7 @@ int sys_memfd_create(const char *name, unsigned int flags) static __attribute__((unused)) int memfd_create(const char *name, unsigned int flags) { - ssize_t ret = sys_memfd_create(name, flags); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; + return __sysret(sys_memfd_create(name, flags)); } /* make sure to include all global symbols */ diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h index f96e28bff4ba..8cfc4c860fa4 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -8,13 +8,15 @@ #define _NOLIBC_TYPES_H #include "std.h" -#include <linux/time.h> +#include <linux/mman.h> +#include <linux/reboot.h> /* for LINUX_REBOOT_* */ #include <linux/stat.h> +#include <linux/time.h> /* Only the generic macros and types may be defined here. The arch-specific - * ones such as the O_RDONLY and related macros used by fcntl() and open(), or - * the layout of sys_stat_struct must not be defined here. + * ones such as the O_RDONLY and related macros used by fcntl() and open() + * must not be defined here. */ /* stat flags (WARNING, octal here). We need to check for an existing @@ -81,11 +83,25 @@ #define MAXPATHLEN (PATH_MAX) #endif +/* flags for mmap */ +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + /* whence values for lseek() */ #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 +/* flags for reboot */ +#define RB_AUTOBOOT LINUX_REBOOT_CMD_RESTART +#define RB_HALT_SYSTEM LINUX_REBOOT_CMD_HALT +#define RB_ENABLE_CAD LINUX_REBOOT_CMD_CAD_ON +#define RB_DISABLE_CAD LINUX_REBOOT_CMD_CAD_OFF +#define RB_POWER_OFF LINUX_REBOOT_CMD_POWER_OFF +#define RB_SW_SUSPEND LINUX_REBOOT_CMD_SW_SUSPEND +#define RB_KEXEC LINUX_REBOOT_CMD_KEXEC + /* Macros used on waitpid()'s return status */ #define WEXITSTATUS(status) (((status) & 0xff00) >> 8) #define WIFEXITED(status) (((status) & 0x7f) == 0) diff --git a/tools/include/nolibc/unistd.h b/tools/include/nolibc/unistd.h index 0e832e10a0b2..e38f3660c051 100644 --- a/tools/include/nolibc/unistd.h +++ b/tools/include/nolibc/unistd.h @@ -56,18 +56,9 @@ int tcsetpgrp(int fd, pid_t pid) return ioctl(fd, TIOCSPGRP, &pid); } -#define _syscall(N, ...) \ -({ \ - long _ret = my_syscall##N(__VA_ARGS__); \ - if (_ret < 0) { \ - SET_ERRNO(-_ret); \ - _ret = -1; \ - } \ - _ret; \ -}) - -#define _syscall_narg(...) __syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) #define __syscall_narg(_0, _1, _2, _3, _4, _5, _6, N, ...) N +#define _syscall_narg(...) __syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) +#define _syscall(N, ...) __sysret(my_syscall##N(__VA_ARGS__)) #define _syscall_n(N, ...) _syscall(N, __VA_ARGS__) #define syscall(...) _syscall_n(_syscall_narg(__VA_ARGS__), ##__VA_ARGS__) diff --git a/tools/include/uapi/asm-generic/unistd.h b/tools/include/uapi/asm-generic/unistd.h index dd7d8e10f16d..fd6c1cb585db 100644 --- a/tools/include/uapi/asm-generic/unistd.h +++ b/tools/include/uapi/asm-generic/unistd.h @@ -817,8 +817,11 @@ __SYSCALL(__NR_futex_waitv, sys_futex_waitv) #define __NR_set_mempolicy_home_node 450 __SYSCALL(__NR_set_mempolicy_home_node, sys_set_mempolicy_home_node) +#define __NR_cachestat 451 +__SYSCALL(__NR_cachestat, sys_cachestat) + #undef __NR_syscalls -#define __NR_syscalls 451 +#define __NR_syscalls 452 /* * 32 bit systems traditionally used different diff --git a/tools/include/uapi/drm/i915_drm.h b/tools/include/uapi/drm/i915_drm.h index dba7c5a5b25e..7000e5910a1d 100644 --- a/tools/include/uapi/drm/i915_drm.h +++ b/tools/include/uapi/drm/i915_drm.h @@ -280,7 +280,16 @@ enum drm_i915_pmu_engine_sample { #define I915_PMU_ENGINE_SEMA(class, instance) \ __I915_PMU_ENGINE(class, instance, I915_SAMPLE_SEMA) -#define __I915_PMU_OTHER(x) (__I915_PMU_ENGINE(0xff, 0xff, 0xf) + 1 + (x)) +/* + * Top 4 bits of every non-engine counter are GT id. + */ +#define __I915_PMU_GT_SHIFT (60) + +#define ___I915_PMU_OTHER(gt, x) \ + (((__u64)__I915_PMU_ENGINE(0xff, 0xff, 0xf) + 1 + (x)) | \ + ((__u64)(gt) << __I915_PMU_GT_SHIFT)) + +#define __I915_PMU_OTHER(x) ___I915_PMU_OTHER(0, x) #define I915_PMU_ACTUAL_FREQUENCY __I915_PMU_OTHER(0) #define I915_PMU_REQUESTED_FREQUENCY __I915_PMU_OTHER(1) @@ -290,6 +299,12 @@ enum drm_i915_pmu_engine_sample { #define I915_PMU_LAST /* Deprecated - do not use */ I915_PMU_RC6_RESIDENCY +#define __I915_PMU_ACTUAL_FREQUENCY(gt) ___I915_PMU_OTHER(gt, 0) +#define __I915_PMU_REQUESTED_FREQUENCY(gt) ___I915_PMU_OTHER(gt, 1) +#define __I915_PMU_INTERRUPTS(gt) ___I915_PMU_OTHER(gt, 2) +#define __I915_PMU_RC6_RESIDENCY(gt) ___I915_PMU_OTHER(gt, 3) +#define __I915_PMU_SOFTWARE_GT_AWAKE_TIME(gt) ___I915_PMU_OTHER(gt, 4) + /* Each region is a minimum of 16k, and there are at most 255 of them. */ #define I915_NR_TEX_REGIONS 255 /* table size 2k - maximum due to use @@ -659,7 +674,8 @@ typedef struct drm_i915_irq_wait { * If the IOCTL is successful, the returned parameter will be set to one of the * following values: * * 0 if HuC firmware load is not complete, - * * 1 if HuC firmware is authenticated and running. + * * 1 if HuC firmware is loaded and fully authenticated, + * * 2 if HuC firmware is loaded and authenticated for clear media only */ #define I915_PARAM_HUC_STATUS 42 @@ -771,6 +787,25 @@ typedef struct drm_i915_irq_wait { */ #define I915_PARAM_OA_TIMESTAMP_FREQUENCY 57 +/* + * Query the status of PXP support in i915. + * + * The query can fail in the following scenarios with the listed error codes: + * -ENODEV = PXP support is not available on the GPU device or in the + * kernel due to missing component drivers or kernel configs. + * + * If the IOCTL is successful, the returned parameter will be set to one of + * the following values: + * 1 = PXP feature is supported and is ready for use. + * 2 = PXP feature is supported but should be ready soon (pending + * initialization of non-i915 system dependencies). + * + * NOTE: When param is supported (positive return values), user space should + * still refer to the GEM PXP context-creation UAPI header specs to be + * aware of possible failure due to system state machine at the time. + */ +#define I915_PARAM_PXP_STATUS 58 + /* Must be kept compact -- no holes and well documented */ /** @@ -2096,6 +2131,21 @@ struct drm_i915_gem_context_param { * * -ENODEV: feature not available * -EPERM: trying to mark a recoverable or not bannable context as protected + * -ENXIO: A dependency such as a component driver or firmware is not yet + * loaded so user space may need to attempt again. Depending on the + * device, this error may be reported if protected context creation is + * attempted very early after kernel start because the internal timeout + * waiting for such dependencies is not guaranteed to be larger than + * required (numbers differ depending on system and kernel config): + * - ADL/RPL: dependencies may take up to 3 seconds from kernel start + * while context creation internal timeout is 250 milisecs + * - MTL: dependencies may take up to 8 seconds from kernel start + * while context creation internal timeout is 250 milisecs + * NOTE: such dependencies happen once, so a subsequent call to create a + * protected context after a prior successful call will not experience + * such timeouts and will not return -ENXIO (unless the driver is reloaded, + * or, depending on the device, resumes from a suspended state). + * -EIO: The firmware did not succeed in creating the protected context. */ #define I915_CONTEXT_PARAM_PROTECTED_CONTENT 0xd /* Must be kept compact -- no holes and well documented */ @@ -3630,9 +3680,13 @@ struct drm_i915_gem_create_ext { * * For I915_GEM_CREATE_EXT_PROTECTED_CONTENT usage see * struct drm_i915_gem_create_ext_protected_content. + * + * For I915_GEM_CREATE_EXT_SET_PAT usage see + * struct drm_i915_gem_create_ext_set_pat. */ #define I915_GEM_CREATE_EXT_MEMORY_REGIONS 0 #define I915_GEM_CREATE_EXT_PROTECTED_CONTENT 1 +#define I915_GEM_CREATE_EXT_SET_PAT 2 __u64 extensions; }; @@ -3747,6 +3801,43 @@ struct drm_i915_gem_create_ext_protected_content { __u32 flags; }; +/** + * struct drm_i915_gem_create_ext_set_pat - The + * I915_GEM_CREATE_EXT_SET_PAT extension. + * + * If this extension is provided, the specified caching policy (PAT index) is + * applied to the buffer object. + * + * Below is an example on how to create an object with specific caching policy: + * + * .. code-block:: C + * + * struct drm_i915_gem_create_ext_set_pat set_pat_ext = { + * .base = { .name = I915_GEM_CREATE_EXT_SET_PAT }, + * .pat_index = 0, + * }; + * struct drm_i915_gem_create_ext create_ext = { + * .size = PAGE_SIZE, + * .extensions = (uintptr_t)&set_pat_ext, + * }; + * + * int err = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &create_ext); + * if (err) ... + */ +struct drm_i915_gem_create_ext_set_pat { + /** @base: Extension link. See struct i915_user_extension. */ + struct i915_user_extension base; + /** + * @pat_index: PAT index to be set + * PAT index is a bit field in Page Table Entry to control caching + * behaviors for GPU accesses. The definition of PAT index is + * platform dependent and can be found in hardware specifications, + */ + __u32 pat_index; + /** @rsvd: reserved for future use */ + __u32 rsvd; +}; + /* ID of the protected content session managed by i915 when PXP is active */ #define I915_PROTECTED_CONTENT_DEFAULT_SESSION 0xf diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 60a9d59beeab..8790b3962e4b 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -19,6 +19,7 @@ /* ld/ldx fields */ #define BPF_DW 0x18 /* double word (64-bit) */ +#define BPF_MEMSX 0x80 /* load with sign extension */ #define BPF_ATOMIC 0xc0 /* atomic memory ops - op type in immediate */ #define BPF_XADD 0xc0 /* exclusive add - legacy name */ @@ -1036,6 +1037,9 @@ enum bpf_attach_type { BPF_LSM_CGROUP, BPF_STRUCT_OPS, BPF_NETFILTER, + BPF_TCX_INGRESS, + BPF_TCX_EGRESS, + BPF_TRACE_UPROBE_MULTI, __MAX_BPF_ATTACH_TYPE }; @@ -1053,10 +1057,21 @@ enum bpf_link_type { BPF_LINK_TYPE_KPROBE_MULTI = 8, BPF_LINK_TYPE_STRUCT_OPS = 9, BPF_LINK_TYPE_NETFILTER = 10, - + BPF_LINK_TYPE_TCX = 11, + BPF_LINK_TYPE_UPROBE_MULTI = 12, MAX_BPF_LINK_TYPE, }; +enum bpf_perf_event_type { + BPF_PERF_EVENT_UNSPEC = 0, + BPF_PERF_EVENT_UPROBE = 1, + BPF_PERF_EVENT_URETPROBE = 2, + BPF_PERF_EVENT_KPROBE = 3, + BPF_PERF_EVENT_KRETPROBE = 4, + BPF_PERF_EVENT_TRACEPOINT = 5, + BPF_PERF_EVENT_EVENT = 6, +}; + /* cgroup-bpf attach flags used in BPF_PROG_ATTACH command * * NONE(default): No further bpf programs allowed in the subtree. @@ -1103,7 +1118,12 @@ enum bpf_link_type { */ #define BPF_F_ALLOW_OVERRIDE (1U << 0) #define BPF_F_ALLOW_MULTI (1U << 1) +/* Generic attachment flags. */ #define BPF_F_REPLACE (1U << 2) +#define BPF_F_BEFORE (1U << 3) +#define BPF_F_AFTER (1U << 4) +#define BPF_F_ID (1U << 5) +#define BPF_F_LINK BPF_F_LINK /* 1 << 13 */ /* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the * verifier will perform strict alignment checking as if the kernel @@ -1168,7 +1188,21 @@ enum bpf_link_type { /* link_create.kprobe_multi.flags used in LINK_CREATE command for * BPF_TRACE_KPROBE_MULTI attach type to create return probe. */ -#define BPF_F_KPROBE_MULTI_RETURN (1U << 0) +enum { + BPF_F_KPROBE_MULTI_RETURN = (1U << 0) +}; + +/* link_create.uprobe_multi.flags used in LINK_CREATE command for + * BPF_TRACE_UPROBE_MULTI attach type to create return probe. + */ +enum { + BPF_F_UPROBE_MULTI_RETURN = (1U << 0) +}; + +/* link_create.netfilter.flags used in LINK_CREATE command for + * BPF_PROG_TYPE_NETFILTER to enable IP packet defragmentation. + */ +#define BPF_F_NETFILTER_IP_DEFRAG (1U << 0) /* When BPF ldimm64's insn[0].src_reg != 0 then this can have * the following extensions: @@ -1434,14 +1468,19 @@ union bpf_attr { }; struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */ - __u32 target_fd; /* container object to attach to */ - __u32 attach_bpf_fd; /* eBPF program to attach */ + union { + __u32 target_fd; /* target object to attach to or ... */ + __u32 target_ifindex; /* target ifindex */ + }; + __u32 attach_bpf_fd; __u32 attach_type; __u32 attach_flags; - __u32 replace_bpf_fd; /* previously attached eBPF - * program to replace if - * BPF_F_REPLACE is used - */ + __u32 replace_bpf_fd; + union { + __u32 relative_fd; + __u32 relative_id; + }; + __u64 expected_revision; }; struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */ @@ -1487,16 +1526,26 @@ union bpf_attr { } info; struct { /* anonymous struct used by BPF_PROG_QUERY command */ - __u32 target_fd; /* container object to query */ + union { + __u32 target_fd; /* target object to query or ... */ + __u32 target_ifindex; /* target ifindex */ + }; __u32 attach_type; __u32 query_flags; __u32 attach_flags; __aligned_u64 prog_ids; - __u32 prog_cnt; + union { + __u32 prog_cnt; + __u32 count; + }; + __u32 :32; /* output: per-program attach_flags. * not allowed to be set during effective query. */ __aligned_u64 prog_attach_flags; + __aligned_u64 link_ids; + __aligned_u64 link_attach_flags; + __u64 revision; } query; struct { /* anonymous struct used by BPF_RAW_TRACEPOINT_OPEN command */ @@ -1539,13 +1588,13 @@ union bpf_attr { __u32 map_fd; /* struct_ops to attach */ }; union { - __u32 target_fd; /* object to attach to */ - __u32 target_ifindex; /* target ifindex */ + __u32 target_fd; /* target object to attach to or ... */ + __u32 target_ifindex; /* target ifindex */ }; __u32 attach_type; /* attach type */ __u32 flags; /* extra flags */ union { - __u32 target_btf_id; /* btf_id of target to attach to */ + __u32 target_btf_id; /* btf_id of target to attach to */ struct { __aligned_u64 iter_info; /* extra bpf_iter_link_info */ __u32 iter_info_len; /* iter_info length */ @@ -1579,6 +1628,22 @@ union bpf_attr { __s32 priority; __u32 flags; } netfilter; + struct { + union { + __u32 relative_fd; + __u32 relative_id; + }; + __u64 expected_revision; + } tcx; + struct { + __aligned_u64 path; + __aligned_u64 offsets; + __aligned_u64 ref_ctr_offsets; + __aligned_u64 cookies; + __u32 cnt; + __u32 flags; + __u32 pid; + } uprobe_multi; }; } link_create; @@ -4159,9 +4224,6 @@ union bpf_attr { * **-EOPNOTSUPP** if the operation is not supported, for example * a call from outside of TC ingress. * - * **-ESOCKTNOSUPPORT** if the socket type is not supported - * (reuseport). - * * long bpf_sk_assign(struct bpf_sk_lookup *ctx, struct bpf_sock *sk, u64 flags) * Description * Helper is overloaded depending on BPF program type. This @@ -5044,9 +5106,14 @@ union bpf_attr { * u64 bpf_get_func_ip(void *ctx) * Description * Get address of the traced function (for tracing and kprobe programs). + * + * When called for kprobe program attached as uprobe it returns + * probe address for both entry and return uprobe. + * * Return - * Address of the traced function. + * Address of the traced function for kprobe. * 0 for kprobes placed within the function (not at the entry). + * Address of the probe for uprobe and return uprobe. * * u64 bpf_get_attach_cookie(void *ctx) * Description @@ -6187,6 +6254,19 @@ struct bpf_sock_tuple { }; }; +/* (Simplified) user return codes for tcx prog type. + * A valid tcx program must return one of these defined values. All other + * return codes are reserved for future use. Must remain compatible with + * their TC_ACT_* counter-parts. For compatibility in behavior, unknown + * return codes are mapped to TCX_NEXT. + */ +enum tcx_action_base { + TCX_NEXT = -1, + TCX_PASS = 0, + TCX_DROP = 2, + TCX_REDIRECT = 7, +}; + struct bpf_xdp_sock { __u32 queue_id; }; @@ -6439,6 +6519,40 @@ struct bpf_link_info { __s32 priority; __u32 flags; } netfilter; + struct { + __aligned_u64 addrs; + __u32 count; /* in/out: kprobe_multi function count */ + __u32 flags; + } kprobe_multi; + struct { + __u32 type; /* enum bpf_perf_event_type */ + __u32 :32; + union { + struct { + __aligned_u64 file_name; /* in/out */ + __u32 name_len; + __u32 offset; /* offset from file_name */ + } uprobe; /* BPF_PERF_EVENT_UPROBE, BPF_PERF_EVENT_URETPROBE */ + struct { + __aligned_u64 func_name; /* in/out */ + __u32 name_len; + __u32 offset; /* offset from func_name */ + __u64 addr; + } kprobe; /* BPF_PERF_EVENT_KPROBE, BPF_PERF_EVENT_KRETPROBE */ + struct { + __aligned_u64 tp_name; /* in/out */ + __u32 name_len; + } tracepoint; /* BPF_PERF_EVENT_TRACEPOINT */ + struct { + __u64 config; + __u32 type; + } event; /* BPF_PERF_EVENT_EVENT */ + }; + } perf_event; + struct { + __u32 ifindex; + __u32 attach_type; + } tcx; }; } __attribute__((aligned(8))); @@ -7012,6 +7126,7 @@ struct bpf_list_head { struct bpf_list_node { __u64 :64; __u64 :64; + __u64 :64; } __attribute__((aligned(8))); struct bpf_rb_root { @@ -7023,6 +7138,7 @@ struct bpf_rb_node { __u64 :64; __u64 :64; __u64 :64; + __u64 :64; } __attribute__((aligned(8))); struct bpf_refcount { diff --git a/tools/include/uapi/linux/fcntl.h b/tools/include/uapi/linux/fcntl.h index e8c07da58c9f..6c80f96049bd 100644 --- a/tools/include/uapi/linux/fcntl.h +++ b/tools/include/uapi/linux/fcntl.h @@ -112,4 +112,9 @@ #define AT_RECURSIVE 0x8000 /* Apply to the entire subtree */ +/* Flags for name_to_handle_at(2). We reuse AT_ flag space to save bits... */ +#define AT_HANDLE_FID AT_REMOVEDIR /* file handle is needed to + compare object identity and may not + be usable to open_by_handle_at(2) */ + #endif /* _UAPI_LINUX_FCNTL_H */ diff --git a/tools/include/uapi/linux/if_xdp.h b/tools/include/uapi/linux/if_xdp.h index a78a8096f4ce..73a47da885dc 100644 --- a/tools/include/uapi/linux/if_xdp.h +++ b/tools/include/uapi/linux/if_xdp.h @@ -25,6 +25,12 @@ * application. */ #define XDP_USE_NEED_WAKEUP (1 << 3) +/* By setting this option, userspace application indicates that it can + * handle multiple descriptors per packet thus enabling xsk core to split + * multi-buffer XDP frames into multiple Rx descriptors. Without this set + * such frames will be dropped by xsk. + */ +#define XDP_USE_SG (1 << 4) /* Flags for xsk_umem_config flags */ #define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0) @@ -106,6 +112,9 @@ struct xdp_desc { __u32 options; }; +/* Flag indicating packet constitutes of multiple buffers*/ +#define XDP_PKT_CONTD (1 << 0) + /* UMEM descriptor is __u64 */ #endif /* _LINUX_IF_XDP_H */ diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index 737318b1c1d9..f089ab290978 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h @@ -1190,6 +1190,8 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP 225 #define KVM_CAP_PMU_EVENT_MASKED_EVENTS 226 #define KVM_CAP_COUNTER_OFFSET 227 +#define KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE 228 +#define KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES 229 #ifdef KVM_CAP_IRQ_ROUTING @@ -1442,6 +1444,8 @@ enum kvm_device_type { #define KVM_DEV_TYPE_XIVE KVM_DEV_TYPE_XIVE KVM_DEV_TYPE_ARM_PV_TIME, #define KVM_DEV_TYPE_ARM_PV_TIME KVM_DEV_TYPE_ARM_PV_TIME + KVM_DEV_TYPE_RISCV_AIA, +#define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_MAX, }; @@ -1613,7 +1617,7 @@ struct kvm_s390_ucas_mapping { #define KVM_GET_DEBUGREGS _IOR(KVMIO, 0xa1, struct kvm_debugregs) #define KVM_SET_DEBUGREGS _IOW(KVMIO, 0xa2, struct kvm_debugregs) /* - * vcpu version available with KVM_ENABLE_CAP + * vcpu version available with KVM_CAP_ENABLE_CAP * vm version available with KVM_CAP_ENABLE_CAP_VM */ #define KVM_ENABLE_CAP _IOW(KVMIO, 0xa3, struct kvm_enable_cap) diff --git a/tools/include/uapi/linux/mman.h b/tools/include/uapi/linux/mman.h index f55bc680b5b0..a246e11988d5 100644 --- a/tools/include/uapi/linux/mman.h +++ b/tools/include/uapi/linux/mman.h @@ -4,6 +4,7 @@ #include <asm/mman.h> #include <asm-generic/hugetlb_encode.h> +#include <linux/types.h> #define MREMAP_MAYMOVE 1 #define MREMAP_FIXED 2 @@ -41,4 +42,17 @@ #define MAP_HUGE_2GB HUGETLB_FLAG_ENCODE_2GB #define MAP_HUGE_16GB HUGETLB_FLAG_ENCODE_16GB +struct cachestat_range { + __u64 off; + __u64 len; +}; + +struct cachestat { + __u64 nr_cache; + __u64 nr_dirty; + __u64 nr_writeback; + __u64 nr_evicted; + __u64 nr_recently_evicted; +}; + #endif /* _UAPI_LINUX_MMAN_H */ diff --git a/tools/include/uapi/linux/mount.h b/tools/include/uapi/linux/mount.h index 4d93967f8aea..8eb0d7b758d2 100644 --- a/tools/include/uapi/linux/mount.h +++ b/tools/include/uapi/linux/mount.h @@ -74,7 +74,8 @@ #define MOVE_MOUNT_T_AUTOMOUNTS 0x00000020 /* Follow automounts on to path */ #define MOVE_MOUNT_T_EMPTY_PATH 0x00000040 /* Empty to path permitted */ #define MOVE_MOUNT_SET_GROUP 0x00000100 /* Set sharing group instead */ -#define MOVE_MOUNT__MASK 0x00000177 +#define MOVE_MOUNT_BENEATH 0x00000200 /* Mount beneath top mount */ +#define MOVE_MOUNT__MASK 0x00000377 /* * fsopen() flags. diff --git a/tools/include/uapi/linux/netdev.h b/tools/include/uapi/linux/netdev.h index 639524b59930..c1634b95c223 100644 --- a/tools/include/uapi/linux/netdev.h +++ b/tools/include/uapi/linux/netdev.h @@ -11,7 +11,7 @@ /** * enum netdev_xdp_act - * @NETDEV_XDP_ACT_BASIC: XDP feautues set supported by all drivers + * @NETDEV_XDP_ACT_BASIC: XDP features set supported by all drivers * (XDP_ABORTED, XDP_DROP, XDP_PASS, XDP_TX) * @NETDEV_XDP_ACT_REDIRECT: The netdev supports XDP_REDIRECT * @NETDEV_XDP_ACT_NDO_XMIT: This feature informs if netdev implements @@ -34,6 +34,7 @@ enum netdev_xdp_act { NETDEV_XDP_ACT_RX_SG = 32, NETDEV_XDP_ACT_NDO_XMIT_SG = 64, + /* private: */ NETDEV_XDP_ACT_MASK = 127, }; @@ -41,6 +42,7 @@ enum { NETDEV_A_DEV_IFINDEX = 1, NETDEV_A_DEV_PAD, NETDEV_A_DEV_XDP_FEATURES, + NETDEV_A_DEV_XDP_ZC_MAX_SEGS, __NETDEV_A_DEV_MAX, NETDEV_A_DEV_MAX = (__NETDEV_A_DEV_MAX - 1) diff --git a/tools/include/uapi/linux/prctl.h b/tools/include/uapi/linux/prctl.h index f23d9a16507f..3c36aeade991 100644 --- a/tools/include/uapi/linux/prctl.h +++ b/tools/include/uapi/linux/prctl.h @@ -294,4 +294,15 @@ struct prctl_mm_map { #define PR_SET_MEMORY_MERGE 67 #define PR_GET_MEMORY_MERGE 68 + +#define PR_RISCV_V_SET_CONTROL 69 +#define PR_RISCV_V_GET_CONTROL 70 +# define PR_RISCV_V_VSTATE_CTRL_DEFAULT 0 +# define PR_RISCV_V_VSTATE_CTRL_OFF 1 +# define PR_RISCV_V_VSTATE_CTRL_ON 2 +# define PR_RISCV_V_VSTATE_CTRL_INHERIT (1 << 4) +# define PR_RISCV_V_VSTATE_CTRL_CUR_MASK 0x3 +# define PR_RISCV_V_VSTATE_CTRL_NEXT_MASK 0xc +# define PR_RISCV_V_VSTATE_CTRL_MASK 0x1f + #endif /* _LINUX_PRCTL_H */ diff --git a/tools/include/uapi/linux/vhost.h b/tools/include/uapi/linux/vhost.h index 92e1b700b51c..f5c48b61ab62 100644 --- a/tools/include/uapi/linux/vhost.h +++ b/tools/include/uapi/linux/vhost.h @@ -45,6 +45,25 @@ #define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64) /* Specify an eventfd file descriptor to signal on log write. */ #define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int) +/* By default, a device gets one vhost_worker that its virtqueues share. This + * command allows the owner of the device to create an additional vhost_worker + * for the device. It can later be bound to 1 or more of its virtqueues using + * the VHOST_ATTACH_VRING_WORKER command. + * + * This must be called after VHOST_SET_OWNER and the caller must be the owner + * of the device. The new thread will inherit caller's cgroups and namespaces, + * and will share the caller's memory space. The new thread will also be + * counted against the caller's RLIMIT_NPROC value. + * + * The worker's ID used in other commands will be returned in + * vhost_worker_state. + */ +#define VHOST_NEW_WORKER _IOR(VHOST_VIRTIO, 0x8, struct vhost_worker_state) +/* Free a worker created with VHOST_NEW_WORKER if it's not attached to any + * virtqueue. If userspace is not able to call this for workers its created, + * the kernel will free all the device's workers when the device is closed. + */ +#define VHOST_FREE_WORKER _IOW(VHOST_VIRTIO, 0x9, struct vhost_worker_state) /* Ring setup. */ /* Set number of descriptors in ring. This parameter can not @@ -70,6 +89,18 @@ #define VHOST_VRING_BIG_ENDIAN 1 #define VHOST_SET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_state) #define VHOST_GET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state) +/* Attach a vhost_worker created with VHOST_NEW_WORKER to one of the device's + * virtqueues. + * + * This will replace the virtqueue's existing worker. If the replaced worker + * is no longer attached to any virtqueues, it can be freed with + * VHOST_FREE_WORKER. + */ +#define VHOST_ATTACH_VRING_WORKER _IOW(VHOST_VIRTIO, 0x15, \ + struct vhost_vring_worker) +/* Return the vring worker's ID */ +#define VHOST_GET_VRING_WORKER _IOWR(VHOST_VIRTIO, 0x16, \ + struct vhost_vring_worker) /* The following ioctls use eventfd file descriptors to signal and poll * for events. */ diff --git a/tools/include/uapi/sound/asound.h b/tools/include/uapi/sound/asound.h index 0aa955aa8246..f9939da41122 100644 --- a/tools/include/uapi/sound/asound.h +++ b/tools/include/uapi/sound/asound.h @@ -274,6 +274,7 @@ typedef int __bitwise snd_pcm_subformat_t; #define SNDRV_PCM_INFO_DOUBLE 0x00000004 /* Double buffering needed for PCM start/stop */ #define SNDRV_PCM_INFO_BATCH 0x00000010 /* double buffering */ #define SNDRV_PCM_INFO_SYNC_APPLPTR 0x00000020 /* need the explicit sync of appl_ptr update */ +#define SNDRV_PCM_INFO_PERFECT_DRAIN 0x00000040 /* silencing at the end of stream is not required */ #define SNDRV_PCM_INFO_INTERLEAVED 0x00000100 /* channels are interleaved */ #define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200 /* channels are not interleaved */ #define SNDRV_PCM_INFO_COMPLEX 0x00000400 /* complex frame organization (mmap only) */ @@ -383,6 +384,9 @@ typedef int snd_pcm_hw_param_t; #define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* avoid rate resampling */ #define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER (1<<1) /* export buffer */ #define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) /* disable period wakeups */ +#define SNDRV_PCM_HW_PARAMS_NO_DRAIN_SILENCE (1<<3) /* suppress drain with the filling + * of the silence samples + */ struct snd_interval { unsigned int min, max; @@ -708,7 +712,7 @@ enum { * Raw MIDI section - /dev/snd/midi?? */ -#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 2) +#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 4) enum { SNDRV_RAWMIDI_STREAM_OUTPUT = 0, @@ -719,6 +723,7 @@ enum { #define SNDRV_RAWMIDI_INFO_OUTPUT 0x00000001 #define SNDRV_RAWMIDI_INFO_INPUT 0x00000002 #define SNDRV_RAWMIDI_INFO_DUPLEX 0x00000004 +#define SNDRV_RAWMIDI_INFO_UMP 0x00000008 struct snd_rawmidi_info { unsigned int device; /* RO/WR (control): device number */ @@ -779,6 +784,72 @@ struct snd_rawmidi_status { }; #endif +/* UMP EP info flags */ +#define SNDRV_UMP_EP_INFO_STATIC_BLOCKS 0x01 + +/* UMP EP Protocol / JRTS capability bits */ +#define SNDRV_UMP_EP_INFO_PROTO_MIDI_MASK 0x0300 +#define SNDRV_UMP_EP_INFO_PROTO_MIDI1 0x0100 /* MIDI 1.0 */ +#define SNDRV_UMP_EP_INFO_PROTO_MIDI2 0x0200 /* MIDI 2.0 */ +#define SNDRV_UMP_EP_INFO_PROTO_JRTS_MASK 0x0003 +#define SNDRV_UMP_EP_INFO_PROTO_JRTS_TX 0x0001 /* JRTS Transmit */ +#define SNDRV_UMP_EP_INFO_PROTO_JRTS_RX 0x0002 /* JRTS Receive */ + +/* UMP Endpoint information */ +struct snd_ump_endpoint_info { + int card; /* card number */ + int device; /* device number */ + unsigned int flags; /* additional info */ + unsigned int protocol_caps; /* protocol capabilities */ + unsigned int protocol; /* current protocol */ + unsigned int num_blocks; /* # of function blocks */ + unsigned short version; /* UMP major/minor version */ + unsigned short family_id; /* MIDI device family ID */ + unsigned short model_id; /* MIDI family model ID */ + unsigned int manufacturer_id; /* MIDI manufacturer ID */ + unsigned char sw_revision[4]; /* software revision */ + unsigned short padding; + unsigned char name[128]; /* endpoint name string */ + unsigned char product_id[128]; /* unique product id string */ + unsigned char reserved[32]; +} __packed; + +/* UMP direction */ +#define SNDRV_UMP_DIR_INPUT 0x01 +#define SNDRV_UMP_DIR_OUTPUT 0x02 +#define SNDRV_UMP_DIR_BIDIRECTION 0x03 + +/* UMP block info flags */ +#define SNDRV_UMP_BLOCK_IS_MIDI1 (1U << 0) /* MIDI 1.0 port w/o restrict */ +#define SNDRV_UMP_BLOCK_IS_LOWSPEED (1U << 1) /* 31.25Kbps B/W MIDI1 port */ + +/* UMP block user-interface hint */ +#define SNDRV_UMP_BLOCK_UI_HINT_UNKNOWN 0x00 +#define SNDRV_UMP_BLOCK_UI_HINT_RECEIVER 0x01 +#define SNDRV_UMP_BLOCK_UI_HINT_SENDER 0x02 +#define SNDRV_UMP_BLOCK_UI_HINT_BOTH 0x03 + +/* UMP groups and blocks */ +#define SNDRV_UMP_MAX_GROUPS 16 +#define SNDRV_UMP_MAX_BLOCKS 32 + +/* UMP Block information */ +struct snd_ump_block_info { + int card; /* card number */ + int device; /* device number */ + unsigned char block_id; /* block ID (R/W) */ + unsigned char direction; /* UMP direction */ + unsigned char active; /* Activeness */ + unsigned char first_group; /* first group ID */ + unsigned char num_groups; /* number of groups */ + unsigned char midi_ci_version; /* MIDI-CI support version */ + unsigned char sysex8_streams; /* max number of sysex8 streams */ + unsigned char ui_hint; /* user interface hint */ + unsigned int flags; /* various info flags */ + unsigned char name[128]; /* block name string */ + unsigned char reserved[32]; +} __packed; + #define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int) #define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info) #define SNDRV_RAWMIDI_IOCTL_USER_PVERSION _IOW('W', 0x02, int) @@ -786,6 +857,9 @@ struct snd_rawmidi_status { #define SNDRV_RAWMIDI_IOCTL_STATUS _IOWR('W', 0x20, struct snd_rawmidi_status) #define SNDRV_RAWMIDI_IOCTL_DROP _IOW('W', 0x30, int) #define SNDRV_RAWMIDI_IOCTL_DRAIN _IOW('W', 0x31, int) +/* Additional ioctls for UMP rawmidi devices */ +#define SNDRV_UMP_IOCTL_ENDPOINT_INFO _IOR('W', 0x40, struct snd_ump_endpoint_info) +#define SNDRV_UMP_IOCTL_BLOCK_INFO _IOR('W', 0x41, struct snd_ump_block_info) /* * Timer section - /dev/snd/timer @@ -961,7 +1035,7 @@ struct snd_timer_tread { * * ****************************************************************************/ -#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 8) +#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 9) struct snd_ctl_card_info { int card; /* card number */ @@ -1122,6 +1196,9 @@ struct snd_ctl_tlv { #define SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE _IOWR('U', 0x40, int) #define SNDRV_CTL_IOCTL_RAWMIDI_INFO _IOWR('U', 0x41, struct snd_rawmidi_info) #define SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE _IOW('U', 0x42, int) +#define SNDRV_CTL_IOCTL_UMP_NEXT_DEVICE _IOWR('U', 0x43, int) +#define SNDRV_CTL_IOCTL_UMP_ENDPOINT_INFO _IOWR('U', 0x44, struct snd_ump_endpoint_info) +#define SNDRV_CTL_IOCTL_UMP_BLOCK_INFO _IOWR('U', 0x45, struct snd_ump_block_info) #define SNDRV_CTL_IOCTL_POWER _IOWR('U', 0xd0, int) #define SNDRV_CTL_IOCTL_POWER_STATE _IOR('U', 0xd1, int) |