From b08b0728ae5e297d794a02297f01eb76aa8fb909 Mon Sep 17 00:00:00 2001 From: cowmonk Date: Wed, 28 May 2025 18:58:30 -0700 Subject: [PATCH] cowos uses it's own cowlibc! big W --- Makefile | 3 +- README.md | 1 - kernel/include/klibc/arch.h | 235 ------ kernel/include/klibc/ctype.h | 118 --- kernel/include/klibc/errno.h | 46 -- kernel/include/klibc/nolibc.h | 130 ---- kernel/include/klibc/signal.h | 41 -- kernel/include/klibc/std.h | 68 -- kernel/include/klibc/stdio.h | 328 +-------- kernel/include/klibc/stdlib.h | 353 --------- kernel/include/klibc/string.h | 237 +----- kernel/include/klibc/sys.h | 1187 ------------------------------ kernel/include/klibc/sys/cdefs.h | 6 + kernel/include/klibc/time.h | 47 -- kernel/include/klibc/types.h | 203 ----- kernel/include/klibc/unistd.h | 73 -- kernel/klibc/stdio.c | 100 +++ kernel/klibc/string.c | 62 ++ 18 files changed, 188 insertions(+), 3050 deletions(-) delete mode 100644 kernel/include/klibc/arch.h delete mode 100644 kernel/include/klibc/ctype.h delete mode 100644 kernel/include/klibc/errno.h delete mode 100644 kernel/include/klibc/nolibc.h delete mode 100644 kernel/include/klibc/signal.h delete mode 100644 kernel/include/klibc/std.h delete mode 100644 kernel/include/klibc/stdlib.h delete mode 100644 kernel/include/klibc/sys.h create mode 100644 kernel/include/klibc/sys/cdefs.h delete mode 100644 kernel/include/klibc/time.h delete mode 100644 kernel/include/klibc/types.h delete mode 100644 kernel/include/klibc/unistd.h create mode 100644 kernel/klibc/stdio.c create mode 100644 kernel/klibc/string.c diff --git a/Makefile b/Makefile index b99e058..694385f 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ iso: kernel limine kernel: make -C ./kernel/ all -limine: +limine: kernel git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1 make -C limine @@ -26,3 +26,4 @@ limine: clean: rm cowos.iso + make -C ./kernel/ clean diff --git a/README.md b/README.md index 6429cac..3b93a81 100644 --- a/README.md +++ b/README.md @@ -23,5 +23,4 @@ make ``` # Credits -- [nolibc](https://github.com/wtarreau/nolibc): libc-less wrapper to make tiny static executables for simple programs. - [Limine](https://github.com/limine-bootloader/limine): modern, advanced, portable, multiprotocol bootloader and boot manager. diff --git a/kernel/include/klibc/arch.h b/kernel/include/klibc/arch.h deleted file mode 100644 index 1510679..0000000 --- a/kernel/include/klibc/arch.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - * x86_64 specific definitions for NOLIBC - * Copyright (C) 2017-2022 Willy Tarreau - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _NOLIBC_ARCH_H -#define _NOLIBC_ARCH_H - -/* O_* macros for fcntl/open are architecture-specific */ -#define O_RDONLY 0 -#define O_WRONLY 1 -#define O_RDWR 2 -#define O_CREAT 0x40 -#define O_EXCL 0x80 -#define O_NOCTTY 0x100 -#define O_TRUNC 0x200 -#define O_APPEND 0x400 -#define O_NONBLOCK 0x800 -#define O_DIRECTORY 0x10000 - -/* 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]; -}; - -/* Syscalls for x86_64 : - * - registers are 64-bit - * - syscall number is passed in rax - * - arguments are in rdi, rsi, rdx, r10, r8, r9 respectively - * - the system call is performed by calling the syscall instruction - * - syscall return comes in rax - * - rcx and r11 are clobbered, others are preserved. - * - 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. - * - the syscall number is always specified last in order to allow to force - * some registers before (gcc refuses a %-register at the last position). - * - see also x86-64 ABI section A.2 AMD64 Linux Kernel Conventions, A.2.1 - * Calling Conventions. - * - * Link x86-64 ABI: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI - * - */ - -#define my_syscall0(num) \ -({ \ - long _ret; \ - register long _num asm("rax") = (num); \ - \ - asm volatile ( \ - "syscall\n" \ - : "=a"(_ret) \ - : "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ -}) - -#define my_syscall1(num, arg1) \ -({ \ - long _ret; \ - register long _num asm("rax") = (num); \ - register long _arg1 asm("rdi") = (long)(arg1); \ - \ - asm volatile ( \ - "syscall\n" \ - : "=a"(_ret) \ - : "r"(_arg1), \ - "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ -}) - -#define my_syscall2(num, arg1, arg2) \ -({ \ - long _ret; \ - register long _num asm("rax") = (num); \ - register long _arg1 asm("rdi") = (long)(arg1); \ - register long _arg2 asm("rsi") = (long)(arg2); \ - \ - asm volatile ( \ - "syscall\n" \ - : "=a"(_ret) \ - : "r"(_arg1), "r"(_arg2), \ - "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ -}) - -#define my_syscall3(num, arg1, arg2, arg3) \ -({ \ - long _ret; \ - register long _num asm("rax") = (num); \ - register long _arg1 asm("rdi") = (long)(arg1); \ - register long _arg2 asm("rsi") = (long)(arg2); \ - register long _arg3 asm("rdx") = (long)(arg3); \ - \ - asm volatile ( \ - "syscall\n" \ - : "=a"(_ret) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ - "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ -}) - -#define my_syscall4(num, arg1, arg2, arg3, arg4) \ -({ \ - long _ret; \ - register long _num asm("rax") = (num); \ - register long _arg1 asm("rdi") = (long)(arg1); \ - register long _arg2 asm("rsi") = (long)(arg2); \ - register long _arg3 asm("rdx") = (long)(arg3); \ - register long _arg4 asm("r10") = (long)(arg4); \ - \ - asm volatile ( \ - "syscall\n" \ - : "=a"(_ret) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ - "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ -}) - -#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ -({ \ - long _ret; \ - register long _num asm("rax") = (num); \ - register long _arg1 asm("rdi") = (long)(arg1); \ - register long _arg2 asm("rsi") = (long)(arg2); \ - register long _arg3 asm("rdx") = (long)(arg3); \ - register long _arg4 asm("r10") = (long)(arg4); \ - register long _arg5 asm("r8") = (long)(arg5); \ - \ - asm volatile ( \ - "syscall\n" \ - : "=a"(_ret) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ - "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ -}) - -#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ -({ \ - long _ret; \ - register long _num asm("rax") = (num); \ - register long _arg1 asm("rdi") = (long)(arg1); \ - register long _arg2 asm("rsi") = (long)(arg2); \ - register long _arg3 asm("rdx") = (long)(arg3); \ - register long _arg4 asm("r10") = (long)(arg4); \ - register long _arg5 asm("r8") = (long)(arg5); \ - register long _arg6 asm("r9") = (long)(arg6); \ - \ - asm volatile ( \ - "syscall\n" \ - : "=a"(_ret) \ - : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ - "r"(_arg6), "0"(_num) \ - : "rcx", "r11", "memory", "cc" \ - ); \ - _ret; \ -}) - -/* startup code */ -/* - * x86-64 System V ABI mandates: - * 1) %rsp must be 16-byte aligned right before the function call. - * 2) The deepest stack frame should be zero (the %rbp). - * - */ -asm(".section .text\n" - ".weak _start\n" - ".global _start\n" - "_start:\n" - "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) - "xor %ebp, %ebp\n" // zero the stack frame - "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 - ""); - -#endif // _NOLIBC_ARCH_H diff --git a/kernel/include/klibc/ctype.h b/kernel/include/klibc/ctype.h deleted file mode 100644 index 807b18d..0000000 --- a/kernel/include/klibc/ctype.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * ctype function definitions for NOLIBC - * Copyright (C) 2017-2021 Willy Tarreau - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _NOLIBC_CTYPE_H -#define _NOLIBC_CTYPE_H - -#include "std.h" - -/* - * As much as possible, please keep functions alphabetically sorted. - */ - -static __attribute__((unused)) -int isascii(int c) -{ - /* 0x00..0x7f */ - return (unsigned int)c <= 0x7f; -} - -static __attribute__((unused)) -int isblank(int c) -{ - return c == '\t' || c == ' '; -} - -static __attribute__((unused)) -int iscntrl(int c) -{ - /* 0x00..0x1f, 0x7f */ - return (unsigned int)c < 0x20 || c == 0x7f; -} - -static __attribute__((unused)) -int isdigit(int c) -{ - return (unsigned int)(c - '0') < 10; -} - -static __attribute__((unused)) -int isgraph(int c) -{ - /* 0x21..0x7e */ - return (unsigned int)(c - 0x21) < 0x5e; -} - -static __attribute__((unused)) -int islower(int c) -{ - return (unsigned int)(c - 'a') < 26; -} - -static __attribute__((unused)) -int isprint(int c) -{ - /* 0x20..0x7e */ - return (unsigned int)(c - 0x20) < 0x5f; -} - -static __attribute__((unused)) -int isspace(int c) -{ - /* \t is 0x9, \n is 0xA, \v is 0xB, \f is 0xC, \r is 0xD */ - return ((unsigned int)c == ' ') || (unsigned int)(c - 0x09) < 5; -} - -static __attribute__((unused)) -int isupper(int c) -{ - return (unsigned int)(c - 'A') < 26; -} - -static __attribute__((unused)) -int isxdigit(int c) -{ - return isdigit(c) || (unsigned int)(c - 'A') < 6 || (unsigned int)(c - 'a') < 6; -} - -static __attribute__((unused)) -int isalpha(int c) -{ - return islower(c) || isupper(c); -} - -static __attribute__((unused)) -int isalnum(int c) -{ - return isalpha(c) || isdigit(c); -} - -static __attribute__((unused)) -int ispunct(int c) -{ - return isgraph(c) && !isalnum(c); -} - -#endif /* _NOLIBC_CTYPE_H */ diff --git a/kernel/include/klibc/errno.h b/kernel/include/klibc/errno.h deleted file mode 100644 index df0e473..0000000 --- a/kernel/include/klibc/errno.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Minimal errno definitions for NOLIBC - * Copyright (C) 2017-2022 Willy Tarreau - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _NOLIBC_ERRNO_H -#define _NOLIBC_ERRNO_H - -#include - -/* this way it will be removed if unused */ -static int errno; - -#ifndef NOLIBC_IGNORE_ERRNO -#define SET_ERRNO(v) do { errno = (v); } while (0) -#else -#define SET_ERRNO(v) do { } while (0) -#endif - - -/* errno codes all ensure that they will not conflict with a valid pointer - * because they all correspond to the highest addressable memory page. - */ -#define MAX_ERRNO 4095 - -#endif /* _NOLIBC_ERRNO_H */ diff --git a/kernel/include/klibc/nolibc.h b/kernel/include/klibc/nolibc.h deleted file mode 100644 index c8ef67e..0000000 --- a/kernel/include/klibc/nolibc.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2017-2018 Willy Tarreau - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * This file is designed to be used as a libc alternative for minimal programs - * with very limited requirements. It consists of a small number of syscall and - * type definitions, and the minimal startup code needed to call main(). - * All syscalls are declared as static functions so that they can be optimized - * away by the compiler when not used. - * - * 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. - * - * - The second level is mostly architecture-independent. It is made of - * static functions called sys_() which rely on my_syscallN() - * depending on the syscall definition. These functions are responsible - * for exposing the appropriate types for the syscall arguments (int, - * pointers, etc) and for setting the appropriate return type (often int). - * A few of them are architecture-specific because the syscalls are not all - * mapped exactly the same among architectures. For example, some archs do - * not implement select() and need pselect6() instead, so the sys_select() - * function will have to abstract this. - * - * - The third level is the libc call definition. It exposes the lower raw - * sys_() calls in a way that looks like what a libc usually does, - * takes care of specific input values, and of setting errno upon error. - * There can be minor variations compared to standard libc calls. For - * example the open() call always takes 3 args here. - * - * The errno variable is declared static and unused. This way it can be - * optimized away if not used. However this means that a program made of - * multiple C files may observe different errno values (one per C file). For - * the type of programs this project targets it usually is not a problem. The - * resulting program may even be reduced by defining the NOLIBC_IGNORE_ERRNO - * macro, in which case the errno value will never be assigned. - * - * Some stdint-like integer types are defined. These are valid on all currently - * supported architectures, because signs are enforced, ints are assumed to be - * 32 bits, longs the size of a pointer and long long 64 bits. If more - * architectures have to be supported, this may need to be adapted. - * - * Some macro definitions like the O_* values passed to open(), and some - * structures like the sys_stat struct depend on the architecture. - * - * The definitions start with the architecture-specific parts, which are picked - * based on what the compiler knows about the target architecture, and are - * completed with the generic code. Since it is the compiler which sets the - * target architecture, cross-compiling normally works out of the box without - * having to specify anything. - * - * Finally some very common libc-level functions are provided. It is the case - * for a few functions usually found in string.h, ctype.h, or stdlib.h. - * - * The nolibc.h file is only a convenient entry point which includes all other - * files. It also defines the NOLIBC macro, so that it is possible for a - * program to check this macro to know if it is being built against and decide - * to disable some features or simply not to include some standard libc files. - * - * A simple static executable may be built this way : - * $ gcc -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \ - * -static -include nolibc.h -o hello hello.c -lgcc - * - * Simple programs meant to be reasonably portable to various libc and using - * only a few common includes, may also be built by simply making the include - * path point to the nolibc directory: - * $ gcc -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \ - * -I../nolibc -o hello hello.c -lgcc - * - * The available standard (but limited) include files are: - * ctype.h, errno.h, signal.h, stdio.h, stdlib.h, string.h, time.h - * - * In addition, the following ones are expected to be provided by the compiler: - * float.h, stdarg.h, stddef.h - * - * The following ones which are part to the C standard are not provided: - * assert.h, locale.h, math.h, setjmp.h, limits.h - * - * A very useful calling convention table may be found here : - * http://man7.org/linux/man-pages/man2/syscall.2.html - * - * This doc is quite convenient though not necessarily up to date : - * https://w3challs.com/syscalls/ - * - */ -#ifndef _NOLIBC_H -#define _NOLIBC_H - -#include "std.h" -#include "arch.h" -#include "types.h" -#include "sys.h" -#include "ctype.h" -#include "signal.h" -#include "stdio.h" -#include "stdlib.h" -#include "string.h" -#include "time.h" -#include "unistd.h" - -/* Used by programs to avoid std includes */ -#define NOLIBC - -#endif /* _NOLIBC_H */ diff --git a/kernel/include/klibc/signal.h b/kernel/include/klibc/signal.h deleted file mode 100644 index 78109a3..0000000 --- a/kernel/include/klibc/signal.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * signal function definitions for NOLIBC - * Copyright (C) 2017-2022 Willy Tarreau - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _NOLIBC_SIGNAL_H -#define _NOLIBC_SIGNAL_H - -#include "std.h" -#include "arch.h" -#include "types.h" -#include "sys.h" - -/* This one is not marked static as it's needed by libgcc for divide by zero */ -__attribute__((weak,unused,section(".text.nolibc_raise"))) -int raise(int signal) -{ - return sys_kill(sys_getpid(), signal); -} - -#endif /* _NOLIBC_SIGNAL_H */ diff --git a/kernel/include/klibc/std.h b/kernel/include/klibc/std.h deleted file mode 100644 index fdb4d0e..0000000 --- a/kernel/include/klibc/std.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Standard definitions and types for NOLIBC - * Copyright (C) 2017-2021 Willy Tarreau - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _NOLIBC_STD_H -#define _NOLIBC_STD_H - -/* Declare a few quite common macros and types that usually are in stdlib.h, - * stdint.h, ctype.h, unistd.h and a few other common locations. Please place - * integer type definitions and generic macros here, but avoid OS-specific and - * syscall-specific stuff, as this file is expected to be included very early. - */ - -/* note: may already be defined */ -#ifndef NULL -#define NULL ((void *)0) -#endif - -/* stdint types */ -typedef unsigned char uint8_t; -typedef signed char int8_t; -typedef unsigned short uint16_t; -typedef signed short int16_t; -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 signed long ssize_t; -typedef unsigned long uintptr_t; -typedef signed long intptr_t; -typedef signed long ptrdiff_t; - -/* those are commonly provided by sys/types.h */ -typedef unsigned int dev_t; -typedef unsigned long ino_t; -typedef unsigned int mode_t; -typedef signed int pid_t; -typedef unsigned int uid_t; -typedef unsigned int gid_t; -typedef unsigned long nlink_t; -typedef signed long off_t; -typedef signed long blksize_t; -typedef signed long blkcnt_t; -typedef signed long time_t; - -#endif /* _NOLIBC_STD_H */ diff --git a/kernel/include/klibc/stdio.h b/kernel/include/klibc/stdio.h index 68cb75c..be66ea1 100644 --- a/kernel/include/klibc/stdio.h +++ b/kernel/include/klibc/stdio.h @@ -1,325 +1,13 @@ -/* - * minimal stdio function definitions for NOLIBC - * Copyright (C) 2017-2021 Willy Tarreau - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ +#ifndef _STDIO_H +#define _STDIO_H 1 -#ifndef _NOLIBC_STDIO_H -#define _NOLIBC_STDIO_H +#include -#include - -#include "std.h" -#include "arch.h" -#include "errno.h" -#include "types.h" -#include "sys.h" -#include "stdlib.h" -#include "string.h" - -#ifndef EOF #define EOF (-1) + +int printf(const char* __restrict, ...); +int putchar(int); +int puts(const char*); + #endif -/* just define FILE as a non-empty type */ -typedef struct FILE { - char dummy[1]; -} FILE; - -/* We define the 3 common stdio files as constant invalid pointers that - * are easily recognized. - */ -static __attribute__((unused)) FILE* const stdin = (FILE*)-3; -static __attribute__((unused)) FILE* const stdout = (FILE*)-2; -static __attribute__((unused)) FILE* const stderr = (FILE*)-1; - -/* getc(), fgetc(), getchar() */ - -#define getc(stream) fgetc(stream) - -static __attribute__((unused)) -int fgetc(FILE* stream) -{ - unsigned char ch; - int fd; - - if (stream < stdin || stream > stderr) - return EOF; - - fd = 3 + (long)stream; - - if (read(fd, &ch, 1) <= 0) - return EOF; - return ch; -} - -static __attribute__((unused)) -int getchar(void) -{ - return fgetc(stdin); -} - - -/* putc(), fputc(), putchar() */ - -#define putc(c, stream) fputc(c, stream) - -static __attribute__((unused)) -int fputc(int c, FILE* stream) -{ - unsigned char ch = c; - int fd; - - if (stream < stdin || stream > stderr) - return EOF; - - fd = 3 + (long)stream; - - if (write(fd, &ch, 1) <= 0) - return EOF; - return ch; -} - -static __attribute__((unused)) -int putchar(int c) -{ - return fputc(c, stdout); -} - - -/* fwrite(), puts(), fputs(). Note that puts() emits '\n' but not fputs(). */ - -/* internal fwrite()-like function which only takes a size and returns 0 on - * success or EOF on error. It automatically retries on short writes. - */ -static __attribute__((unused)) -int _fwrite(const void *buf, size_t size, FILE *stream) -{ - ssize_t ret; - int fd; - - if (stream < stdin || stream > stderr) - return EOF; - - fd = 3 + (long)stream; - - while (size) { - ret = write(fd, buf, size); - if (ret <= 0) - return EOF; - size -= ret; - buf += ret; - } - return 0; -} - -static __attribute__((unused)) -size_t fwrite(const void *s, size_t size, size_t nmemb, FILE *stream) -{ - size_t written; - - for (written = 0; written < nmemb; written++) { - if (_fwrite(s, size, stream) != 0) - break; - s += size; - } - return written; -} - -static __attribute__((unused)) -int fputs(const char *s, FILE *stream) -{ - return _fwrite(s, strlen(s), stream); -} - -static __attribute__((unused)) -int puts(const char *s) -{ - if (fputs(s, stdout) == EOF) - return EOF; - return putchar('\n'); -} - - -/* fgets() */ -static __attribute__((unused)) -char *fgets(char *s, int size, FILE *stream) -{ - int ofs; - int c; - - for (ofs = 0; ofs + 1 < size;) { - c = fgetc(stream); - if (c == EOF) - break; - s[ofs++] = c; - if (c == '\n') - break; - } - if (ofs < size) - s[ofs] = 0; - return ofs ? s : NULL; -} - - -/* minimal vfprintf(). It supports the following formats: - * - %[l*]{d,u,c,x,p} - * - %s - * - unknown modifiers are ignored. - */ -static __attribute__((unused)) -int vfprintf(FILE *stream, const char *fmt, va_list args) -{ - char escape, lpref, c; - unsigned long long v; - unsigned int written; - size_t len, ofs; - char tmpbuf[21]; - const char *outstr; - - written = ofs = escape = lpref = 0; - while (1) { - c = fmt[ofs++]; - - if (escape) { - /* we're in an escape sequence, ofs == 1 */ - escape = 0; - if (c == 'c' || c == 'd' || c == 'u' || c == 'x' || c == 'p') { - char *out = tmpbuf; - - if (c == 'p') - v = va_arg(args, unsigned long); - else if (lpref) { - if (lpref > 1) - v = va_arg(args, unsigned long long); - else - v = va_arg(args, unsigned long); - } else - v = va_arg(args, unsigned int); - - if (c == 'd') { - /* sign-extend the value */ - if (lpref == 0) - v = (long long)(int)v; - else if (lpref == 1) - v = (long long)(long)v; - } - - switch (c) { - case 'c': - out[0] = v; - out[1] = 0; - break; - case 'd': - i64toa_r(v, out); - break; - case 'u': - u64toa_r(v, out); - break; - case 'p': - *(out++) = '0'; - *(out++) = 'x'; - /* fall through */ - default: /* 'x' and 'p' above */ - u64toh_r(v, out); - break; - } - outstr = tmpbuf; - } - else if (c == 's') { - outstr = va_arg(args, char *); - if (!outstr) - outstr="(null)"; - } - else if (c == '%') { - /* queue it verbatim */ - continue; - } - else { - /* modifiers or final 0 */ - if (c == 'l') { - /* long format prefix, maintain the escape */ - lpref++; - } - escape = 1; - goto do_escape; - } - len = strlen(outstr); - goto flush_str; - } - - /* not an escape sequence */ - if (c == 0 || c == '%') { - /* flush pending data on escape or end */ - escape = 1; - lpref = 0; - outstr = fmt; - len = ofs - 1; - flush_str: - if (_fwrite(outstr, len, stream) != 0) - break; - - written += len; - do_escape: - if (c == 0) - break; - fmt += ofs; - ofs = 0; - continue; - } - - /* literal char, just queue it */ - } - return written; -} - -static __attribute__((unused)) -int fprintf(FILE *stream, const char *fmt, ...) -{ - va_list args; - int ret; - - va_start(args, fmt); - ret = vfprintf(stream, fmt, args); - va_end(args); - return ret; -} - -static __attribute__((unused)) -int printf(const char *fmt, ...) -{ - va_list args; - int ret; - - va_start(args, fmt); - ret = vfprintf(stdout, fmt, args); - va_end(args); - return ret; -} - -static __attribute__((unused)) -void perror(const char *msg) -{ - fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno); -} - -#endif /* _NOLIBC_STDIO_H */ diff --git a/kernel/include/klibc/stdlib.h b/kernel/include/klibc/stdlib.h deleted file mode 100644 index d97ce7f..0000000 --- a/kernel/include/klibc/stdlib.h +++ /dev/null @@ -1,353 +0,0 @@ -/* - * stdlib function definitions for NOLIBC - * Copyright (C) 2017-2021 Willy Tarreau - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _NOLIBC_STDLIB_H -#define _NOLIBC_STDLIB_H - -#include "std.h" -#include "arch.h" -#include "types.h" -#include "sys.h" - - -/* Buffer used to store int-to-ASCII conversions. Will only be implemented if - * any of the related functions is implemented. The area is large enough to - * store "18446744073709551615" or "-9223372036854775808" and the final zero. - */ -static __attribute__((unused)) char itoa_buffer[21]; - -/* - * As much as possible, please keep functions alphabetically sorted. - */ - -/* must be exported, as it's used by libgcc for various divide functions */ -__attribute__((weak,unused,noreturn,section(".text.nolibc_abort"))) -void abort(void) -{ - sys_kill(sys_getpid(), SIGABRT); - for (;;); -} - -static __attribute__((unused)) -long atol(const char *s) -{ - unsigned long ret = 0; - unsigned long d; - int neg = 0; - - if (*s == '-') { - neg = 1; - s++; - } - - while (1) { - d = (*s++) - '0'; - if (d > 9) - break; - ret *= 10; - ret += d; - } - - return neg ? -ret : ret; -} - -static __attribute__((unused)) -int atoi(const char *s) -{ - return atol(s); -} - -/* Tries to find the environment variable named in the environment array - * pointed to by global variable "environ" which must be 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. - */ -static __attribute__((unused)) -char *getenv(const char *name) -{ - extern char **environ; - int idx, i; - - if (environ) { - for (idx = 0; environ[idx]; idx++) { - for (i = 0; name[i] && name[i] == environ[idx][i];) - i++; - if (!name[i] && environ[idx][i] == '=') - return &environ[idx][i+1]; - } - } - return NULL; -} - -/* Converts the unsigned long integer to its hex representation into - * buffer , which must be long enough to store the number and the - * trailing zero (17 bytes for "ffffffffffffffff" or 9 for "ffffffff"). The - * buffer is filled from the first byte, and the number of characters emitted - * (not counting the trailing zero) is returned. The function is constructed - * in a way to optimize the code size and avoid any divide that could add a - * dependency on large external functions. - */ -static __attribute__((unused)) -int utoh_r(unsigned long in, char *buffer) -{ - signed char pos = (~0UL > 0xfffffffful) ? 60 : 28; - int digits = 0; - int dig; - - do { - dig = in >> pos; - in -= (uint64_t)dig << pos; - pos -= 4; - if (dig || digits || pos < 0) { - if (dig > 9) - dig += 'a' - '0' - 10; - buffer[digits++] = '0' + dig; - } - } while (pos >= 0); - - buffer[digits] = 0; - return digits; -} - -/* converts unsigned long to an hex string using the static itoa_buffer - * and returns the pointer to that string. - */ -static inline __attribute__((unused)) -char *utoh(unsigned long in) -{ - utoh_r(in, itoa_buffer); - return itoa_buffer; -} - -/* Converts the unsigned long integer to its string representation into - * buffer , which must be long enough to store the number and the - * trailing zero (21 bytes for 18446744073709551615 in 64-bit, 11 for - * 4294967295 in 32-bit). The buffer is filled from the first byte, and the - * number of characters emitted (not counting the trailing zero) is returned. - * The function is constructed in a way to optimize the code size and avoid - * any divide that could add a dependency on large external functions. - */ -static __attribute__((unused)) -int utoa_r(unsigned long in, char *buffer) -{ - unsigned long lim; - int digits = 0; - int pos = (~0UL > 0xfffffffful) ? 19 : 9; - int dig; - - do { - for (dig = 0, lim = 1; dig < pos; dig++) - lim *= 10; - - if (digits || in >= lim || !pos) { - for (dig = 0; in >= lim; dig++) - in -= lim; - buffer[digits++] = '0' + dig; - } - } while (pos--); - - buffer[digits] = 0; - return digits; -} - -/* Converts the signed long integer to its string representation into - * buffer , which must be long enough to store the number and the - * trailing zero (21 bytes for -9223372036854775808 in 64-bit, 12 for - * -2147483648 in 32-bit). The buffer is filled from the first byte, and the - * number of characters emitted (not counting the trailing zero) is returned. - */ -static __attribute__((unused)) -int itoa_r(long in, char *buffer) -{ - char *ptr = buffer; - int len = 0; - - if (in < 0) { - in = -in; - *(ptr++) = '-'; - len++; - } - len += utoa_r(in, ptr); - return len; -} - -/* for historical compatibility, same as above but returns the pointer to the - * buffer. - */ -static inline __attribute__((unused)) -char *ltoa_r(long in, char *buffer) -{ - itoa_r(in, buffer); - return buffer; -} - -/* converts long integer to a string using the static itoa_buffer and - * returns the pointer to that string. - */ -static inline __attribute__((unused)) -char *itoa(long in) -{ - itoa_r(in, itoa_buffer); - return itoa_buffer; -} - -/* converts long integer to a string using the static itoa_buffer and - * returns the pointer to that string. Same as above, for compatibility. - */ -static inline __attribute__((unused)) -char *ltoa(long in) -{ - itoa_r(in, itoa_buffer); - return itoa_buffer; -} - -/* converts unsigned long integer to a string using the static itoa_buffer - * and returns the pointer to that string. - */ -static inline __attribute__((unused)) -char *utoa(unsigned long in) -{ - utoa_r(in, itoa_buffer); - return itoa_buffer; -} - -/* Converts the unsigned 64-bit integer to its hex representation into - * buffer , which must be long enough to store the number and the - * trailing zero (17 bytes for "ffffffffffffffff"). The buffer is filled from - * the first byte, and the number of characters emitted (not counting the - * trailing zero) is returned. The function is constructed in a way to optimize - * the code size and avoid any divide that could add a dependency on large - * external functions. - */ -static __attribute__((unused)) -int u64toh_r(uint64_t in, char *buffer) -{ - signed char pos = 60; - int digits = 0; - int dig; - - do { - if (sizeof(long) >= 8) { - dig = (in >> pos) & 0xF; - } else { - /* 32-bit platforms: avoid a 64-bit shift */ - uint32_t d = (pos >= 32) ? (in >> 32) : in; - dig = (d >> (pos & 31)) & 0xF; - } - if (dig > 9) - dig += 'a' - '0' - 10; - pos -= 4; - if (dig || digits || pos < 0) - buffer[digits++] = '0' + dig; - } while (pos >= 0); - - buffer[digits] = 0; - return digits; -} - -/* converts uint64_t to an hex string using the static itoa_buffer and - * returns the pointer to that string. - */ -static inline __attribute__((unused)) -char *u64toh(uint64_t in) -{ - u64toh_r(in, itoa_buffer); - return itoa_buffer; -} - -/* Converts the unsigned 64-bit integer to its string representation into - * buffer , which must be long enough to store the number and the - * trailing zero (21 bytes for 18446744073709551615). The buffer is filled from - * the first byte, and the number of characters emitted (not counting the - * trailing zero) is returned. The function is constructed in a way to optimize - * the code size and avoid any divide that could add a dependency on large - * external functions. - */ -static __attribute__((unused)) -int u64toa_r(uint64_t in, char *buffer) -{ - unsigned long long lim; - int digits = 0; - int pos = 19; /* start with the highest possible digit */ - int dig; - - do { - for (dig = 0, lim = 1; dig < pos; dig++) - lim *= 10; - - if (digits || in >= lim || !pos) { - for (dig = 0; in >= lim; dig++) - in -= lim; - buffer[digits++] = '0' + dig; - } - } while (pos--); - - buffer[digits] = 0; - return digits; -} - -/* Converts the signed 64-bit integer to its string representation into - * buffer , which must be long enough to store the number and the - * trailing zero (21 bytes for -9223372036854775808). The buffer is filled from - * the first byte, and the number of characters emitted (not counting the - * trailing zero) is returned. - */ -static __attribute__((unused)) -int i64toa_r(int64_t in, char *buffer) -{ - char *ptr = buffer; - int len = 0; - - if (in < 0) { - in = -in; - *(ptr++) = '-'; - len++; - } - len += u64toa_r(in, ptr); - return len; -} - -/* converts int64_t to a string using the static itoa_buffer and returns - * the pointer to that string. - */ -static inline __attribute__((unused)) -char *i64toa(int64_t in) -{ - i64toa_r(in, itoa_buffer); - return itoa_buffer; -} - -/* converts uint64_t to a string using the static itoa_buffer and returns - * the pointer to that string. - */ -static inline __attribute__((unused)) -char *u64toa(uint64_t in) -{ - u64toa_r(in, itoa_buffer); - return itoa_buffer; -} - -#endif /* _NOLIBC_STDLIB_H */ diff --git a/kernel/include/klibc/string.h b/kernel/include/klibc/string.h index 04aed15..d6fa69c 100644 --- a/kernel/include/klibc/string.h +++ b/kernel/include/klibc/string.h @@ -1,231 +1,14 @@ -/* - * string function definitions for NOLIBC - * Copyright (C) 2017-2021 Willy Tarreau - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ +#ifndef _STRING_H +#define _STRING_H 1 -#ifndef _NOLIBC_STRING_H -#define _NOLIBC_STRING_H +#include -#include "std.h" +#include -/* - * As much as possible, please keep functions alphabetically sorted. - */ +int memcmp(const void*, const void*, size_t); +void* memcpy(void* __restrict, const void* __restrict, size_t); +void* memmove(void*, const void*, size_t); +void* memset(void*, int, size_t); +size_t strlen(const char*); -static __attribute__((unused)) -int memcmp(const void *s1, const void *s2, size_t n) -{ - size_t ofs = 0; - char c1 = 0; - - while (ofs < n && !(c1 = ((char *)s1)[ofs] - ((char *)s2)[ofs])) { - ofs++; - } - return c1; -} - -static __attribute__((unused)) -void *_nolibc_memcpy_up(void *dst, const void *src, size_t len) -{ - size_t pos = 0; - - while (pos < len) { - ((char *)dst)[pos] = ((const char *)src)[pos]; - pos++; - } - return dst; -} - -static __attribute__((unused)) -void *_nolibc_memcpy_down(void *dst, const void *src, size_t len) -{ - while (len) { - len--; - ((char *)dst)[len] = ((const char *)src)[len]; - } - return dst; -} - -/* might be ignored by the compiler without -ffreestanding, then found as - * missing. - */ -__attribute__((weak,unused,section(".text.nolibc_memmove"))) -void *memmove(void *dst, const void *src, size_t len) -{ - size_t dir, pos; - - pos = len; - dir = -1; - - if (dst < src) { - pos = -1; - dir = 1; - } - - while (len) { - pos += dir; - ((char *)dst)[pos] = ((const char *)src)[pos]; - len--; - } - return dst; -} - -/* must be exported, as it's used by libgcc on ARM */ -__attribute__((weak,unused,section(".text.nolibc_memcpy"))) -void *memcpy(void *dst, const void *src, size_t len) -{ - return _nolibc_memcpy_up(dst, src, len); -} - -/* might be ignored by the compiler without -ffreestanding, then found as - * missing. - */ -__attribute__((weak,unused,section(".text.nolibc_memset"))) -void *memset(void *dst, int b, size_t len) -{ - char *p = dst; - - while (len--) - *(p++) = b; - return dst; -} - -static __attribute__((unused)) -char *strchr(const char *s, int c) -{ - while (*s) { - if (*s == (char)c) - return (char *)s; - s++; - } - return NULL; -} - -static __attribute__((unused)) -char *strcpy(char *dst, const char *src) -{ - char *ret = dst; - - while ((*dst++ = *src++)); - return ret; -} - -/* this function is only used with arguments that are not constants */ -static __attribute__((unused)) -size_t nolibc_strlen(const char *str) -{ - size_t len; - - for (len = 0; str[len]; len++); - return len; -} - -#define strlen(str) ({ \ - __builtin_constant_p((str)) ? \ - __builtin_strlen((str)) : \ - nolibc_strlen((str)); \ -}) - -static __attribute__((unused)) -size_t strlcat(char *dst, const char *src, size_t size) -{ - size_t len; - char c; - - for (len = 0; dst[len]; len++) - ; - - for (;;) { - c = *src; - if (len < size) - dst[len] = c; - if (!c) - break; - len++; - src++; - } - - return len; -} - -static __attribute__((unused)) -size_t strlcpy(char *dst, const char *src, size_t size) -{ - size_t len; - char c; - - for (len = 0;;) { - c = src[len]; - if (len < size) - dst[len] = c; - if (!c) - break; - len++; - } - return len; -} - -static __attribute__((unused)) -char *strncat(char *dst, const char *src, size_t size) -{ - char *orig = dst; - - while (*dst) - dst++; - - while (size && (*dst = *src)) { - src++; - dst++; - size--; - } - - *dst = 0; - return orig; -} - - -static __attribute__((unused)) -char *strncpy(char *dst, const char *src, size_t size) -{ - size_t len; - - for (len = 0; len < size; len++) - if ((dst[len] = *src)) - src++; - return dst; -} - -static __attribute__((unused)) -char *strrchr(const char *s, int c) -{ - const char *ret = NULL; - - while (*s) { - if (*s == (char)c) - ret = s; - s++; - } - return (char *)ret; -} - -#endif /* _NOLIBC_STRING_H */ +#endif diff --git a/kernel/include/klibc/sys.h b/kernel/include/klibc/sys.h deleted file mode 100644 index 427081c..0000000 --- a/kernel/include/klibc/sys.h +++ /dev/null @@ -1,1187 +0,0 @@ -/* - * Syscall definitions for NOLIBC (those in man(2)) - * Copyright (C) 2017-2021 Willy Tarreau - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _NOLIBC_SYS_H -#define _NOLIBC_SYS_H - -#include -#include "std.h" - -/* system includes */ -#include -#include // for SIGCHLD -#include -#include -#include -#include - -#include "arch.h" -#include "errno.h" -#include "types.h" - - -/* 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 - * versions: - * - the "internal" ones, which matches the raw syscall interface at the - * kernel level, which may sometimes slightly differ from the documented - * libc-level ones. For example most of them return either a valid value - * or -errno. All of these are prefixed with "sys_". They may be called - * by non-portable applications if desired. - * - * - the "exported" ones, whose interface must closely match the one - * documented in man(2), that applications are supposed to expect. These - * ones rely on the internal ones, and set errno. - * - * Each syscall will be defined with the two functions, sorted in alphabetical - * order applied to the exported names. - * - * In case of doubt about the relevance of a function here, only those which - * set errno should be defined here. Wrappers like those appearing in man(3) - * should not be placed here. - */ - - -/* - * int brk(void *addr); - * void *sbrk(intptr_t inc) - */ - -static __attribute__((unused)) -void *sys_brk(void *addr) -{ - return (void *)my_syscall1(__NR_brk, addr); -} - -static __attribute__((unused)) -int brk(void *addr) -{ - void *ret = sys_brk(addr); - - if (!ret) { - SET_ERRNO(ENOMEM); - return -1; - } - return 0; -} - -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)) - return ret + inc; - - SET_ERRNO(ENOMEM); - return (void *)-1; -} - - -/* - * int chdir(const char *path); - */ - -static __attribute__((unused)) -int sys_chdir(const char *path) -{ - return my_syscall1(__NR_chdir, path); -} - -static __attribute__((unused)) -int chdir(const char *path) -{ - int ret = sys_chdir(path); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - - -/* - * int chmod(const char *path, mode_t mode); - */ - -static __attribute__((unused)) -int sys_chmod(const char *path, mode_t mode) -{ -#ifdef __NR_fchmodat - return my_syscall4(__NR_fchmodat, AT_FDCWD, path, mode, 0); -#elif defined(__NR_chmod) - return my_syscall2(__NR_chmod, path, mode); -#else -#error Neither __NR_fchmodat nor __NR_chmod defined, cannot implement sys_chmod() -#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; -} - - -/* - * int chown(const char *path, uid_t owner, gid_t group); - */ - -static __attribute__((unused)) -int sys_chown(const char *path, uid_t owner, gid_t group) -{ -#ifdef __NR_fchownat - return my_syscall5(__NR_fchownat, AT_FDCWD, path, owner, group, 0); -#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() -#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; -} - - -/* - * int chroot(const char *path); - */ - -static __attribute__((unused)) -int sys_chroot(const char *path) -{ - return my_syscall1(__NR_chroot, path); -} - -static __attribute__((unused)) -int chroot(const char *path) -{ - int ret = sys_chroot(path); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - - -/* - * int close(int fd); - */ - -static __attribute__((unused)) -int sys_close(int fd) -{ - return my_syscall1(__NR_close, fd); -} - -static __attribute__((unused)) -int close(int fd) -{ - int ret = sys_close(fd); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - - -/* - * int dup(int fd); - */ - -static __attribute__((unused)) -int sys_dup(int fd) -{ - return my_syscall1(__NR_dup, fd); -} - -static __attribute__((unused)) -int dup(int fd) -{ - int ret = sys_dup(fd); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - - -/* - * int dup2(int old, int new); - */ - -static __attribute__((unused)) -int sys_dup2(int old, int new) -{ -#ifdef __NR_dup3 - return my_syscall3(__NR_dup3, old, new, 0); -#elif defined(__NR_dup2) - return my_syscall2(__NR_dup2, old, new); -#else -#error Neither __NR_dup3 nor __NR_dup2 defined, cannot implement sys_dup2() -#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; -} - - -/* - * int dup3(int old, int new, int flags); - */ - -#ifdef __NR_dup3 -static __attribute__((unused)) -int sys_dup3(int old, int new, int flags) -{ - return my_syscall3(__NR_dup3, old, new, 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; -} -#endif - - -/* - * int execve(const char *filename, char *const argv[], char *const envp[]); - */ - -static __attribute__((unused)) -int sys_execve(const char *filename, char *const argv[], char *const envp[]) -{ - return my_syscall3(__NR_execve, filename, argv, 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; -} - - -/* - * void exit(int status); - */ - -static __attribute__((noreturn,unused)) -void sys_exit(int status) -{ - my_syscall1(__NR_exit, status & 255); - while(1); // shut the "noreturn" warnings. -} - -static __attribute__((noreturn,unused)) -void exit(int status) -{ - sys_exit(status); -} - - -/* - * pid_t fork(void); - */ - -static __attribute__((unused)) -pid_t sys_fork(void) -{ -#ifdef __NR_clone - /* note: some archs only have clone() and not fork(). Different archs - * have a different API, but most archs have the flags on first arg and - * will not use the rest with no other flag. - */ - return my_syscall5(__NR_clone, SIGCHLD, 0, 0, 0, 0); -#elif defined(__NR_fork) - return my_syscall0(__NR_fork); -#else -#error Neither __NR_clone nor __NR_fork defined, cannot implement sys_fork() -#endif -} - -static __attribute__((unused)) -pid_t fork(void) -{ - pid_t ret = sys_fork(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - - -/* - * int fsync(int fd); - */ - -static __attribute__((unused)) -int sys_fsync(int fd) -{ - return my_syscall1(__NR_fsync, fd); -} - -static __attribute__((unused)) -int fsync(int fd) -{ - int ret = sys_fsync(fd); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - - -/* - * int getdents64(int fd, struct linux_dirent64 *dirp, int count); - */ - -static __attribute__((unused)) -int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) -{ - return my_syscall3(__NR_getdents64, fd, dirp, 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; -} - - -/* - * pid_t getpgid(pid_t pid); - */ - -static __attribute__((unused)) -pid_t sys_getpgid(pid_t pid) -{ - return my_syscall1(__NR_getpgid, 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; -} - - -/* - * pid_t getpgrp(void); - */ - -static __attribute__((unused)) -pid_t sys_getpgrp(void) -{ - return sys_getpgid(0); -} - -static __attribute__((unused)) -pid_t getpgrp(void) -{ - return sys_getpgrp(); -} - - -/* - * pid_t getpid(void); - */ - -static __attribute__((unused)) -pid_t sys_getpid(void) -{ - return my_syscall0(__NR_getpid); -} - -static __attribute__((unused)) -pid_t getpid(void) -{ - return sys_getpid(); -} - - -/* - * pid_t gettid(void); - */ - -static __attribute__((unused)) -pid_t sys_gettid(void) -{ - return my_syscall0(__NR_gettid); -} - -static __attribute__((unused)) -pid_t gettid(void) -{ - return sys_gettid(); -} - - -/* - * int gettimeofday(struct timeval *tv, struct timezone *tz); - */ - -static __attribute__((unused)) -int sys_gettimeofday(struct timeval *tv, struct timezone *tz) -{ - return my_syscall2(__NR_gettimeofday, tv, tz); -} - -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; -} - - -/* - * int ioctl(int fd, unsigned long req, void *value); - */ - -static __attribute__((unused)) -int sys_ioctl(int fd, unsigned long req, void *value) -{ - return my_syscall3(__NR_ioctl, fd, req, 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; -} - -/* - * int kill(pid_t pid, int signal); - */ - -static __attribute__((unused)) -int sys_kill(pid_t pid, int signal) -{ - return my_syscall2(__NR_kill, pid, 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; -} - - -/* - * int link(const char *old, const char *new); - */ - -static __attribute__((unused)) -int sys_link(const char *old, const char *new) -{ -#ifdef __NR_linkat - return my_syscall5(__NR_linkat, AT_FDCWD, old, AT_FDCWD, new, 0); -#elif defined(__NR_link) - return my_syscall2(__NR_link, old, new); -#else -#error Neither __NR_linkat nor __NR_link defined, cannot implement sys_link() -#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; -} - - -/* - * off_t lseek(int fd, off_t offset, int whence); - */ - -static __attribute__((unused)) -off_t sys_lseek(int fd, off_t offset, int whence) -{ - return my_syscall3(__NR_lseek, fd, offset, whence); -} - -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; -} - - -/* - * int mkdir(const char *path, mode_t mode); - */ - -static __attribute__((unused)) -int sys_mkdir(const char *path, mode_t mode) -{ -#ifdef __NR_mkdirat - return my_syscall3(__NR_mkdirat, AT_FDCWD, path, 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() -#endif -} - -static __attribute__((unused)) -int mkdir(const char *path, mode_t mode) -{ - int ret = sys_mkdir(path, mode); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - - -/* - * int mknod(const char *path, mode_t mode, dev_t dev); - */ - -static __attribute__((unused)) -long sys_mknod(const char *path, mode_t mode, dev_t dev) -{ -#ifdef __NR_mknodat - return my_syscall4(__NR_mknodat, AT_FDCWD, path, mode, 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() -#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; -} - - -/* - * int mount(const char *source, const char *target, - * const char *fstype, unsigned long flags, - * const void *data); - */ -static __attribute__((unused)) -int sys_mount(const char *src, const char *tgt, const char *fst, - unsigned long flags, const void *data) -{ - return my_syscall5(__NR_mount, src, tgt, fst, flags, data); -} - -static __attribute__((unused)) -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; -} - - -/* - * int open(const char *path, int flags[, mode_t mode]); - */ - -static __attribute__((unused)) -int sys_open(const char *path, int flags, mode_t mode) -{ -#ifdef __NR_openat - return my_syscall4(__NR_openat, AT_FDCWD, path, flags, 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() -#endif -} - -static __attribute__((unused)) -int open(const char *path, int flags, ...) -{ - mode_t mode = 0; - int ret; - - if (flags & O_CREAT) { - va_list args; - - va_start(args, flags); - mode = va_arg(args, mode_t); - va_end(args); - } - - ret = sys_open(path, flags, mode); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - - -/* - * int pivot_root(const char *new, const char *old); - */ - -static __attribute__((unused)) -int sys_pivot_root(const char *new, const char *old) -{ - return my_syscall2(__NR_pivot_root, new, 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; -} - - -/* - * int poll(struct pollfd *fds, int nfds, int timeout); - */ - -static __attribute__((unused)) -int sys_poll(struct pollfd *fds, int nfds, int timeout) -{ -#if defined(__NR_ppoll) - struct timespec t; - - if (timeout >= 0) { - t.tv_sec = timeout / 1000; - t.tv_nsec = (timeout % 1000) * 1000000; - } - return my_syscall4(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL); -#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() -#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; -} - - -/* - * ssize_t read(int fd, void *buf, size_t count); - */ - -static __attribute__((unused)) -ssize_t sys_read(int fd, void *buf, size_t count) -{ - return my_syscall3(__NR_read, fd, buf, 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; -} - - -/* - * int reboot(int cmd); - * is among LINUX_REBOOT_CMD_* - */ - -static __attribute__((unused)) -ssize_t sys_reboot(int magic1, int magic2, int cmd, void *arg) -{ - return my_syscall4(__NR_reboot, magic1, magic2, cmd, 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; -} - - -/* - * int sched_yield(void); - */ - -static __attribute__((unused)) -int sys_sched_yield(void) -{ - return my_syscall0(__NR_sched_yield); -} - -static __attribute__((unused)) -int sched_yield(void) -{ - int ret = sys_sched_yield(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - - -/* - * int select(int nfds, fd_set *read_fds, fd_set *write_fds, - * fd_set *except_fds, struct timeval *timeout); - */ - -static __attribute__((unused)) -int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) -{ -#if defined(__ARCH_WANT_SYS_OLD_SELECT) && !defined(__NR__newselect) - struct sel_arg_struct { - unsigned long n; - fd_set *r, *w, *e; - struct timeval *t; - } arg = { .n = nfds, .r = rfds, .w = wfds, .e = efds, .t = timeout }; - return my_syscall1(__NR_select, &arg); -#elif defined(__ARCH_WANT_SYS_PSELECT6) && defined(__NR_pselect6) - struct timespec t; - - if (timeout) { - t.tv_sec = timeout->tv_sec; - t.tv_nsec = timeout->tv_usec * 1000; - } - return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL); -#elif defined(__NR__newselect) || defined(__NR_select) -#ifndef __NR__newselect -#define __NR__newselect __NR_select -#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() -#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; -} - - -/* - * int setpgid(pid_t pid, pid_t pgid); - */ - -static __attribute__((unused)) -int sys_setpgid(pid_t pid, pid_t pgid) -{ - return my_syscall2(__NR_setpgid, pid, 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; -} - - -/* - * pid_t setsid(void); - */ - -static __attribute__((unused)) -pid_t sys_setsid(void) -{ - return my_syscall0(__NR_setsid); -} - -static __attribute__((unused)) -pid_t setsid(void) -{ - pid_t ret = sys_setsid(); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - - -/* - * int stat(const char *path, struct stat *buf); - * Warning: the struct stat's layout is arch-dependent. - */ - -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_atime = stat.st_atime; - buf->st_mtime = stat.st_mtime; - buf->st_ctime = stat.st_ctime; - return ret; -} - -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; -} - - -/* - * int symlink(const char *old, const char *new); - */ - -static __attribute__((unused)) -int sys_symlink(const char *old, const char *new) -{ -#ifdef __NR_symlinkat - return my_syscall3(__NR_symlinkat, old, AT_FDCWD, 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() -#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; -} - - -/* - * mode_t umask(mode_t mode); - */ - -static __attribute__((unused)) -mode_t sys_umask(mode_t mode) -{ - return my_syscall1(__NR_umask, mode); -} - -static __attribute__((unused)) -mode_t umask(mode_t mode) -{ - return sys_umask(mode); -} - - -/* - * int umount2(const char *path, int flags); - */ - -static __attribute__((unused)) -int sys_umount2(const char *path, int flags) -{ - return my_syscall2(__NR_umount2, path, 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; -} - - -/* - * int unlink(const char *path); - */ - -static __attribute__((unused)) -int sys_unlink(const char *path) -{ -#ifdef __NR_unlinkat - return my_syscall3(__NR_unlinkat, AT_FDCWD, path, 0); -#elif defined(__NR_unlink) - return my_syscall1(__NR_unlink, path); -#else -#error Neither __NR_unlinkat nor __NR_unlink defined, cannot implement sys_unlink() -#endif -} - -static __attribute__((unused)) -int unlink(const char *path) -{ - int ret = sys_unlink(path); - - if (ret < 0) { - SET_ERRNO(-ret); - ret = -1; - } - return ret; -} - - -/* - * pid_t wait(int *status); - * pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage); - * pid_t waitpid(pid_t pid, int *status, int options); - */ - -static __attribute__((unused)) -pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage) -{ - return my_syscall4(__NR_wait4, pid, status, options, rusage); -} - -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; -} - -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; -} - - -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; -} - - -/* - * ssize_t write(int fd, const void *buf, size_t count); - */ - -static __attribute__((unused)) -ssize_t sys_write(int fd, const void *buf, size_t count) -{ - return my_syscall3(__NR_write, fd, buf, 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; -} - - -#endif /* _NOLIBC_SYS_H */ diff --git a/kernel/include/klibc/sys/cdefs.h b/kernel/include/klibc/sys/cdefs.h new file mode 100644 index 0000000..5f17cc3 --- /dev/null +++ b/kernel/include/klibc/sys/cdefs.h @@ -0,0 +1,6 @@ +#ifndef _SYS_CDEFS_H +#define _SYS_CDEFS_H 1 + +#define __cow_libc 1 + +#endif diff --git a/kernel/include/klibc/time.h b/kernel/include/klibc/time.h deleted file mode 100644 index 2cf3d84..0000000 --- a/kernel/include/klibc/time.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * time function definitions for NOLIBC - * Copyright (C) 2017-2022 Willy Tarreau - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _NOLIBC_TIME_H -#define _NOLIBC_TIME_H - -#include "std.h" -#include "arch.h" -#include "types.h" -#include "sys.h" - -static __attribute__((unused)) -time_t time(time_t *tptr) -{ - struct timeval tv; - - /* note, cannot fail here */ - sys_gettimeofday(&tv, NULL); - - if (tptr) - *tptr = tv.tv_sec; - return tv.tv_sec; -} - -#endif /* _NOLIBC_TIME_H */ diff --git a/kernel/include/klibc/types.h b/kernel/include/klibc/types.h deleted file mode 100644 index c44e4a7..0000000 --- a/kernel/include/klibc/types.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Special types used by various syscalls for NOLIBC - * Copyright (C) 2017-2021 Willy Tarreau - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _NOLIBC_TYPES_H -#define _NOLIBC_TYPES_H - -#include "std.h" -#include - - -/* 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. - */ - -/* stat flags (WARNING, octal here) */ -#define S_IFDIR 0040000 -#define S_IFCHR 0020000 -#define S_IFBLK 0060000 -#define S_IFREG 0100000 -#define S_IFIFO 0010000 -#define S_IFLNK 0120000 -#define S_IFSOCK 0140000 -#define S_IFMT 0170000 - -#define S_ISDIR(mode) (((mode) & S_IFDIR) == S_IFDIR) -#define S_ISCHR(mode) (((mode) & S_IFCHR) == S_IFCHR) -#define S_ISBLK(mode) (((mode) & S_IFBLK) == S_IFBLK) -#define S_ISREG(mode) (((mode) & S_IFREG) == S_IFREG) -#define S_ISFIFO(mode) (((mode) & S_IFIFO) == S_IFIFO) -#define S_ISLNK(mode) (((mode) & S_IFLNK) == S_IFLNK) -#define S_ISSOCK(mode) (((mode) & S_IFSOCK) == S_IFSOCK) - -/* dirent types */ -#define DT_UNKNOWN 0x0 -#define DT_FIFO 0x1 -#define DT_CHR 0x2 -#define DT_DIR 0x4 -#define DT_BLK 0x6 -#define DT_REG 0x8 -#define DT_LNK 0xa -#define DT_SOCK 0xc - -/* commonly an fd_set represents 256 FDs */ -#ifndef FD_SETSIZE -#define FD_SETSIZE 256 -#endif - -/* PATH_MAX and MAXPATHLEN are often used and found with plenty of different - * values. - */ -#ifndef PATH_MAX -#define PATH_MAX 4096 -#endif - -#ifndef MAXPATHLEN -#define MAXPATHLEN (PATH_MAX) -#endif - -/* Special FD used by all the *at functions */ -#ifndef AT_FDCWD -#define AT_FDCWD (-100) -#endif - -/* whence values for lseek() */ -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 - -/* cmd for reboot() */ -#define LINUX_REBOOT_MAGIC1 0xfee1dead -#define LINUX_REBOOT_MAGIC2 0x28121969 -#define LINUX_REBOOT_CMD_HALT 0xcdef0123 -#define LINUX_REBOOT_CMD_POWER_OFF 0x4321fedc -#define LINUX_REBOOT_CMD_RESTART 0x01234567 -#define LINUX_REBOOT_CMD_SW_SUSPEND 0xd000fce2 - -/* Macros used on waitpid()'s return status */ -#define WEXITSTATUS(status) (((status) & 0xff00) >> 8) -#define WIFEXITED(status) (((status) & 0x7f) == 0) - -/* standard exit() codes */ -#define EXIT_SUCCESS 0 -#define EXIT_FAILURE 1 - -/* for select() */ -typedef struct { - uint32_t fd32[(FD_SETSIZE + 31) / 32]; -} fd_set; - -#define FD_CLR(fd, set) do { \ - fd_set *__set = (set); \ - int __fd = (fd); \ - if (__fd >= 0) \ - __set->fd32[__fd / 32] &= ~(1U << (__fd & 31)); \ - } while (0) - -#define FD_SET(fd, set) do { \ - fd_set *__set = (set); \ - int __fd = (fd); \ - if (__fd >= 0) \ - __set->fd32[__fd / 32] |= 1U << (__fd & 31); \ - } while (0) - -#define FD_ISSET(fd, set) ({ \ - fd_set *__set = (set); \ - int __fd = (fd); \ - int __r = 0; \ - if (__fd >= 0) \ - __r = !!(__set->fd32[__fd / 32] & 1U << (__fd & 31)); \ - __r; \ - }) - -#define FD_ZERO(set) do { \ - fd_set *__set = (set); \ - int __idx; \ - for (__idx = 0; __idx < (FD_SETSIZE+31) / 32; __idx ++) \ - __set->fd32[__idx] = 0; \ - } while (0) - -/* for poll() */ -struct pollfd { - int fd; - short int events; - short int revents; -}; - -/* for getdents64() */ -struct linux_dirent64 { - uint64_t d_ino; - int64_t d_off; - unsigned short d_reclen; - unsigned char d_type; - char d_name[]; -}; - -/* needed by wait4() */ -struct rusage { - struct timeval ru_utime; - struct timeval ru_stime; - long ru_maxrss; - long ru_ixrss; - long ru_idrss; - long ru_isrss; - long ru_minflt; - long ru_majflt; - long ru_nswap; - long ru_inblock; - long ru_oublock; - long ru_msgsnd; - long ru_msgrcv; - long ru_nsignals; - long ru_nvcsw; - long ru_nivcsw; -}; - -/* The format of the struct as returned by the libc to the application, which - * significantly differs from the format returned by the stat() syscall flavours. - */ -struct stat { - dev_t st_dev; /* ID of device containing file */ - ino_t st_ino; /* inode number */ - mode_t st_mode; /* protection */ - nlink_t st_nlink; /* number of hard links */ - uid_t st_uid; /* user ID of owner */ - gid_t st_gid; /* group ID of owner */ - dev_t st_rdev; /* device ID (if special file) */ - off_t st_size; /* total size, in bytes */ - blksize_t st_blksize; /* blocksize for file system I/O */ - blkcnt_t st_blocks; /* number of 512B blocks allocated */ - time_t st_atime; /* time of last access */ - time_t st_mtime; /* time of last modification */ - time_t st_ctime; /* time of last status change */ -}; - -/* WARNING, it only deals with the 4096 first majors and 256 first minors */ -#define makedev(major, minor) ((dev_t)((((major) & 0xfff) << 8) | ((minor) & 0xff))) -#define major(dev) ((unsigned int)(((dev) >> 8) & 0xfff)) -#define minor(dev) ((unsigned int)(((dev) & 0xff)) - -#endif /* _NOLIBC_TYPES_H */ diff --git a/kernel/include/klibc/unistd.h b/kernel/include/klibc/unistd.h deleted file mode 100644 index ad83159..0000000 --- a/kernel/include/klibc/unistd.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * unistd function definitions for NOLIBC - * Copyright (C) 2017-2022 Willy Tarreau - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _NOLIBC_UNISTD_H -#define _NOLIBC_UNISTD_H - -#include "std.h" -#include "arch.h" -#include "types.h" -#include "sys.h" - - -static __attribute__((unused)) -int msleep(unsigned int msecs) -{ - struct timeval my_timeval = { msecs / 1000, (msecs % 1000) * 1000 }; - - if (sys_select(0, 0, 0, 0, &my_timeval) < 0) - return (my_timeval.tv_sec * 1000) + - (my_timeval.tv_usec / 1000) + - !!(my_timeval.tv_usec % 1000); - else - return 0; -} - -static __attribute__((unused)) -unsigned int sleep(unsigned int seconds) -{ - struct timeval my_timeval = { seconds, 0 }; - - if (sys_select(0, 0, 0, 0, &my_timeval) < 0) - return my_timeval.tv_sec + !!my_timeval.tv_usec; - else - return 0; -} - -static __attribute__((unused)) -int usleep(unsigned int usecs) -{ - struct timeval my_timeval = { usecs / 1000000, usecs % 1000000 }; - - return sys_select(0, 0, 0, 0, &my_timeval); -} - -static __attribute__((unused)) -int tcsetpgrp(int fd, pid_t pid) -{ - return ioctl(fd, TIOCSPGRP, &pid); -} - -#endif /* _NOLIBC_UNISTD_H */ diff --git a/kernel/klibc/stdio.c b/kernel/klibc/stdio.c new file mode 100644 index 0000000..f6ae5ad --- /dev/null +++ b/kernel/klibc/stdio.c @@ -0,0 +1,100 @@ +#include +#include +/* #include */ +#include +#include + +/* returns 1 for true, adhering to suckless */ +static int +print(const char* data, size_t length) +{ + const unsigned char* bytes = (const unsigned char*) data; + for (size_t i = 0; i < length; i++) { + if (putchar(bytes[i]) == EOF) { + return 0; + } + } + return 1; +} + +/* todo: set errno to eoverflow for some cases in which errno should not be used */ +int +printf(const char* restrict format, ...) +{ + va_list parameters; + va_start(parameters, format); + + int written = 0; + + while (*format != '\0') { + size_t maxrem = INT_MAX - written; + + if (format[0] != '%' || format[1] == '%') { + if (format[0] == '%') + format++; + size_t amount = 1; + while (format[amount] && format[amount] != '%') + amount++; + if (maxrem < amount) { + return -1; + } + if (!print(format, amount)) + return -1; + format += amount; + written += amount; + continue; + } + + const char* format_begun_at = format++; + + if (*format == 'c') { + format++; + char c = (char) va_arg(parameters, int /* char promotes to int */); + if (!maxrem) { + return -1; + } + if (!print(&c, sizeof(c))) { + return -1; + } + written++; + } else if (*format == 's') { + format++; + const char* str = va_arg(parameters, const char*); + size_t len = strlen(str); + if (maxrem < len) { + return -1; + } + if (!print(str, len)) { + return -1; + } + written += len; + } else { + format = format_begun_at; + size_t len = strlen(format); + if (maxrem < len) { + return -1; + } + if (!print(format, len)) { + return -1; + } + written += len; + format += len; + } + } + + va_end(parameters); + return written; +} + +/* todo: Implement stdio and the write system call. */ +int +putchar(int ic) +{ + return ic; +} + +int +puts(const char* string) +{ + return printf("%s\n", string); +} diff --git a/kernel/klibc/string.c b/kernel/klibc/string.c new file mode 100644 index 0000000..b512017 --- /dev/null +++ b/kernel/klibc/string.c @@ -0,0 +1,62 @@ +#include + +size_t +strlen(const char* str) +{ + size_t len = 0; + while (str[len]) { + len++; + } + return len; +} + +void* +memset(void* bufptr, int value, size_t size) +{ + unsigned char* buf = (unsigned char*) bufptr; + for (size_t i = 0; i < size; i++) { + buf[i] = (unsigned char) value; + } + return bufptr; +} + +void* +memmove(void* dstptr, const void* srcptr, size_t size) +{ + unsigned char* dst = (unsigned char*) dstptr; + const unsigned char* src = (const unsigned char*) srcptr; + if (dst < src) { + for (size_t i = 0; i < size; i++) + dst[i] = src[i]; + } else { + for (size_t i = size; i != 0; i--) + dst[i-1] = src[i-1]; + } + return dstptr; +} + +void* +memcpy(void* restrict dstptr, const void* restrict srcptr, size_t size) +{ + unsigned char* dst = (unsigned char*) dstptr; + const unsigned char* src = (const unsigned char*) srcptr; + for (size_t i = 0; i < size; i++) { + dst[i] = src[i]; + } + return dstptr; +} + +int +memcmp(const void* aptr, const void* bptr, size_t size) +{ + const unsigned char* a = (const unsigned char*) aptr; + const unsigned char* b = (const unsigned char*) bptr; + for (size_t i = 0; i < size; i++) { + if (a[i] < b[i]) { + return -1; + } else if (b[i] < a[i]) { + return 1; + } + } + return 0; +}