Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'nolibc.2023.02.06a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu

Pull nolibc updates from Paul McKenney:

- Add s390 support

- Add support for the ARM Thumb1 instruction set

- Fix O_* flags definitions for open() and fcntl()

- Make errno a weak symbol instead of a static variable

- Export environ as a weak symbol

- Export _auxv as a weak symbol for auxilliary vector retrieval

- Implement getauxval() and getpagesize()

- Further improve self tests, including permitting userland testing of
the nolibc library

* tag 'nolibc.2023.02.06a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu: (28 commits)
selftests/nolibc: Add a "run-user" target to test the program in user land
selftests/nolibc: Support "x86_64" for arch name
selftests/nolibc: Add `getpagesize(2)` selftest
nolibc/sys: Implement `getpagesize(2)` function
nolibc/stdlib: Implement `getauxval(3)` function
tools/nolibc: add auxiliary vector retrieval for s390
tools/nolibc: add auxiliary vector retrieval for mips
tools/nolibc: add auxiliary vector retrieval for riscv
tools/nolibc: add auxiliary vector retrieval for arm
tools/nolibc: add auxiliary vector retrieval for arm64
tools/nolibc: add auxiliary vector retrieval for x86_64
tools/nolibc: add auxiliary vector retrieval for i386
tools/nolibc: export environ as a weak symbol on s390
tools/nolibc: export environ as a weak symbol on riscv
tools/nolibc: export environ as a weak symbol on mips
tools/nolibc: export environ as a weak symbol on arm
tools/nolibc: export environ as a weak symbol on arm64
tools/nolibc: export environ as a weak symbol on i386
tools/nolibc: export environ as a weak symbol on x86_64
tools/nolibc: make errno a weak symbol instead of a static one
...

+579 -202
+26 -26
tools/include/nolibc/arch-aarch64.h
··· 7 7 #ifndef _NOLIBC_ARCH_AARCH64_H 8 8 #define _NOLIBC_ARCH_AARCH64_H 9 9 10 - /* O_* macros for fcntl/open are architecture-specific */ 11 - #define O_RDONLY 0 12 - #define O_WRONLY 1 13 - #define O_RDWR 2 14 - #define O_CREAT 0x40 15 - #define O_EXCL 0x80 16 - #define O_NOCTTY 0x100 17 - #define O_TRUNC 0x200 18 - #define O_APPEND 0x400 19 - #define O_NONBLOCK 0x800 20 - #define O_DIRECTORY 0x4000 21 - 22 10 /* The struct returned by the newfstatat() syscall. Differs slightly from the 23 11 * x86_64's stat one by field ordering, so be careful. 24 12 */ ··· 169 181 _arg1; \ 170 182 }) 171 183 172 - /* startup code */ 173 - __asm__ (".section .text\n" 174 - ".weak _start\n" 175 - "_start:\n" 176 - "ldr x0, [sp]\n" // argc (x0) was in the stack 177 - "add x1, sp, 8\n" // argv (x1) = sp 178 - "lsl x2, x0, 3\n" // envp (x2) = 8*argc ... 179 - "add x2, x2, 8\n" // + 8 (skip null) 180 - "add x2, x2, x1\n" // + argv 181 - "and sp, x1, -16\n" // sp must be 16-byte aligned in the callee 182 - "bl main\n" // main() returns the status code, we'll exit with it. 183 - "mov x8, 93\n" // NR_exit == 93 184 - "svc #0\n" 185 - ""); 184 + char **environ __attribute__((weak)); 185 + const unsigned long *_auxv __attribute__((weak)); 186 186 187 + /* startup code */ 188 + void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void) 189 + { 190 + __asm__ volatile ( 191 + "ldr x0, [sp]\n" // argc (x0) was in the stack 192 + "add x1, sp, 8\n" // argv (x1) = sp 193 + "lsl x2, x0, 3\n" // envp (x2) = 8*argc ... 194 + "add x2, x2, 8\n" // + 8 (skip null) 195 + "add x2, x2, x1\n" // + argv 196 + "adrp x3, environ\n" // x3 = &environ (high bits) 197 + "str x2, [x3, #:lo12:environ]\n" // store envp into environ 198 + "mov x4, x2\n" // search for auxv (follows NULL after last env) 199 + "0:\n" 200 + "ldr x5, [x4], 8\n" // x5 = *x4; x4 += 8 201 + "cbnz x5, 0b\n" // and stop at NULL after last env 202 + "adrp x3, _auxv\n" // x3 = &_auxv (high bits) 203 + "str x4, [x3, #:lo12:_auxv]\n" // store x4 into _auxv 204 + "and sp, x1, -16\n" // sp must be 16-byte aligned in the callee 205 + "bl main\n" // main() returns the status code, we'll exit with it. 206 + "mov x8, 93\n" // NR_exit == 93 207 + "svc #0\n" 208 + ); 209 + __builtin_unreachable(); 210 + } 187 211 #endif // _NOLIBC_ARCH_AARCH64_H
+88 -50
tools/include/nolibc/arch-arm.h
··· 7 7 #ifndef _NOLIBC_ARCH_ARM_H 8 8 #define _NOLIBC_ARCH_ARM_H 9 9 10 - /* O_* macros for fcntl/open are architecture-specific */ 11 - #define O_RDONLY 0 12 - #define O_WRONLY 1 13 - #define O_RDWR 2 14 - #define O_CREAT 0x40 15 - #define O_EXCL 0x80 16 - #define O_NOCTTY 0x100 17 - #define O_TRUNC 0x200 18 - #define O_APPEND 0x400 19 - #define O_NONBLOCK 0x800 20 - #define O_DIRECTORY 0x4000 21 - 22 10 /* The struct returned by the stat() syscall, 32-bit only, the syscall returns 23 11 * exactly 56 bytes (stops before the unused array). In big endian, the format 24 12 * differs as devices are returned as short only. ··· 58 70 * don't have to experience issues with register constraints. 59 71 * - the syscall number is always specified last in order to allow to force 60 72 * some registers before (gcc refuses a %-register at the last position). 73 + * - in thumb mode without -fomit-frame-pointer, r7 is also used to store the 74 + * frame pointer, and we cannot directly assign it as a register variable, 75 + * nor can we clobber it. Instead we assign the r6 register and swap it 76 + * with r7 before calling svc, and r6 is marked as clobbered. 77 + * We're just using any regular register which we assign to r7 after saving 78 + * it. 61 79 * 62 80 * Also, ARM supports the old_select syscall if newselect is not available 63 81 */ 64 82 #define __ARCH_WANT_SYS_OLD_SELECT 65 83 84 + #if (defined(__THUMBEB__) || defined(__THUMBEL__)) && \ 85 + !defined(NOLIBC_OMIT_FRAME_POINTER) 86 + /* swap r6,r7 needed in Thumb mode since we can't use nor clobber r7 */ 87 + #define _NOLIBC_SYSCALL_REG "r6" 88 + #define _NOLIBC_THUMB_SET_R7 "eor r7, r6\neor r6, r7\neor r7, r6\n" 89 + #define _NOLIBC_THUMB_RESTORE_R7 "mov r7, r6\n" 90 + 91 + #else /* we're in ARM mode */ 92 + /* in Arm mode we can directly use r7 */ 93 + #define _NOLIBC_SYSCALL_REG "r7" 94 + #define _NOLIBC_THUMB_SET_R7 "" 95 + #define _NOLIBC_THUMB_RESTORE_R7 "" 96 + 97 + #endif /* end THUMB */ 98 + 66 99 #define my_syscall0(num) \ 67 100 ({ \ 68 - register long _num __asm__ ("r7") = (num); \ 101 + register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ 69 102 register long _arg1 __asm__ ("r0"); \ 70 103 \ 71 104 __asm__ volatile ( \ 105 + _NOLIBC_THUMB_SET_R7 \ 72 106 "svc #0\n" \ 73 - : "=r"(_arg1) \ 74 - : "r"(_num) \ 107 + _NOLIBC_THUMB_RESTORE_R7 \ 108 + : "=r"(_arg1), "=r"(_num) \ 109 + : "r"(_arg1), \ 110 + "r"(_num) \ 75 111 : "memory", "cc", "lr" \ 76 112 ); \ 77 113 _arg1; \ ··· 103 91 104 92 #define my_syscall1(num, arg1) \ 105 93 ({ \ 106 - register long _num __asm__ ("r7") = (num); \ 94 + register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ 107 95 register long _arg1 __asm__ ("r0") = (long)(arg1); \ 108 96 \ 109 97 __asm__ volatile ( \ 98 + _NOLIBC_THUMB_SET_R7 \ 110 99 "svc #0\n" \ 111 - : "=r"(_arg1) \ 100 + _NOLIBC_THUMB_RESTORE_R7 \ 101 + : "=r"(_arg1), "=r" (_num) \ 112 102 : "r"(_arg1), \ 113 103 "r"(_num) \ 114 104 : "memory", "cc", "lr" \ ··· 120 106 121 107 #define my_syscall2(num, arg1, arg2) \ 122 108 ({ \ 123 - register long _num __asm__ ("r7") = (num); \ 109 + register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ 124 110 register long _arg1 __asm__ ("r0") = (long)(arg1); \ 125 111 register long _arg2 __asm__ ("r1") = (long)(arg2); \ 126 112 \ 127 113 __asm__ volatile ( \ 114 + _NOLIBC_THUMB_SET_R7 \ 128 115 "svc #0\n" \ 129 - : "=r"(_arg1) \ 116 + _NOLIBC_THUMB_RESTORE_R7 \ 117 + : "=r"(_arg1), "=r" (_num) \ 130 118 : "r"(_arg1), "r"(_arg2), \ 131 119 "r"(_num) \ 132 120 : "memory", "cc", "lr" \ ··· 138 122 139 123 #define my_syscall3(num, arg1, arg2, arg3) \ 140 124 ({ \ 141 - register long _num __asm__ ("r7") = (num); \ 125 + register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ 142 126 register long _arg1 __asm__ ("r0") = (long)(arg1); \ 143 127 register long _arg2 __asm__ ("r1") = (long)(arg2); \ 144 128 register long _arg3 __asm__ ("r2") = (long)(arg3); \ 145 129 \ 146 130 __asm__ volatile ( \ 131 + _NOLIBC_THUMB_SET_R7 \ 147 132 "svc #0\n" \ 148 - : "=r"(_arg1) \ 133 + _NOLIBC_THUMB_RESTORE_R7 \ 134 + : "=r"(_arg1), "=r" (_num) \ 149 135 : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ 150 136 "r"(_num) \ 151 137 : "memory", "cc", "lr" \ ··· 157 139 158 140 #define my_syscall4(num, arg1, arg2, arg3, arg4) \ 159 141 ({ \ 160 - register long _num __asm__ ("r7") = (num); \ 142 + register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ 161 143 register long _arg1 __asm__ ("r0") = (long)(arg1); \ 162 144 register long _arg2 __asm__ ("r1") = (long)(arg2); \ 163 145 register long _arg3 __asm__ ("r2") = (long)(arg3); \ 164 146 register long _arg4 __asm__ ("r3") = (long)(arg4); \ 165 147 \ 166 148 __asm__ volatile ( \ 149 + _NOLIBC_THUMB_SET_R7 \ 167 150 "svc #0\n" \ 168 - : "=r"(_arg1) \ 151 + _NOLIBC_THUMB_RESTORE_R7 \ 152 + : "=r"(_arg1), "=r" (_num) \ 169 153 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ 170 154 "r"(_num) \ 171 155 : "memory", "cc", "lr" \ ··· 177 157 178 158 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ 179 159 ({ \ 180 - register long _num __asm__ ("r7") = (num); \ 160 + register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \ 181 161 register long _arg1 __asm__ ("r0") = (long)(arg1); \ 182 162 register long _arg2 __asm__ ("r1") = (long)(arg2); \ 183 163 register long _arg3 __asm__ ("r2") = (long)(arg3); \ ··· 185 165 register long _arg5 __asm__ ("r4") = (long)(arg5); \ 186 166 \ 187 167 __asm__ volatile ( \ 168 + _NOLIBC_THUMB_SET_R7 \ 188 169 "svc #0\n" \ 189 - : "=r" (_arg1) \ 170 + _NOLIBC_THUMB_RESTORE_R7 \ 171 + : "=r"(_arg1), "=r" (_num) \ 190 172 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ 191 173 "r"(_num) \ 192 174 : "memory", "cc", "lr" \ ··· 196 174 _arg1; \ 197 175 }) 198 176 177 + char **environ __attribute__((weak)); 178 + const unsigned long *_auxv __attribute__((weak)); 179 + 199 180 /* startup code */ 200 - __asm__ (".section .text\n" 201 - ".weak _start\n" 202 - "_start:\n" 203 - #if defined(__THUMBEB__) || defined(__THUMBEL__) 204 - /* We enter here in 32-bit mode but if some previous functions were in 205 - * 16-bit mode, the assembler cannot know, so we need to tell it we're in 206 - * 32-bit now, then switch to 16-bit (is there a better way to do it than 207 - * adding 1 by hand ?) and tell the asm we're now in 16-bit mode so that 208 - * it generates correct instructions. Note that we do not support thumb1. 209 - */ 210 - ".code 32\n" 211 - "add r0, pc, #1\n" 212 - "bx r0\n" 213 - ".code 16\n" 214 - #endif 215 - "pop {%r0}\n" // argc was in the stack 216 - "mov %r1, %sp\n" // argv = sp 217 - "add %r2, %r1, %r0, lsl #2\n" // envp = argv + 4*argc ... 218 - "add %r2, %r2, $4\n" // ... + 4 219 - "and %r3, %r1, $-8\n" // AAPCS : sp must be 8-byte aligned in the 220 - "mov %sp, %r3\n" // callee, an bl doesn't push (lr=pc) 221 - "bl main\n" // main() returns the status code, we'll exit with it. 222 - "movs r7, $1\n" // NR_exit == 1 223 - "svc $0x00\n" 224 - ""); 181 + void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void) 182 + { 183 + __asm__ volatile ( 184 + "pop {%r0}\n" // argc was in the stack 185 + "mov %r1, %sp\n" // argv = sp 186 + 187 + "add %r2, %r0, $1\n" // envp = (argc + 1) ... 188 + "lsl %r2, %r2, $2\n" // * 4 ... 189 + "add %r2, %r2, %r1\n" // + argv 190 + "ldr %r3, 1f\n" // r3 = &environ (see below) 191 + "str %r2, [r3]\n" // store envp into environ 192 + 193 + "mov r4, r2\n" // search for auxv (follows NULL after last env) 194 + "0:\n" 195 + "mov r5, r4\n" // r5 = r4 196 + "add r4, r4, #4\n" // r4 += 4 197 + "ldr r5,[r5]\n" // r5 = *r5 = *(r4-4) 198 + "cmp r5, #0\n" // and stop at NULL after last env 199 + "bne 0b\n" 200 + "ldr %r3, 2f\n" // r3 = &_auxv (low bits) 201 + "str r4, [r3]\n" // store r4 into _auxv 202 + 203 + "mov %r3, $8\n" // AAPCS : sp must be 8-byte aligned in the 204 + "neg %r3, %r3\n" // callee, and bl doesn't push (lr=pc) 205 + "and %r3, %r3, %r1\n" // so we do sp = r1(=sp) & r3(=-8); 206 + "mov %sp, %r3\n" // 207 + 208 + "bl main\n" // main() returns the status code, we'll exit with it. 209 + "movs r7, $1\n" // NR_exit == 1 210 + "svc $0x00\n" 211 + ".align 2\n" // below are the pointers to a few variables 212 + "1:\n" 213 + ".word environ\n" 214 + "2:\n" 215 + ".word _auxv\n" 216 + ); 217 + __builtin_unreachable(); 218 + } 225 219 226 220 #endif // _NOLIBC_ARCH_ARM_H
+30 -30
tools/include/nolibc/arch-i386.h
··· 7 7 #ifndef _NOLIBC_ARCH_I386_H 8 8 #define _NOLIBC_ARCH_I386_H 9 9 10 - /* O_* macros for fcntl/open are architecture-specific */ 11 - #define O_RDONLY 0 12 - #define O_WRONLY 1 13 - #define O_RDWR 2 14 - #define O_CREAT 0x40 15 - #define O_EXCL 0x80 16 - #define O_NOCTTY 0x100 17 - #define O_TRUNC 0x200 18 - #define O_APPEND 0x400 19 - #define O_NONBLOCK 0x800 20 - #define O_DIRECTORY 0x10000 21 - 22 10 /* The struct returned by the stat() syscall, 32-bit only, the syscall returns 23 11 * exactly 56 bytes (stops before the unused array). 24 12 */ ··· 178 190 _eax; \ 179 191 }) 180 192 193 + char **environ __attribute__((weak)); 194 + const unsigned long *_auxv __attribute__((weak)); 195 + 181 196 /* startup code */ 182 197 /* 183 198 * i386 System V ABI mandates: ··· 188 197 * 2) The deepest stack frame should be set to zero 189 198 * 190 199 */ 191 - __asm__ (".section .text\n" 192 - ".weak _start\n" 193 - "_start:\n" 194 - "pop %eax\n" // argc (first arg, %eax) 195 - "mov %esp, %ebx\n" // argv[] (second arg, %ebx) 196 - "lea 4(%ebx,%eax,4),%ecx\n" // then a NULL then envp (third arg, %ecx) 197 - "xor %ebp, %ebp\n" // zero the stack frame 198 - "and $-16, %esp\n" // x86 ABI : esp must be 16-byte aligned before 199 - "sub $4, %esp\n" // the call instruction (args are aligned) 200 - "push %ecx\n" // push all registers on the stack so that we 201 - "push %ebx\n" // support both regparm and plain stack modes 202 - "push %eax\n" 203 - "call main\n" // main() returns the status code in %eax 204 - "mov %eax, %ebx\n" // retrieve exit code (32-bit int) 205 - "movl $1, %eax\n" // NR_exit == 1 206 - "int $0x80\n" // exit now 207 - "hlt\n" // ensure it does not 208 - ""); 200 + void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void) 201 + { 202 + __asm__ volatile ( 203 + "pop %eax\n" // argc (first arg, %eax) 204 + "mov %esp, %ebx\n" // argv[] (second arg, %ebx) 205 + "lea 4(%ebx,%eax,4),%ecx\n" // then a NULL then envp (third arg, %ecx) 206 + "mov %ecx, environ\n" // save environ 207 + "xor %ebp, %ebp\n" // zero the stack frame 208 + "mov %ecx, %edx\n" // search for auxv (follows NULL after last env) 209 + "0:\n" 210 + "add $4, %edx\n" // search for auxv using edx, it follows the 211 + "cmp -4(%edx), %ebp\n" // ... NULL after last env (ebp is zero here) 212 + "jnz 0b\n" 213 + "mov %edx, _auxv\n" // save it into _auxv 214 + "and $-16, %esp\n" // x86 ABI : esp must be 16-byte aligned before 215 + "sub $4, %esp\n" // the call instruction (args are aligned) 216 + "push %ecx\n" // push all registers on the stack so that we 217 + "push %ebx\n" // support both regparm and plain stack modes 218 + "push %eax\n" 219 + "call main\n" // main() returns the status code in %eax 220 + "mov %eax, %ebx\n" // retrieve exit code (32-bit int) 221 + "movl $1, %eax\n" // NR_exit == 1 222 + "int $0x80\n" // exit now 223 + "hlt\n" // ensure it does not 224 + ); 225 + __builtin_unreachable(); 226 + } 209 227 210 228 #endif // _NOLIBC_ARCH_I386_H
+43 -36
tools/include/nolibc/arch-mips.h
··· 7 7 #ifndef _NOLIBC_ARCH_MIPS_H 8 8 #define _NOLIBC_ARCH_MIPS_H 9 9 10 - /* O_* macros for fcntl/open are architecture-specific */ 11 - #define O_RDONLY 0 12 - #define O_WRONLY 1 13 - #define O_RDWR 2 14 - #define O_APPEND 0x0008 15 - #define O_NONBLOCK 0x0080 16 - #define O_CREAT 0x0100 17 - #define O_TRUNC 0x0200 18 - #define O_EXCL 0x0400 19 - #define O_NOCTTY 0x0800 20 - #define O_DIRECTORY 0x10000 21 - 22 10 /* The struct returned by the stat() syscall. 88 bytes are returned by the 23 11 * syscall. 24 12 */ ··· 176 188 _arg4 ? -_num : _num; \ 177 189 }) 178 190 191 + char **environ __attribute__((weak)); 192 + const unsigned long *_auxv __attribute__((weak)); 193 + 179 194 /* startup code, note that it's called __start on MIPS */ 180 - __asm__ (".section .text\n" 181 - ".weak __start\n" 182 - ".set nomips16\n" 183 - ".set push\n" 184 - ".set noreorder\n" 185 - ".option pic0\n" 186 - ".ent __start\n" 187 - "__start:\n" 188 - "lw $a0,($sp)\n" // argc was in the stack 189 - "addiu $a1, $sp, 4\n" // argv = sp + 4 190 - "sll $a2, $a0, 2\n" // a2 = argc * 4 191 - "add $a2, $a2, $a1\n" // envp = argv + 4*argc ... 192 - "addiu $a2, $a2, 4\n" // ... + 4 193 - "li $t0, -8\n" 194 - "and $sp, $sp, $t0\n" // sp must be 8-byte aligned 195 - "addiu $sp,$sp,-16\n" // the callee expects to save a0..a3 there! 196 - "jal main\n" // main() returns the status code, we'll exit with it. 197 - "nop\n" // delayed slot 198 - "move $a0, $v0\n" // retrieve 32-bit exit code from v0 199 - "li $v0, 4001\n" // NR_exit == 4001 200 - "syscall\n" 201 - ".end __start\n" 202 - ".set pop\n" 203 - ""); 195 + void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __start(void) 196 + { 197 + __asm__ volatile ( 198 + //".set nomips16\n" 199 + ".set push\n" 200 + ".set noreorder\n" 201 + ".option pic0\n" 202 + //".ent __start\n" 203 + //"__start:\n" 204 + "lw $a0,($sp)\n" // argc was in the stack 205 + "addiu $a1, $sp, 4\n" // argv = sp + 4 206 + "sll $a2, $a0, 2\n" // a2 = argc * 4 207 + "add $a2, $a2, $a1\n" // envp = argv + 4*argc ... 208 + "addiu $a2, $a2, 4\n" // ... + 4 209 + "lui $a3, %hi(environ)\n" // load environ into a3 (hi) 210 + "addiu $a3, %lo(environ)\n" // load environ into a3 (lo) 211 + "sw $a2,($a3)\n" // store envp(a2) into environ 212 + 213 + "move $t0, $a2\n" // iterate t0 over envp, look for NULL 214 + "0:" // do { 215 + "lw $a3, ($t0)\n" // a3=*(t0); 216 + "bne $a3, $0, 0b\n" // } while (a3); 217 + "addiu $t0, $t0, 4\n" // delayed slot: t0+=4; 218 + "lui $a3, %hi(_auxv)\n" // load _auxv into a3 (hi) 219 + "addiu $a3, %lo(_auxv)\n" // load _auxv into a3 (lo) 220 + "sw $t0, ($a3)\n" // store t0 into _auxv 221 + 222 + "li $t0, -8\n" 223 + "and $sp, $sp, $t0\n" // sp must be 8-byte aligned 224 + "addiu $sp,$sp,-16\n" // the callee expects to save a0..a3 there! 225 + "jal main\n" // main() returns the status code, we'll exit with it. 226 + "nop\n" // delayed slot 227 + "move $a0, $v0\n" // retrieve 32-bit exit code from v0 228 + "li $v0, 4001\n" // NR_exit == 4001 229 + "syscall\n" 230 + //".end __start\n" 231 + ".set pop\n" 232 + ); 233 + __builtin_unreachable(); 234 + } 204 235 205 236 #endif // _NOLIBC_ARCH_MIPS_H
+33 -29
tools/include/nolibc/arch-riscv.h
··· 7 7 #ifndef _NOLIBC_ARCH_RISCV_H 8 8 #define _NOLIBC_ARCH_RISCV_H 9 9 10 - /* O_* macros for fcntl/open are architecture-specific */ 11 - #define O_RDONLY 0 12 - #define O_WRONLY 1 13 - #define O_RDWR 2 14 - #define O_CREAT 0x40 15 - #define O_EXCL 0x80 16 - #define O_NOCTTY 0x100 17 - #define O_TRUNC 0x200 18 - #define O_APPEND 0x400 19 - #define O_NONBLOCK 0x800 20 - #define O_DIRECTORY 0x10000 21 - 22 10 struct sys_stat_struct { 23 11 unsigned long st_dev; /* Device. */ 24 12 unsigned long st_ino; /* File serial number. */ ··· 170 182 _arg1; \ 171 183 }) 172 184 185 + char **environ __attribute__((weak)); 186 + const unsigned long *_auxv __attribute__((weak)); 187 + 173 188 /* startup code */ 174 - __asm__ (".section .text\n" 175 - ".weak _start\n" 176 - "_start:\n" 177 - ".option push\n" 178 - ".option norelax\n" 179 - "lla gp, __global_pointer$\n" 180 - ".option pop\n" 181 - "lw a0, 0(sp)\n" // argc (a0) was in the stack 182 - "add a1, sp, "SZREG"\n" // argv (a1) = sp 183 - "slli a2, a0, "PTRLOG"\n" // envp (a2) = SZREG*argc ... 184 - "add a2, a2, "SZREG"\n" // + SZREG (skip null) 185 - "add a2,a2,a1\n" // + argv 186 - "andi sp,a1,-16\n" // sp must be 16-byte aligned 187 - "call main\n" // main() returns the status code, we'll exit with it. 188 - "li a7, 93\n" // NR_exit == 93 189 - "ecall\n" 190 - ""); 189 + void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void) 190 + { 191 + __asm__ volatile ( 192 + ".option push\n" 193 + ".option norelax\n" 194 + "lla gp, __global_pointer$\n" 195 + ".option pop\n" 196 + "lw a0, 0(sp)\n" // argc (a0) was in the stack 197 + "add a1, sp, "SZREG"\n" // argv (a1) = sp 198 + "slli a2, a0, "PTRLOG"\n" // envp (a2) = SZREG*argc ... 199 + "add a2, a2, "SZREG"\n" // + SZREG (skip null) 200 + "add a2,a2,a1\n" // + argv 201 + 202 + "add a3, a2, zero\n" // iterate a3 over envp to find auxv (after NULL) 203 + "0:\n" // do { 204 + "ld a4, 0(a3)\n" // a4 = *a3; 205 + "add a3, a3, "SZREG"\n" // a3 += sizeof(void*); 206 + "bne a4, zero, 0b\n" // } while (a4); 207 + "lui a4, %hi(_auxv)\n" // a4 = &_auxv (high bits) 208 + "sd a3, %lo(_auxv)(a4)\n" // store a3 into _auxv 209 + 210 + "lui a3, %hi(environ)\n" // a3 = &environ (high bits) 211 + "sd a2,%lo(environ)(a3)\n" // store envp(a2) into environ 212 + "andi sp,a1,-16\n" // sp must be 16-byte aligned 213 + "call main\n" // main() returns the status code, we'll exit with it. 214 + "li a7, 93\n" // NR_exit == 93 215 + "ecall\n" 216 + ); 217 + __builtin_unreachable(); 218 + } 191 219 192 220 #endif // _NOLIBC_ARCH_RISCV_H
+226
tools/include/nolibc/arch-s390.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * s390 specific definitions for NOLIBC 4 + */ 5 + 6 + #ifndef _NOLIBC_ARCH_S390_H 7 + #define _NOLIBC_ARCH_S390_H 8 + #include <asm/unistd.h> 9 + 10 + /* The struct returned by the stat() syscall, equivalent to stat64(). The 11 + * syscall returns 116 bytes and stops in the middle of __unused. 12 + */ 13 + 14 + struct sys_stat_struct { 15 + unsigned long st_dev; 16 + unsigned long st_ino; 17 + unsigned long st_nlink; 18 + unsigned int st_mode; 19 + unsigned int st_uid; 20 + unsigned int st_gid; 21 + unsigned int __pad1; 22 + unsigned long st_rdev; 23 + unsigned long st_size; 24 + unsigned long st_atime; 25 + unsigned long st_atime_nsec; 26 + unsigned long st_mtime; 27 + unsigned long st_mtime_nsec; 28 + unsigned long st_ctime; 29 + unsigned long st_ctime_nsec; 30 + unsigned long st_blksize; 31 + long st_blocks; 32 + unsigned long __unused[3]; 33 + }; 34 + 35 + /* Syscalls for s390: 36 + * - registers are 64-bit 37 + * - syscall number is passed in r1 38 + * - arguments are in r2-r7 39 + * - the system call is performed by calling the svc instruction 40 + * - syscall return value is in r2 41 + * - r1 and r2 are clobbered, others are preserved. 42 + * 43 + * Link s390 ABI: https://github.com/IBM/s390x-abi 44 + * 45 + */ 46 + 47 + #define my_syscall0(num) \ 48 + ({ \ 49 + register long _num __asm__ ("1") = (num); \ 50 + register long _rc __asm__ ("2"); \ 51 + \ 52 + __asm__ volatile ( \ 53 + "svc 0\n" \ 54 + : "=d"(_rc) \ 55 + : "d"(_num) \ 56 + : "memory", "cc" \ 57 + ); \ 58 + _rc; \ 59 + }) 60 + 61 + #define my_syscall1(num, arg1) \ 62 + ({ \ 63 + register long _num __asm__ ("1") = (num); \ 64 + register long _arg1 __asm__ ("2") = (long)(arg1); \ 65 + \ 66 + __asm__ volatile ( \ 67 + "svc 0\n" \ 68 + : "+d"(_arg1) \ 69 + : "d"(_num) \ 70 + : "memory", "cc" \ 71 + ); \ 72 + _arg1; \ 73 + }) 74 + 75 + #define my_syscall2(num, arg1, arg2) \ 76 + ({ \ 77 + register long _num __asm__ ("1") = (num); \ 78 + register long _arg1 __asm__ ("2") = (long)(arg1); \ 79 + register long _arg2 __asm__ ("3") = (long)(arg2); \ 80 + \ 81 + __asm__ volatile ( \ 82 + "svc 0\n" \ 83 + : "+d"(_arg1) \ 84 + : "d"(_arg2), "d"(_num) \ 85 + : "memory", "cc" \ 86 + ); \ 87 + _arg1; \ 88 + }) 89 + 90 + #define my_syscall3(num, arg1, arg2, arg3) \ 91 + ({ \ 92 + register long _num __asm__ ("1") = (num); \ 93 + register long _arg1 __asm__ ("2") = (long)(arg1); \ 94 + register long _arg2 __asm__ ("3") = (long)(arg2); \ 95 + register long _arg3 __asm__ ("4") = (long)(arg3); \ 96 + \ 97 + __asm__ volatile ( \ 98 + "svc 0\n" \ 99 + : "+d"(_arg1) \ 100 + : "d"(_arg2), "d"(_arg3), "d"(_num) \ 101 + : "memory", "cc" \ 102 + ); \ 103 + _arg1; \ 104 + }) 105 + 106 + #define my_syscall4(num, arg1, arg2, arg3, arg4) \ 107 + ({ \ 108 + register long _num __asm__ ("1") = (num); \ 109 + register long _arg1 __asm__ ("2") = (long)(arg1); \ 110 + register long _arg2 __asm__ ("3") = (long)(arg2); \ 111 + register long _arg3 __asm__ ("4") = (long)(arg3); \ 112 + register long _arg4 __asm__ ("5") = (long)(arg4); \ 113 + \ 114 + __asm__ volatile ( \ 115 + "svc 0\n" \ 116 + : "+d"(_arg1) \ 117 + : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_num) \ 118 + : "memory", "cc" \ 119 + ); \ 120 + _arg1; \ 121 + }) 122 + 123 + #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ 124 + ({ \ 125 + register long _num __asm__ ("1") = (num); \ 126 + register long _arg1 __asm__ ("2") = (long)(arg1); \ 127 + register long _arg2 __asm__ ("3") = (long)(arg2); \ 128 + register long _arg3 __asm__ ("4") = (long)(arg3); \ 129 + register long _arg4 __asm__ ("5") = (long)(arg4); \ 130 + register long _arg5 __asm__ ("6") = (long)(arg5); \ 131 + \ 132 + __asm__ volatile ( \ 133 + "svc 0\n" \ 134 + : "+d"(_arg1) \ 135 + : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \ 136 + "d"(_num) \ 137 + : "memory", "cc" \ 138 + ); \ 139 + _arg1; \ 140 + }) 141 + 142 + #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ 143 + ({ \ 144 + register long _num __asm__ ("1") = (num); \ 145 + register long _arg1 __asm__ ("2") = (long)(arg1); \ 146 + register long _arg2 __asm__ ("3") = (long)(arg2); \ 147 + register long _arg3 __asm__ ("4") = (long)(arg3); \ 148 + register long _arg4 __asm__ ("5") = (long)(arg4); \ 149 + register long _arg5 __asm__ ("6") = (long)(arg5); \ 150 + register long _arg6 __asm__ ("7") = (long)(arg6); \ 151 + \ 152 + __asm__ volatile ( \ 153 + "svc 0\n" \ 154 + : "+d"(_arg1) \ 155 + : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \ 156 + "d"(_arg6), "d"(_num) \ 157 + : "memory", "cc" \ 158 + ); \ 159 + _arg1; \ 160 + }) 161 + 162 + char **environ __attribute__((weak)); 163 + const unsigned long *_auxv __attribute__((weak)); 164 + 165 + /* startup code */ 166 + void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void) 167 + { 168 + __asm__ volatile ( 169 + "lg %r2,0(%r15)\n" /* argument count */ 170 + "la %r3,8(%r15)\n" /* argument pointers */ 171 + 172 + "xgr %r0,%r0\n" /* r0 will be our NULL value */ 173 + /* search for envp */ 174 + "lgr %r4,%r3\n" /* start at argv */ 175 + "0:\n" 176 + "clg %r0,0(%r4)\n" /* entry zero? */ 177 + "la %r4,8(%r4)\n" /* advance pointer */ 178 + "jnz 0b\n" /* no -> test next pointer */ 179 + /* yes -> r4 now contains start of envp */ 180 + "larl %r1,environ\n" 181 + "stg %r4,0(%r1)\n" 182 + 183 + /* search for auxv */ 184 + "lgr %r5,%r4\n" /* start at envp */ 185 + "1:\n" 186 + "clg %r0,0(%r5)\n" /* entry zero? */ 187 + "la %r5,8(%r5)\n" /* advance pointer */ 188 + "jnz 1b\n" /* no -> test next pointer */ 189 + "larl %r1,_auxv\n" /* yes -> store value in _auxv */ 190 + "stg %r5,0(%r1)\n" 191 + 192 + "aghi %r15,-160\n" /* allocate new stackframe */ 193 + "xc 0(8,%r15),0(%r15)\n" /* clear backchain */ 194 + "brasl %r14,main\n" /* ret value of main is arg to exit */ 195 + "lghi %r1,1\n" /* __NR_exit */ 196 + "svc 0\n" 197 + ); 198 + __builtin_unreachable(); 199 + } 200 + 201 + struct s390_mmap_arg_struct { 202 + unsigned long addr; 203 + unsigned long len; 204 + unsigned long prot; 205 + unsigned long flags; 206 + unsigned long fd; 207 + unsigned long offset; 208 + }; 209 + 210 + static __attribute__((unused)) 211 + void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, 212 + off_t offset) 213 + { 214 + struct s390_mmap_arg_struct args = { 215 + .addr = (unsigned long)addr, 216 + .len = (unsigned long)length, 217 + .prot = prot, 218 + .flags = flags, 219 + .fd = fd, 220 + .offset = (unsigned long)offset 221 + }; 222 + 223 + return (void *)my_syscall1(__NR_mmap, &args); 224 + } 225 + #define sys_mmap sys_mmap 226 + #endif // _NOLIBC_ARCH_S390_H
+26 -26
tools/include/nolibc/arch-x86_64.h
··· 7 7 #ifndef _NOLIBC_ARCH_X86_64_H 8 8 #define _NOLIBC_ARCH_X86_64_H 9 9 10 - /* O_* macros for fcntl/open are architecture-specific */ 11 - #define O_RDONLY 0 12 - #define O_WRONLY 1 13 - #define O_RDWR 2 14 - #define O_CREAT 0x40 15 - #define O_EXCL 0x80 16 - #define O_NOCTTY 0x100 17 - #define O_TRUNC 0x200 18 - #define O_APPEND 0x400 19 - #define O_NONBLOCK 0x800 20 - #define O_DIRECTORY 0x10000 21 - 22 10 /* The struct returned by the stat() syscall, equivalent to stat64(). The 23 11 * syscall returns 116 bytes and stops in the middle of __unused. 24 12 */ ··· 178 190 _ret; \ 179 191 }) 180 192 193 + char **environ __attribute__((weak)); 194 + const unsigned long *_auxv __attribute__((weak)); 195 + 181 196 /* startup code */ 182 197 /* 183 198 * x86-64 System V ABI mandates: ··· 188 197 * 2) The deepest stack frame should be zero (the %rbp). 189 198 * 190 199 */ 191 - __asm__ (".section .text\n" 192 - ".weak _start\n" 193 - "_start:\n" 194 - "pop %rdi\n" // argc (first arg, %rdi) 195 - "mov %rsp, %rsi\n" // argv[] (second arg, %rsi) 196 - "lea 8(%rsi,%rdi,8),%rdx\n" // then a NULL then envp (third arg, %rdx) 197 - "xor %ebp, %ebp\n" // zero the stack frame 198 - "and $-16, %rsp\n" // x86 ABI : esp must be 16-byte aligned before call 199 - "call main\n" // main() returns the status code, we'll exit with it. 200 - "mov %eax, %edi\n" // retrieve exit code (32 bit) 201 - "mov $60, %eax\n" // NR_exit == 60 202 - "syscall\n" // really exit 203 - "hlt\n" // ensure it does not return 204 - ""); 200 + void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void) 201 + { 202 + __asm__ volatile ( 203 + "pop %rdi\n" // argc (first arg, %rdi) 204 + "mov %rsp, %rsi\n" // argv[] (second arg, %rsi) 205 + "lea 8(%rsi,%rdi,8),%rdx\n" // then a NULL then envp (third arg, %rdx) 206 + "mov %rdx, environ\n" // save environ 207 + "xor %ebp, %ebp\n" // zero the stack frame 208 + "mov %rdx, %rax\n" // search for auxv (follows NULL after last env) 209 + "0:\n" 210 + "add $8, %rax\n" // search for auxv using rax, it follows the 211 + "cmp -8(%rax), %rbp\n" // ... NULL after last env (rbp is zero here) 212 + "jnz 0b\n" 213 + "mov %rax, _auxv\n" // save it into _auxv 214 + "and $-16, %rsp\n" // x86 ABI : esp must be 16-byte aligned before call 215 + "call main\n" // main() returns the status code, we'll exit with it. 216 + "mov %eax, %edi\n" // retrieve exit code (32 bit) 217 + "mov $60, %eax\n" // NR_exit == 60 218 + "syscall\n" // really exit 219 + "hlt\n" // ensure it does not return 220 + ); 221 + __builtin_unreachable(); 222 + } 205 223 206 224 #endif // _NOLIBC_ARCH_X86_64_H
+2
tools/include/nolibc/arch.h
··· 27 27 #include "arch-mips.h" 28 28 #elif defined(__riscv) 29 29 #include "arch-riscv.h" 30 + #elif defined(__s390x__) 31 + #include "arch-s390.h" 30 32 #endif 31 33 32 34 #endif /* _NOLIBC_ARCH_H */
+1 -3
tools/include/nolibc/errno.h
··· 9 9 10 10 #include <asm/errno.h> 11 11 12 - /* this way it will be removed if unused */ 13 - static int errno; 14 - 15 12 #ifndef NOLIBC_IGNORE_ERRNO 16 13 #define SET_ERRNO(v) do { errno = (v); } while (0) 14 + int errno __attribute__((weak)); 17 15 #else 18 16 #define SET_ERRNO(v) do { } while (0) 19 17 #endif
+27
tools/include/nolibc/stdlib.h
··· 12 12 #include "types.h" 13 13 #include "sys.h" 14 14 #include "string.h" 15 + #include <linux/auxvec.h> 15 16 16 17 struct nolibc_heap { 17 18 size_t len; ··· 107 106 { 108 107 extern char **environ; 109 108 return _getenv(name, environ); 109 + } 110 + 111 + static __attribute__((unused)) 112 + unsigned long getauxval(unsigned long type) 113 + { 114 + const unsigned long *auxv = _auxv; 115 + unsigned long ret; 116 + 117 + if (!auxv) 118 + return 0; 119 + 120 + while (1) { 121 + if (!auxv[0] && !auxv[1]) { 122 + ret = 0; 123 + break; 124 + } 125 + 126 + if (auxv[0] == type) { 127 + ret = auxv[1]; 128 + break; 129 + } 130 + 131 + auxv += 2; 132 + } 133 + 134 + return ret; 110 135 } 111 136 112 137 static __attribute__((unused))
+24
tools/include/nolibc/sys.h
··· 11 11 #include "std.h" 12 12 13 13 /* system includes */ 14 + #include <asm/fcntl.h> // for O_* 14 15 #include <asm/unistd.h> 15 16 #include <asm/signal.h> // for SIGCHLD 16 17 #include <asm/ioctls.h> ··· 19 18 #include <linux/fs.h> 20 19 #include <linux/loop.h> 21 20 #include <linux/time.h> 21 + #include <linux/auxvec.h> 22 22 23 23 #include "arch.h" 24 24 #include "errno.h" ··· 500 498 return sys_gettid(); 501 499 } 502 500 501 + static unsigned long getauxval(unsigned long key); 502 + 503 + /* 504 + * long getpagesize(void); 505 + */ 506 + 507 + static __attribute__((unused)) 508 + long getpagesize(void) 509 + { 510 + long ret; 511 + 512 + ret = getauxval(AT_PAGESZ); 513 + if (!ret) { 514 + SET_ERRNO(ENOENT); 515 + return -1; 516 + } 517 + 518 + return ret; 519 + } 520 + 503 521 504 522 /* 505 523 * int gettimeofday(struct timeval *tv, struct timezone *tz); ··· 708 686 #define MAP_FAILED ((void *)-1) 709 687 #endif 710 688 689 + #ifndef sys_mmap 711 690 static __attribute__((unused)) 712 691 void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, 713 692 off_t offset) ··· 730 707 return (void *)my_syscall6(n, addr, length, prot, flags, fd, offset); 731 708 #endif 732 709 } 710 + #endif 733 711 734 712 static __attribute__((unused)) 735 713 void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
+16 -1
tools/testing/selftests/nolibc/Makefile
··· 14 14 15 15 # kernel image names by architecture 16 16 IMAGE_i386 = arch/x86/boot/bzImage 17 + IMAGE_x86_64 = arch/x86/boot/bzImage 17 18 IMAGE_x86 = arch/x86/boot/bzImage 18 19 IMAGE_arm64 = arch/arm64/boot/Image 19 20 IMAGE_arm = arch/arm/boot/zImage 20 21 IMAGE_mips = vmlinuz 21 22 IMAGE_riscv = arch/riscv/boot/Image 23 + IMAGE_s390 = arch/s390/boot/bzImage 22 24 IMAGE = $(IMAGE_$(ARCH)) 23 25 IMAGE_NAME = $(notdir $(IMAGE)) 24 26 25 27 # default kernel configurations that appear to be usable 26 28 DEFCONFIG_i386 = defconfig 29 + DEFCONFIG_x86_64 = defconfig 27 30 DEFCONFIG_x86 = defconfig 28 31 DEFCONFIG_arm64 = defconfig 29 32 DEFCONFIG_arm = multi_v7_defconfig 30 33 DEFCONFIG_mips = malta_defconfig 31 34 DEFCONFIG_riscv = defconfig 35 + DEFCONFIG_s390 = defconfig 32 36 DEFCONFIG = $(DEFCONFIG_$(ARCH)) 33 37 34 38 # optional tests to run (default = all) ··· 40 36 41 37 # QEMU_ARCH: arch names used by qemu 42 38 QEMU_ARCH_i386 = i386 39 + QEMU_ARCH_x86_64 = x86_64 43 40 QEMU_ARCH_x86 = x86_64 44 41 QEMU_ARCH_arm64 = aarch64 45 42 QEMU_ARCH_arm = arm 46 43 QEMU_ARCH_mips = mipsel # works with malta_defconfig 47 44 QEMU_ARCH_riscv = riscv64 45 + QEMU_ARCH_s390 = s390x 48 46 QEMU_ARCH = $(QEMU_ARCH_$(ARCH)) 49 47 50 48 # QEMU_ARGS : some arch-specific args to pass to qemu 51 49 QEMU_ARGS_i386 = -M pc -append "console=ttyS0,9600 i8042.noaux panic=-1 $(TEST:%=NOLIBC_TEST=%)" 50 + QEMU_ARGS_x86_64 = -M pc -append "console=ttyS0,9600 i8042.noaux panic=-1 $(TEST:%=NOLIBC_TEST=%)" 52 51 QEMU_ARGS_x86 = -M pc -append "console=ttyS0,9600 i8042.noaux panic=-1 $(TEST:%=NOLIBC_TEST=%)" 53 52 QEMU_ARGS_arm64 = -M virt -cpu cortex-a53 -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)" 54 53 QEMU_ARGS_arm = -M virt -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)" 55 54 QEMU_ARGS_mips = -M malta -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)" 56 55 QEMU_ARGS_riscv = -M virt -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" 56 + QEMU_ARGS_s390 = -M s390-ccw-virtio -m 1G -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" 57 57 QEMU_ARGS = $(QEMU_ARGS_$(ARCH)) 58 58 59 59 # OUTPUT is only set when run from the main makefile, otherwise ··· 70 62 Q=@ 71 63 endif 72 64 73 - CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables 65 + CFLAGS_s390 = -m64 66 + CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables $(CFLAGS_$(ARCH)) 74 67 LDFLAGS := -s 75 68 76 69 help: ··· 80 71 @echo " help this help" 81 72 @echo " sysroot create the nolibc sysroot here (uses \$$ARCH)" 82 73 @echo " nolibc-test build the executable (uses \$$CC and \$$CROSS_COMPILE)" 74 + @echo " run-user runs the executable under QEMU (uses \$$ARCH, \$$TEST)" 83 75 @echo " initramfs prepare the initramfs with nolibc-test" 84 76 @echo " defconfig create a fresh new default config (uses \$$ARCH)" 85 77 @echo " kernel (re)build the kernel with the initramfs (uses \$$ARCH)" ··· 113 103 nolibc-test: nolibc-test.c sysroot/$(ARCH)/include 114 104 $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \ 115 105 -nostdlib -static -Isysroot/$(ARCH)/include $< -lgcc 106 + 107 + # qemu user-land test 108 + run-user: nolibc-test 109 + $(Q)qemu-$(QEMU_ARCH) ./nolibc-test > "$(CURDIR)/run.out" || : 110 + $(Q)grep -w FAIL "$(CURDIR)/run.out" && echo "See all results in $(CURDIR)/run.out" || echo "$$(grep -c ^[0-9].*OK $(CURDIR)/run.out) test(s) passed." 116 111 117 112 initramfs: nolibc-test 118 113 $(QUIET_MKDIR)mkdir -p initramfs
+30
tools/testing/selftests/nolibc/nolibc-test.c
··· 442 442 return ret; 443 443 } 444 444 445 + static int test_getpagesize(void) 446 + { 447 + long x = getpagesize(); 448 + int c; 449 + 450 + if (x < 0) 451 + return x; 452 + 453 + #if defined(__x86_64__) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) 454 + /* 455 + * x86 family is always 4K page. 456 + */ 457 + c = (x == 4096); 458 + #elif defined(__aarch64__) 459 + /* 460 + * Linux aarch64 supports three values of page size: 4K, 16K, and 64K 461 + * which are selected at kernel compilation time. 462 + */ 463 + c = (x == 4096 || x == (16 * 1024) || x == (64 * 1024)); 464 + #else 465 + /* 466 + * Assuming other architectures must have at least 4K page. 467 + */ 468 + c = (x >= 4096); 469 + #endif 470 + 471 + return !c; 472 + } 473 + 445 474 /* Run syscall tests between IDs <min> and <max>. 446 475 * Return 0 on success, non-zero on failure. 447 476 */ ··· 531 502 CASE_TEST(gettimeofday_bad2); EXPECT_SYSER(1, gettimeofday(NULL, (void *)1), -1, EFAULT); break; 532 503 CASE_TEST(gettimeofday_bad2); EXPECT_SYSER(1, gettimeofday(NULL, (void *)1), -1, EFAULT); break; 533 504 #endif 505 + CASE_TEST(getpagesize); EXPECT_SYSZR(1, test_getpagesize()); break; 534 506 CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break; 535 507 CASE_TEST(ioctl_tiocinq); EXPECT_SYSZR(1, ioctl(0, TIOCINQ, &tmp)); break; 536 508 CASE_TEST(link_root1); EXPECT_SYSER(1, link("/", "/"), -1, EEXIST); break;
+6
tools/testing/selftests/rcutorture/bin/functions.sh
··· 159 159 qemu-system-aarch64) 160 160 echo arch/arm64/boot/Image 161 161 ;; 162 + qemu-system-s390x) 163 + echo arch/s390/boot/bzImage 164 + ;; 162 165 *) 163 166 echo vmlinux 164 167 ;; ··· 187 184 elif echo $u | grep -q aarch64 188 185 then 189 186 echo qemu-system-aarch64 187 + elif echo $u | grep -q 'IBM S/390' 188 + then 189 + echo qemu-system-s390x 190 190 elif uname -a | grep -q ppc64 191 191 then 192 192 echo qemu-system-ppc64
+1 -1
tools/testing/selftests/rcutorture/bin/mkinitrd.sh
··· 64 64 # build using nolibc on supported archs (smaller executable) and fall 65 65 # back to regular glibc on other ones. 66 66 if echo -e "#if __x86_64__||__i386__||__i486__||__i586__||__i686__" \ 67 - "||__ARM_EABI__||__aarch64__\nyes\n#endif" \ 67 + "||__ARM_EABI__||__aarch64__||__s390x__\nyes\n#endif" \ 68 68 | ${CROSS_COMPILE}gcc -E -nostdlib -xc - \ 69 69 | grep -q '^yes'; then 70 70 # architecture supported by nolibc