cowos uses it's own cowlibc! big W

This commit is contained in:
cowmonk 2025-05-28 18:58:30 -07:00
parent 435b2bf2a0
commit b08b0728ae
18 changed files with 188 additions and 3050 deletions

View file

@ -14,7 +14,7 @@ iso: kernel limine
kernel: kernel:
make -C ./kernel/ all make -C ./kernel/ all
limine: limine: kernel
git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1 git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1
make -C limine make -C limine
@ -26,3 +26,4 @@ limine:
clean: clean:
rm cowos.iso rm cowos.iso
make -C ./kernel/ clean

View file

@ -23,5 +23,4 @@ make
``` ```
# Credits # 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. - [Limine](https://github.com/limine-bootloader/limine): modern, advanced, portable, multiprotocol bootloader and boot manager.

View file

@ -1,235 +0,0 @@
/*
* x86_64 specific definitions for NOLIBC
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
*
* 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

View file

@ -1,118 +0,0 @@
/*
* ctype function definitions for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*
* 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 */

View file

@ -1,46 +0,0 @@
/*
* Minimal errno definitions for NOLIBC
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
*
* 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 <asm/errno.h>
/* 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 */

View file

@ -1,130 +0,0 @@
/*
* Copyright (C) 2017-2018 Willy Tarreau <w@1wt.eu>
*
* 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_<name>() 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_<name>() 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 */

View file

@ -1,41 +0,0 @@
/*
* signal function definitions for NOLIBC
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
*
* 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 */

View file

@ -1,68 +0,0 @@
/*
* Standard definitions and types for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*
* 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 */

View file

@ -1,325 +1,13 @@
/* #ifndef _STDIO_H
* minimal stdio function definitions for NOLIBC #define _STDIO_H 1
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*
* 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_STDIO_H #include <klibc/sys/cdefs.h>
#define _NOLIBC_STDIO_H
#include <stdarg.h>
#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) #define EOF (-1)
int printf(const char* __restrict, ...);
int putchar(int);
int puts(const char*);
#endif #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 */

View file

@ -1,353 +0,0 @@
/*
* stdlib function definitions for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*
* 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 <name> 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 <in> to its hex representation into
* buffer <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 <in> 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 <in> to its string representation into
* buffer <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 <in> to its string representation into
* buffer <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 <in> 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 <in> 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 <in> 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 <in> to its hex representation into
* buffer <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 <in> 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 <in> to its string representation into
* buffer <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 <in> to its string representation into
* buffer <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 <in> 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 <in> 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 */

View file

@ -1,231 +1,14 @@
/* #ifndef _STRING_H
* string function definitions for NOLIBC #define _STRING_H 1
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*
* 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_STRING_H #include <klibc/sys/cdefs.h>
#define _NOLIBC_STRING_H
#include "std.h" #include <stddef.h>
/* int memcmp(const void*, const void*, size_t);
* As much as possible, please keep functions alphabetically sorted. 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)) #endif
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 */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,6 @@
#ifndef _SYS_CDEFS_H
#define _SYS_CDEFS_H 1
#define __cow_libc 1
#endif

View file

@ -1,47 +0,0 @@
/*
* time function definitions for NOLIBC
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
*
* 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 */

View file

@ -1,203 +0,0 @@
/*
* Special types used by various syscalls for NOLIBC
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
*
* 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 <linux/time.h>
/* Only the generic macros and types may be defined here. The arch-specific
* ones such as the O_RDONLY and related macros used by fcntl() and open(), or
* the layout of sys_stat_struct must not be defined here.
*/
/* 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 */

View file

@ -1,73 +0,0 @@
/*
* unistd function definitions for NOLIBC
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
*
* 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 */

100
kernel/klibc/stdio.c Normal file
View file

@ -0,0 +1,100 @@
#include <limits.h>
#include <stdarg.h>
/* #include <tty.h> */
#include <klibc/stdio.h>
#include <klibc/string.h>
/* 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);
}

62
kernel/klibc/string.c Normal file
View file

@ -0,0 +1,62 @@
#include <string.h>
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;
}