From babc65305d37b396c8872cffddb7bb9b76c12545 Mon Sep 17 00:00:00 2001 From: cowmonk Date: Fri, 23 May 2025 17:24:25 -0700 Subject: [PATCH] cowos moves to 64bit! and framebuffers too ig --- .gitignore | 8 + Makefile | 28 + README.md | 38 +- isodir/boot/cowos | Bin 0 -> 27704 bytes isodir/boot/grub/grub.cfg | 3 - kernel/Makefile | 58 ++ kernel/arch/i386/boot.s | 72 -- kernel/arch/i386/linker.ld | 25 - kernel/drivers/video/vga.c | 6 + kernel/drivers/video/vga.o | Bin 0 -> 19368 bytes kernel/include/bootloader.h | 21 + kernel/include/drivers/video/vga.h | 4 +- kernel/include/fb.h | 22 + 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 | 325 ++++++++ kernel/include/klibc/stdlib.h | 353 +++++++++ kernel/include/klibc/string.h | 231 ++++++ kernel/include/klibc/sys.h | 1187 ++++++++++++++++++++++++++++ kernel/include/klibc/time.h | 47 ++ kernel/include/klibc/types.h | 203 +++++ kernel/include/klibc/unistd.h | 73 ++ kernel/include/lib/string.h | 8 - kernel/include/limine.h | 754 ++++++++++++++++++ kernel/init/kernel.c | 37 +- kernel/init/kernel.o | Bin 0 -> 10968 bytes kernel/lib/string.c | 11 - kernel/linker.ld | 68 ++ 32 files changed, 4074 insertions(+), 146 deletions(-) create mode 100644 .gitignore create mode 100644 Makefile create mode 100755 isodir/boot/cowos delete mode 100644 isodir/boot/grub/grub.cfg create mode 100644 kernel/Makefile delete mode 100644 kernel/arch/i386/boot.s delete mode 100644 kernel/arch/i386/linker.ld create mode 100644 kernel/drivers/video/vga.o create mode 100644 kernel/include/bootloader.h create mode 100644 kernel/include/fb.h create mode 100644 kernel/include/klibc/arch.h create mode 100644 kernel/include/klibc/ctype.h create mode 100644 kernel/include/klibc/errno.h create mode 100644 kernel/include/klibc/nolibc.h create mode 100644 kernel/include/klibc/signal.h create mode 100644 kernel/include/klibc/std.h create mode 100644 kernel/include/klibc/stdio.h create mode 100644 kernel/include/klibc/stdlib.h create mode 100644 kernel/include/klibc/string.h create mode 100644 kernel/include/klibc/sys.h create mode 100644 kernel/include/klibc/time.h create mode 100644 kernel/include/klibc/types.h create mode 100644 kernel/include/klibc/unistd.h delete mode 100644 kernel/include/lib/string.h create mode 100644 kernel/include/limine.h create mode 100644 kernel/init/kernel.o delete mode 100644 kernel/lib/string.c create mode 100644 kernel/linker.ld diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0b78f32 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +cowos.iso +kernel/bin/ +limine/ +isodir/boot/limine/limine-bios.sys +isodir/boot/limine/limine-bios-cd.bin +isodir/boot/limine/limine-uefi-cd.bin +isodir/EFI/BOOT/BOOTX64.EFI +isodir/EFI/BOOT/BOOTIA32.EFI diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b99e058 --- /dev/null +++ b/Makefile @@ -0,0 +1,28 @@ +all: iso + +iso: kernel limine + cp -v ./kernel/bin/cowos ./isodir/boot/ + + xorriso -as mkisofs -R -r -J -b boot/limine/limine-bios-cd.bin \ + -no-emul-boot -boot-load-size 4 -boot-info-table -hfsplus \ + -apm-block-size 2048 --efi-boot boot/limine/limine-uefi-cd.bin \ + -efi-boot-part --efi-boot-image --protective-msdos-label \ + isodir -o cowos.iso + + ./limine/limine bios-install cowos.iso + +kernel: + make -C ./kernel/ all + +limine: + git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1 + make -C limine + + cp -v limine/limine-bios.sys limine/limine-bios-cd.bin \ + limine/limine-uefi-cd.bin isodir/boot/limine/ + + cp -v limine/BOOTX64.EFI isodir/EFI/BOOT/ + cp -v limine/BOOTIA32.EFI isodir/EFI/BOOT/ + +clean: + rm cowos.iso diff --git a/README.md b/README.md index 3134cb0..6429cac 100644 --- a/README.md +++ b/README.md @@ -4,30 +4,24 @@ Custom OS from scratch in C # Notes -This only supports 32bit for now, please DO NOT compile with 64bit or it'll fail to boot +**Heavily UNDER DEVELOPMENT** -## compilation of any component -You are required to get your own cross C compiler. This is because normal C compilers for your Linux distro (assuming that you are on Linux) will optimize against your own libs and other things. This OS doesn't exist yet, so this is a big no no in OS development. Another thing is that you want to compile for 32 bit, so you'll need to cross compile anyways... +Currently just boots and well, does nothing lol. -### general c files +## BUILDING +You'll need a few things: +- LLVM/Clang (default C compiler) +- LLD (linker) +- xorriso (iso creation) +- git +- make +- qemu (for virtual machine) + +After acquiring those just run make and it'll do everything for you: ```bash -i386-elf-gcc -c kernel.c -o kernel.o -std=c99 -ffreestanding -O2 -Wall -Wextra # i386 is the 32 bit version of x86 -# also please compile with the -Iinclude flag to include the libraries like string.h in the arch +make ``` -### "compiling" the "boot stub" -```bash -i386-elf-as boot.s -o boot.o -``` - -### linking the "compiled" boot stub w/compiled kernel img -``` -i386-elf-gcc -T linker.ld -o cowos.bin -ffreestanding -O2 -nostdlib boot.o kernel.o -``` - -## Getting it bootable -You'll need grub and mtools. First move the compiled cowos.bin to isodir/boot. Then run the following command: -```bash -grub-mkrescue isodir/ -o cowos.iso -``` -Now you can enjoy running this in qemu lol. +# 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/isodir/boot/cowos b/isodir/boot/cowos new file mode 100755 index 0000000000000000000000000000000000000000..1fab62a7c079e0893d27b8a2ef3b39eed128bbc6 GIT binary patch literal 27704 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 literal 0 HcmV?d00001 diff --git a/isodir/boot/grub/grub.cfg b/isodir/boot/grub/grub.cfg deleted file mode 100644 index 74fa80f..0000000 --- a/isodir/boot/grub/grub.cfg +++ /dev/null @@ -1,3 +0,0 @@ -menuentry "cowos" { - multiboot /boot/kernel.elf -} diff --git a/kernel/Makefile b/kernel/Makefile new file mode 100644 index 0000000..48c2246 --- /dev/null +++ b/kernel/Makefile @@ -0,0 +1,58 @@ +MAKEFLAGS += -rR +.SUFFIXES: + +override OUTPUT := cowos + +CC := clang + +CFLAGS := -g -O3 -pipe + +CPPFLAGS := + +override CFLAGS += \ + -m64 -g -c -ffreestanding -Wall -Werror -fcommon -Iinclude/ -fPIE -mno-80387 \ + -mno-mmx \ + -mno-sse \ + -nostdlib \ + -mno-sse2 \ + -mno-red-zone -fno-stack-protector \ + -fno-stack-check \ + -fno-lto \ + -target x86_64-unknown-none + +override CPPFLAGS := \ + -I src \ + $(CPPFLAGS) \ + -DLIMINE_API_REVISION=3 \ + -MMD \ + -MP + +override NASMFLAGS += \ + -Wall \ + -f elf64 + +override LDFLAGS += \ + -Wl,-m,elf_x86_64 \ + -Wl,--build-id=none \ + -nostdlib \ + -static \ + -z max-page-size=0x1000 \ + -T linker.ld + +C_SOURCES = $(shell find . -name '*.c') +C_OBJS = $(patsubst %.c,%.o,$(C_SOURCES)) + +.PHONY: all +all: bin/$(OUTPUT) + +bin/$(OUTPUT): Makefile $(C_OBJS) linker.ld + mkdir ./bin/ -p + $(CC) $(LDFLAGS) -o ./bin/$(OUTPUT) $(C_OBJS) -fuse-ld=lld + +%.o: %.c + $(CC) $(CFLAGS) $(subst .o,.c,$@) -o $@ + +.PHONY: clean +clean: + find . -name '*.o' -delete + rm -r -f ./bin diff --git a/kernel/arch/i386/boot.s b/kernel/arch/i386/boot.s deleted file mode 100644 index 6091341..0000000 --- a/kernel/arch/i386/boot.s +++ /dev/null @@ -1,72 +0,0 @@ -.set ALIGN, 1<<0 /* align loaded modules on page boundaries */ -.set MEMINFO, 1<<1 /* provide memory map */ -.set FLAGS, ALIGN | MEMINFO /* Multiboot flag */ -.set MAGIC, 0x1BADB002 /* Magic number lets bootloader find the header */ -.set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot (sanity check I think) */ - -/* so this basically declares the multiboot header that defines this program as a kernel, - and the following values are in the multiboot standard. The bootloader will look for the - first 8KiB of the kernel file, aligned with the 32-bit boundary, this means that it won't - work with 64bit until I keep on learning or I create my own bootloader (without multiboot) -*/ -.section .multiboot -.align 4 -.long MAGIC -.long FLAGS -.long CHECKSUM - -/* This is where my knowledge is not high enough but here is the summary: - - esp is NOT in the multiboot standard so the kernel has to provide it. - this basically means that it doesn't define the value of the stack register - (whatever that means) - - This allocates some room for a stack by creating a symbol at the bottom of it - then allocate 16 KiB and then creating a symbol on top. - - The stack grows downwards on x86. - -And many more, apparently it's re-aligned to System-V ABI standard as well? Not sure, but hopefully I can -continue learning -*/ -.section .bss -.align 16 -stack_bottom: -.skip 16384 # 16 KiB -stack_top: - -/* linker specifies a _start as the entry point to the kernel and the bootloader will jump to the position -however it doesn't make any sense to return to this after the bootloader is gone -*/ -.section .text -.global _start -.type _start, @function -_start: - /* We are now in... no printf and other things, kernel has FULL CONTROL of the cpu. No security also lol */ - - /* To set up a stack, this sets the esp to register to the point of the stack because it grows downwards on - on x86 systems. this is done in assembly because languages like C can't function without a stack */ - mov $stack_top, %esp - - /* so we need to initialize some critical processor states before the high-level kernel is entered. - interestingly a lot of things are done at the boot level, we should load GDT, enable paging, and add runtime - support (for C++). Crazy! - */ - - /* time to enter the kernel, - according to the guide, this is a well defined call as the stack was originally 16-byte aligned, we pushed a - multiple of 16-bytes to the stack (since 0 bytes were pushed so far), so alignment has been perserved. - */ - call kernel_main - - /* If there is nothing else to do, the computer will be in an infinite loop - - Disable interrupts with cli (they wil be disabled by the bootloader) - - Wait for next interrupt to arrive with halt instruction (hlt) - - Jump to hlt instruction if it ever wakes up due to a non-maskable - interrupt occuring or due to system management mode. - */ - cli -1: hlt - jmp 1b - -/* set the size of _start symbol to the current location minus its start. -Useful for debugging or if I implement call tracing -*/ -.size _start, . - _start diff --git a/kernel/arch/i386/linker.ld b/kernel/arch/i386/linker.ld deleted file mode 100644 index b1f2eeb..0000000 --- a/kernel/arch/i386/linker.ld +++ /dev/null @@ -1,25 +0,0 @@ -ENTRY(_start) /* Entry point symbol */ - -SECTIONS { - /* Load address in memory: 2MB for kernel */ - . = 2M; - - /* Multiboot header must be in the first 8KB of the file and 32-bit aligned */ - .text BLOCK(4K) : ALIGN(4K) { - *(.multiboot) - *(.text) - } - - .rodata BLOCK(4K) : ALIGN(4K) { - *(.rodata) - } - - .data BLOCK(4K) : ALIGN(4K) { - *(.data) - } - - .bss BLOCK(4K) : ALIGN(4K) { - *(COMMON) - *(.bss) - } -} diff --git a/kernel/drivers/video/vga.c b/kernel/drivers/video/vga.c index 3edb4ca..46663b3 100644 --- a/kernel/drivers/video/vga.c +++ b/kernel/drivers/video/vga.c @@ -1,6 +1,12 @@ #include +/* #include */ #include +/* for frame buffer +static volatile struct limine_framebuffer_request limineFBreq = { + .id = LIMINE_FRAMEBUFFER_REQUEST, .revision = 0}; +*/ + size_t term_row; size_t term_col; uint8_t term_color; diff --git a/kernel/drivers/video/vga.o b/kernel/drivers/video/vga.o new file mode 100644 index 0000000000000000000000000000000000000000..c5b6030f1865773f5e702fb946992377b2ce95bb GIT binary patch literal 19368 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 + +void putpixel(int pos_x, int pos_y, unsigned char VGA_COLOR); + +#endif /* FB_H */ diff --git a/kernel/include/klibc/arch.h b/kernel/include/klibc/arch.h new file mode 100644 index 0000000..1510679 --- /dev/null +++ b/kernel/include/klibc/arch.h @@ -0,0 +1,235 @@ +/* + * 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 new file mode 100644 index 0000000..807b18d --- /dev/null +++ b/kernel/include/klibc/ctype.h @@ -0,0 +1,118 @@ +/* + * 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 new file mode 100644 index 0000000..df0e473 --- /dev/null +++ b/kernel/include/klibc/errno.h @@ -0,0 +1,46 @@ +/* + * 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 new file mode 100644 index 0000000..c8ef67e --- /dev/null +++ b/kernel/include/klibc/nolibc.h @@ -0,0 +1,130 @@ +/* + * 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 new file mode 100644 index 0000000..78109a3 --- /dev/null +++ b/kernel/include/klibc/signal.h @@ -0,0 +1,41 @@ +/* + * 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 new file mode 100644 index 0000000..fdb4d0e --- /dev/null +++ b/kernel/include/klibc/std.h @@ -0,0 +1,68 @@ +/* + * 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 new file mode 100644 index 0000000..68cb75c --- /dev/null +++ b/kernel/include/klibc/stdio.h @@ -0,0 +1,325 @@ +/* + * 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 _NOLIBC_STDIO_H +#define _NOLIBC_STDIO_H + +#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) +#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 new file mode 100644 index 0000000..d97ce7f --- /dev/null +++ b/kernel/include/klibc/stdlib.h @@ -0,0 +1,353 @@ +/* + * 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 new file mode 100644 index 0000000..04aed15 --- /dev/null +++ b/kernel/include/klibc/string.h @@ -0,0 +1,231 @@ +/* + * 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 _NOLIBC_STRING_H +#define _NOLIBC_STRING_H + +#include "std.h" + +/* + * As much as possible, please keep functions alphabetically sorted. + */ + +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 */ diff --git a/kernel/include/klibc/sys.h b/kernel/include/klibc/sys.h new file mode 100644 index 0000000..427081c --- /dev/null +++ b/kernel/include/klibc/sys.h @@ -0,0 +1,1187 @@ +/* + * 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/time.h b/kernel/include/klibc/time.h new file mode 100644 index 0000000..2cf3d84 --- /dev/null +++ b/kernel/include/klibc/time.h @@ -0,0 +1,47 @@ +/* + * 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 new file mode 100644 index 0000000..c44e4a7 --- /dev/null +++ b/kernel/include/klibc/types.h @@ -0,0 +1,203 @@ +/* + * 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 new file mode 100644 index 0000000..ad83159 --- /dev/null +++ b/kernel/include/klibc/unistd.h @@ -0,0 +1,73 @@ +/* + * 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/include/lib/string.h b/kernel/include/lib/string.h deleted file mode 100644 index 29e142c..0000000 --- a/kernel/include/lib/string.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef STRING_H -#define STRING_H - -#include - -size_t strlen(const char* str); - -#endif // STRING_H diff --git a/kernel/include/limine.h b/kernel/include/limine.h new file mode 100644 index 0000000..d1d2008 --- /dev/null +++ b/kernel/include/limine.h @@ -0,0 +1,754 @@ +/* BSD Zero Clause License */ + +/* Copyright (C) 2022-2025 Mintsuki and contributors. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef LIMINE_H +#define LIMINE_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Misc */ + +#ifdef LIMINE_NO_POINTERS +# define LIMINE_PTR(TYPE) uint64_t +#else +# define LIMINE_PTR(TYPE) TYPE +#endif + +#ifndef LIMINE_API_REVISION +# define LIMINE_API_REVISION 0 +#endif + +#if LIMINE_API_REVISION > 3 +# error "limine.h API revision unsupported" +#endif + +#ifdef __GNUC__ +# define LIMINE_DEPRECATED __attribute__((__deprecated__)) +# define LIMINE_DEPRECATED_IGNORE_START \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +# define LIMINE_DEPRECATED_IGNORE_END \ + _Pragma("GCC diagnostic pop") +#else +# define LIMINE_DEPRECATED +# define LIMINE_DEPRECATED_IGNORE_START +# define LIMINE_DEPRECATED_IGNORE_END +#endif + +#define LIMINE_REQUESTS_START_MARKER \ + uint64_t limine_requests_start_marker[4] = { 0xf6b8f4b39de7d1ae, 0xfab91a6940fcb9cf, \ + 0x785c6ed015d3e316, 0x181e920a7852b9d9 }; +#define LIMINE_REQUESTS_END_MARKER \ + uint64_t limine_requests_end_marker[2] = { 0xadc0e0531bb10d03, 0x9572709f31764c62 }; + +#define LIMINE_REQUESTS_DELIMITER LIMINE_REQUESTS_END_MARKER + +#define LIMINE_BASE_REVISION(N) \ + uint64_t limine_base_revision[3] = { 0xf9562b2d5c95a6c8, 0x6a7b384944536bdc, (N) }; + +#define LIMINE_BASE_REVISION_SUPPORTED (limine_base_revision[2] == 0) + +#define LIMINE_LOADED_BASE_REV_VALID (limine_base_revision[1] != 0x6a7b384944536bdc) +#define LIMINE_LOADED_BASE_REVISION (limine_base_revision[1]) + +#define LIMINE_COMMON_MAGIC 0xc7b1dd30df4c8b88, 0x0a82e883a194f07b + +struct limine_uuid { + uint32_t a; + uint16_t b; + uint16_t c; + uint8_t d[8]; +}; + +#define LIMINE_MEDIA_TYPE_GENERIC 0 +#define LIMINE_MEDIA_TYPE_OPTICAL 1 +#define LIMINE_MEDIA_TYPE_TFTP 2 + +struct limine_file { + uint64_t revision; + LIMINE_PTR(void *) address; + uint64_t size; + LIMINE_PTR(char *) path; +#if LIMINE_API_REVISION >= 3 + LIMINE_PTR(char *) string; +#else + LIMINE_PTR(char *) cmdline; +#endif + uint32_t media_type; + uint32_t unused; + uint32_t tftp_ip; + uint32_t tftp_port; + uint32_t partition_index; + uint32_t mbr_disk_id; + struct limine_uuid gpt_disk_uuid; + struct limine_uuid gpt_part_uuid; + struct limine_uuid part_uuid; +}; + +/* Boot info */ + +#define LIMINE_BOOTLOADER_INFO_REQUEST { LIMINE_COMMON_MAGIC, 0xf55038d8e2a1202f, 0x279426fcf5f59740 } + +struct limine_bootloader_info_response { + uint64_t revision; + LIMINE_PTR(char *) name; + LIMINE_PTR(char *) version; +}; + +struct limine_bootloader_info_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_bootloader_info_response *) response; +}; + +/* Executable command line */ + +#define LIMINE_EXECUTABLE_CMDLINE_REQUEST { LIMINE_COMMON_MAGIC, 0x4b161536e598651e, 0xb390ad4a2f1f303a } + +struct limine_executable_cmdline_response { + uint64_t revision; + LIMINE_PTR(char *) cmdline; +}; + +struct limine_executable_cmdline_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_executable_cmdline_response *) response; +}; + +/* Firmware type */ + +#define LIMINE_FIRMWARE_TYPE_REQUEST { LIMINE_COMMON_MAGIC, 0x8c2f75d90bef28a8, 0x7045a4688eac00c3 } + +#define LIMINE_FIRMWARE_TYPE_X86BIOS 0 +#define LIMINE_FIRMWARE_TYPE_UEFI32 1 +#define LIMINE_FIRMWARE_TYPE_UEFI64 2 +#define LIMINE_FIRMWARE_TYPE_SBI 3 + +struct limine_firmware_type_response { + uint64_t revision; + uint64_t firmware_type; +}; + +struct limine_firmware_type_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_firmware_type_response *) response; +}; + +/* Stack size */ + +#define LIMINE_STACK_SIZE_REQUEST { LIMINE_COMMON_MAGIC, 0x224ef0460a8e8926, 0xe1cb0fc25f46ea3d } + +struct limine_stack_size_response { + uint64_t revision; +}; + +struct limine_stack_size_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_stack_size_response *) response; + uint64_t stack_size; +}; + +/* HHDM */ + +#define LIMINE_HHDM_REQUEST { LIMINE_COMMON_MAGIC, 0x48dcf1cb8ad2b852, 0x63984e959a98244b } + +struct limine_hhdm_response { + uint64_t revision; + uint64_t offset; +}; + +struct limine_hhdm_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_hhdm_response *) response; +}; + +/* Framebuffer */ + +#define LIMINE_FRAMEBUFFER_REQUEST { LIMINE_COMMON_MAGIC, 0x9d5827dcd881dd75, 0xa3148604f6fab11b } + +#define LIMINE_FRAMEBUFFER_RGB 1 + +struct limine_video_mode { + uint64_t pitch; + uint64_t width; + uint64_t height; + uint16_t bpp; + uint8_t memory_model; + uint8_t red_mask_size; + uint8_t red_mask_shift; + uint8_t green_mask_size; + uint8_t green_mask_shift; + uint8_t blue_mask_size; + uint8_t blue_mask_shift; +}; + +struct limine_framebuffer { + LIMINE_PTR(void *) address; + uint64_t width; + uint64_t height; + uint64_t pitch; + uint16_t bpp; + uint8_t memory_model; + uint8_t red_mask_size; + uint8_t red_mask_shift; + uint8_t green_mask_size; + uint8_t green_mask_shift; + uint8_t blue_mask_size; + uint8_t blue_mask_shift; + uint8_t unused[7]; + uint64_t edid_size; + LIMINE_PTR(void *) edid; + /* Response revision 1 */ + uint64_t mode_count; + LIMINE_PTR(struct limine_video_mode **) modes; +}; + +struct limine_framebuffer_response { + uint64_t revision; + uint64_t framebuffer_count; + LIMINE_PTR(struct limine_framebuffer **) framebuffers; +}; + +struct limine_framebuffer_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_framebuffer_response *) response; +}; + +/* Terminal */ + +#define LIMINE_TERMINAL_REQUEST { LIMINE_COMMON_MAGIC, 0xc8ac59310c2b0844, 0xa68d0c7265d38878 } + +#define LIMINE_TERMINAL_CB_DEC 10 +#define LIMINE_TERMINAL_CB_BELL 20 +#define LIMINE_TERMINAL_CB_PRIVATE_ID 30 +#define LIMINE_TERMINAL_CB_STATUS_REPORT 40 +#define LIMINE_TERMINAL_CB_POS_REPORT 50 +#define LIMINE_TERMINAL_CB_KBD_LEDS 60 +#define LIMINE_TERMINAL_CB_MODE 70 +#define LIMINE_TERMINAL_CB_LINUX 80 + +#define LIMINE_TERMINAL_CTX_SIZE ((uint64_t)(-1)) +#define LIMINE_TERMINAL_CTX_SAVE ((uint64_t)(-2)) +#define LIMINE_TERMINAL_CTX_RESTORE ((uint64_t)(-3)) +#define LIMINE_TERMINAL_FULL_REFRESH ((uint64_t)(-4)) + +/* Response revision 1 */ +#define LIMINE_TERMINAL_OOB_OUTPUT_GET ((uint64_t)(-10)) +#define LIMINE_TERMINAL_OOB_OUTPUT_SET ((uint64_t)(-11)) + +#define LIMINE_TERMINAL_OOB_OUTPUT_OCRNL (1 << 0) +#define LIMINE_TERMINAL_OOB_OUTPUT_OFDEL (1 << 1) +#define LIMINE_TERMINAL_OOB_OUTPUT_OFILL (1 << 2) +#define LIMINE_TERMINAL_OOB_OUTPUT_OLCUC (1 << 3) +#define LIMINE_TERMINAL_OOB_OUTPUT_ONLCR (1 << 4) +#define LIMINE_TERMINAL_OOB_OUTPUT_ONLRET (1 << 5) +#define LIMINE_TERMINAL_OOB_OUTPUT_ONOCR (1 << 6) +#define LIMINE_TERMINAL_OOB_OUTPUT_OPOST (1 << 7) + +LIMINE_DEPRECATED_IGNORE_START + +struct LIMINE_DEPRECATED limine_terminal; + +typedef void (*limine_terminal_write)(struct limine_terminal *, const char *, uint64_t); +typedef void (*limine_terminal_callback)(struct limine_terminal *, uint64_t, uint64_t, uint64_t, uint64_t); + +struct LIMINE_DEPRECATED limine_terminal { + uint64_t columns; + uint64_t rows; + LIMINE_PTR(struct limine_framebuffer *) framebuffer; +}; + +struct LIMINE_DEPRECATED limine_terminal_response { + uint64_t revision; + uint64_t terminal_count; + LIMINE_PTR(struct limine_terminal **) terminals; + LIMINE_PTR(limine_terminal_write) write; +}; + +struct LIMINE_DEPRECATED limine_terminal_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_terminal_response *) response; + LIMINE_PTR(limine_terminal_callback) callback; +}; + +LIMINE_DEPRECATED_IGNORE_END + +/* Paging mode */ + +#define LIMINE_PAGING_MODE_REQUEST { LIMINE_COMMON_MAGIC, 0x95c1a0edab0944cb, 0xa4e5cb3842f7488a } + +#if defined (__x86_64__) || defined (__i386__) +#define LIMINE_PAGING_MODE_X86_64_4LVL 0 +#define LIMINE_PAGING_MODE_X86_64_5LVL 1 +#define LIMINE_PAGING_MODE_MIN LIMINE_PAGING_MODE_X86_64_4LVL +#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_X86_64_4LVL +#elif defined (__aarch64__) +#define LIMINE_PAGING_MODE_AARCH64_4LVL 0 +#define LIMINE_PAGING_MODE_AARCH64_5LVL 1 +#define LIMINE_PAGING_MODE_MIN LIMINE_PAGING_MODE_AARCH64_4LVL +#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_AARCH64_4LVL +#elif defined (__riscv) && (__riscv_xlen == 64) +#define LIMINE_PAGING_MODE_RISCV_SV39 0 +#define LIMINE_PAGING_MODE_RISCV_SV48 1 +#define LIMINE_PAGING_MODE_RISCV_SV57 2 +#define LIMINE_PAGING_MODE_MIN LIMINE_PAGING_MODE_RISCV_SV39 +#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_RISCV_SV48 +#elif defined (__loongarch__) && (__loongarch_grlen == 64) +#define LIMINE_PAGING_MODE_LOONGARCH64_4LVL 0 +#define LIMINE_PAGING_MODE_MIN LIMINE_PAGING_MODE_LOONGARCH64_4LVL +#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_LOONGARCH64_4LVL +#else +#error Unknown architecture +#endif + +struct limine_paging_mode_response { + uint64_t revision; + uint64_t mode; +}; + +struct limine_paging_mode_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_paging_mode_response *) response; + uint64_t mode; + uint64_t max_mode; + uint64_t min_mode; +}; + +/* 5-level paging */ + +#define LIMINE_5_LEVEL_PAGING_REQUEST { LIMINE_COMMON_MAGIC, 0x94469551da9b3192, 0xebe5e86db7382888 } + +LIMINE_DEPRECATED_IGNORE_START + +struct LIMINE_DEPRECATED limine_5_level_paging_response { + uint64_t revision; +}; + +struct LIMINE_DEPRECATED limine_5_level_paging_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_5_level_paging_response *) response; +}; + +LIMINE_DEPRECATED_IGNORE_END + +/* MP */ + +#if LIMINE_API_REVISION >= 1 +# define LIMINE_MP_REQUEST { LIMINE_COMMON_MAGIC, 0x95a67b819a1b857e, 0xa0b61b723b6a73e0 } +# define LIMINE_MP(TEXT) limine_mp_##TEXT +#else +# define LIMINE_SMP_REQUEST { LIMINE_COMMON_MAGIC, 0x95a67b819a1b857e, 0xa0b61b723b6a73e0 } +# define LIMINE_MP(TEXT) limine_smp_##TEXT +#endif + +struct LIMINE_MP(info); + +typedef void (*limine_goto_address)(struct LIMINE_MP(info) *); + +#if defined (__x86_64__) || defined (__i386__) + +#if LIMINE_API_REVISION >= 1 +# define LIMINE_MP_X2APIC (1 << 0) +#else +# define LIMINE_SMP_X2APIC (1 << 0) +#endif + +struct LIMINE_MP(info) { + uint32_t processor_id; + uint32_t lapic_id; + uint64_t reserved; + LIMINE_PTR(limine_goto_address) goto_address; + uint64_t extra_argument; +}; + +struct LIMINE_MP(response) { + uint64_t revision; + uint32_t flags; + uint32_t bsp_lapic_id; + uint64_t cpu_count; + LIMINE_PTR(struct LIMINE_MP(info) **) cpus; +}; + +#elif defined (__aarch64__) + +struct LIMINE_MP(info) { + uint32_t processor_id; + uint32_t reserved1; + uint64_t mpidr; + uint64_t reserved; + LIMINE_PTR(limine_goto_address) goto_address; + uint64_t extra_argument; +}; + +struct LIMINE_MP(response) { + uint64_t revision; + uint64_t flags; + uint64_t bsp_mpidr; + uint64_t cpu_count; + LIMINE_PTR(struct LIMINE_MP(info) **) cpus; +}; + +#elif defined (__riscv) && (__riscv_xlen == 64) + +struct LIMINE_MP(info) { + uint64_t processor_id; + uint64_t hartid; + uint64_t reserved; + LIMINE_PTR(limine_goto_address) goto_address; + uint64_t extra_argument; +}; + +struct LIMINE_MP(response) { + uint64_t revision; + uint64_t flags; + uint64_t bsp_hartid; + uint64_t cpu_count; + LIMINE_PTR(struct LIMINE_MP(info) **) cpus; +}; + +#elif defined (__loongarch__) && (__loongarch_grlen == 64) + +struct LIMINE_MP(info) { + uint64_t reserved; +}; + +struct LIMINE_MP(response) { + uint64_t cpu_count; + LIMINE_PTR(struct LIMINE_MP(info) **) cpus; +}; + +#else +#error Unknown architecture +#endif + +struct LIMINE_MP(request) { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct LIMINE_MP(response) *) response; + uint64_t flags; +}; + +/* Memory map */ + +#define LIMINE_MEMMAP_REQUEST { LIMINE_COMMON_MAGIC, 0x67cf3d9d378a806f, 0xe304acdfc50c3c62 } + +#define LIMINE_MEMMAP_USABLE 0 +#define LIMINE_MEMMAP_RESERVED 1 +#define LIMINE_MEMMAP_ACPI_RECLAIMABLE 2 +#define LIMINE_MEMMAP_ACPI_NVS 3 +#define LIMINE_MEMMAP_BAD_MEMORY 4 +#define LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE 5 +#if LIMINE_API_REVISION >= 2 +# define LIMINE_MEMMAP_EXECUTABLE_AND_MODULES 6 +#else +# define LIMINE_MEMMAP_KERNEL_AND_MODULES 6 +#endif +#define LIMINE_MEMMAP_FRAMEBUFFER 7 + +struct limine_memmap_entry { + uint64_t base; + uint64_t length; + uint64_t type; +}; + +struct limine_memmap_response { + uint64_t revision; + uint64_t entry_count; + LIMINE_PTR(struct limine_memmap_entry **) entries; +}; + +struct limine_memmap_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_memmap_response *) response; +}; + +/* Entry point */ + +#define LIMINE_ENTRY_POINT_REQUEST { LIMINE_COMMON_MAGIC, 0x13d86c035a1cd3e1, 0x2b0caa89d8f3026a } + +typedef void (*limine_entry_point)(void); + +struct limine_entry_point_response { + uint64_t revision; +}; + +struct limine_entry_point_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_entry_point_response *) response; + LIMINE_PTR(limine_entry_point) entry; +}; + +/* Executable File */ + +#if LIMINE_API_REVISION >= 2 +# define LIMINE_EXECUTABLE_FILE_REQUEST { LIMINE_COMMON_MAGIC, 0xad97e90e83f1ed67, 0x31eb5d1c5ff23b69 } +#else +# define LIMINE_KERNEL_FILE_REQUEST { LIMINE_COMMON_MAGIC, 0xad97e90e83f1ed67, 0x31eb5d1c5ff23b69 } +#endif + +#if LIMINE_API_REVISION >= 2 +struct limine_executable_file_response { +#else +struct limine_kernel_file_response { +#endif + uint64_t revision; +#if LIMINE_API_REVISION >= 2 + LIMINE_PTR(struct limine_file *) executable_file; +#else + LIMINE_PTR(struct limine_file *) kernel_file; +#endif +}; + +#if LIMINE_API_REVISION >= 2 +struct limine_executable_file_request { +#else +struct limine_kernel_file_request { +#endif + uint64_t id[4]; + uint64_t revision; +#if LIMINE_API_REVISION >= 2 + LIMINE_PTR(struct limine_executable_file_response *) response; +#else + LIMINE_PTR(struct limine_kernel_file_response *) response; +#endif +}; + +/* Module */ + +#define LIMINE_MODULE_REQUEST { LIMINE_COMMON_MAGIC, 0x3e7e279702be32af, 0xca1c4f3bd1280cee } + +#define LIMINE_INTERNAL_MODULE_REQUIRED (1 << 0) +#define LIMINE_INTERNAL_MODULE_COMPRESSED (1 << 1) + +struct limine_internal_module { + LIMINE_PTR(const char *) path; +#if LIMINE_API_REVISION >= 3 + LIMINE_PTR(const char *) string; +#else + LIMINE_PTR(const char *) cmdline; +#endif + uint64_t flags; +}; + +struct limine_module_response { + uint64_t revision; + uint64_t module_count; + LIMINE_PTR(struct limine_file **) modules; +}; + +struct limine_module_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_module_response *) response; + + /* Request revision 1 */ + uint64_t internal_module_count; + LIMINE_PTR(struct limine_internal_module **) internal_modules; +}; + +/* RSDP */ + +#define LIMINE_RSDP_REQUEST { LIMINE_COMMON_MAGIC, 0xc5e77b6b397e7b43, 0x27637845accdcf3c } + +struct limine_rsdp_response { + uint64_t revision; +#if LIMINE_API_REVISION >= 1 + uint64_t address; +#else + LIMINE_PTR(void *) address; +#endif +}; + +struct limine_rsdp_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_rsdp_response *) response; +}; + +/* SMBIOS */ + +#define LIMINE_SMBIOS_REQUEST { LIMINE_COMMON_MAGIC, 0x9e9046f11e095391, 0xaa4a520fefbde5ee } + +struct limine_smbios_response { + uint64_t revision; +#if LIMINE_API_REVISION >= 1 + uint64_t entry_32; + uint64_t entry_64; +#else + LIMINE_PTR(void *) entry_32; + LIMINE_PTR(void *) entry_64; +#endif +}; + +struct limine_smbios_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_smbios_response *) response; +}; + +/* EFI system table */ + +#define LIMINE_EFI_SYSTEM_TABLE_REQUEST { LIMINE_COMMON_MAGIC, 0x5ceba5163eaaf6d6, 0x0a6981610cf65fcc } + +struct limine_efi_system_table_response { + uint64_t revision; +#if LIMINE_API_REVISION >= 1 + uint64_t address; +#else + LIMINE_PTR(void *) address; +#endif +}; + +struct limine_efi_system_table_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_efi_system_table_response *) response; +}; + +/* EFI memory map */ + +#define LIMINE_EFI_MEMMAP_REQUEST { LIMINE_COMMON_MAGIC, 0x7df62a431d6872d5, 0xa4fcdfb3e57306c8 } + +struct limine_efi_memmap_response { + uint64_t revision; + LIMINE_PTR(void *) memmap; + uint64_t memmap_size; + uint64_t desc_size; + uint64_t desc_version; +}; + +struct limine_efi_memmap_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_efi_memmap_response *) response; +}; + +/* Date at boot */ + +#if LIMINE_API_REVISION >= 3 +# define LIMINE_DATE_AT_BOOT_REQUEST { LIMINE_COMMON_MAGIC, 0x502746e184c088aa, 0xfbc5ec83e6327893 } +#else +# define LIMINE_BOOT_TIME_REQUEST { LIMINE_COMMON_MAGIC, 0x502746e184c088aa, 0xfbc5ec83e6327893 } +#endif + +#if LIMINE_API_REVISION >= 3 +struct limine_date_at_boot_response { +#else +struct limine_boot_time_response { +#endif + uint64_t revision; +#if LIMINE_API_REVISION >= 3 + int64_t timestamp; +#else + int64_t boot_time; +#endif +}; + +#if LIMINE_API_REVISION >= 3 +struct limine_date_at_boot_request { +#else +struct limine_boot_time_request { +#endif + uint64_t id[4]; + uint64_t revision; +#if LIMINE_API_REVISION >= 3 + LIMINE_PTR(struct limine_date_at_boot_response *) response; +#else + LIMINE_PTR(struct limine_boot_time_response *) response; +#endif +}; + +/* Executable address */ + +#if LIMINE_API_REVISION >= 2 +# define LIMINE_EXECUTABLE_ADDRESS_REQUEST { LIMINE_COMMON_MAGIC, 0x71ba76863cc55f63, 0xb2644a48c516a487 } +#else +# define LIMINE_KERNEL_ADDRESS_REQUEST { LIMINE_COMMON_MAGIC, 0x71ba76863cc55f63, 0xb2644a48c516a487 } +#endif + +#if LIMINE_API_REVISION >= 2 +struct limine_executable_address_response { +#else +struct limine_kernel_address_response { +#endif + uint64_t revision; + uint64_t physical_base; + uint64_t virtual_base; +}; + +#if LIMINE_API_REVISION >= 2 +struct limine_executable_address_request { +#else +struct limine_kernel_address_request { +#endif + uint64_t id[4]; + uint64_t revision; +#if LIMINE_API_REVISION >= 2 + LIMINE_PTR(struct limine_executable_address_response *) response; +#else + LIMINE_PTR(struct limine_kernel_address_response *) response; +#endif +}; + +/* Device Tree Blob */ + +#define LIMINE_DTB_REQUEST { LIMINE_COMMON_MAGIC, 0xb40ddb48fb54bac7, 0x545081493f81ffb7 } + +struct limine_dtb_response { + uint64_t revision; + LIMINE_PTR(void *) dtb_ptr; +}; + +struct limine_dtb_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_dtb_response *) response; +}; + +/* RISC-V Boot Hart ID */ + +#define LIMINE_RISCV_BSP_HARTID_REQUEST { LIMINE_COMMON_MAGIC, 0x1369359f025525f9, 0x2ff2a56178391bb6 } + +struct limine_riscv_bsp_hartid_response { + uint64_t revision; + uint64_t bsp_hartid; +}; + +struct limine_riscv_bsp_hartid_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_riscv_bsp_hartid_response *) response; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kernel/init/kernel.c b/kernel/init/kernel.c index e6f9b1e..af2b5d9 100644 --- a/kernel/init/kernel.c +++ b/kernel/init/kernel.c @@ -1,10 +1,41 @@ -#include -#include +#include +/* #include */ +#include +#include + +static void hcf(void) { + for (;;) { + __asm__("hlt"); + } +} void kernel_main(void) { + /* Make sure the bootloader understands our base revision */ + if (LIMINE_BASE_REVISION_SUPPORTED == 0) hcf(); + + /* ensure a framebuffer */ + if (framebuffer_request.response == NULL + || framebuffer_request.response->framebuffer_count < 1) hcf(); + + /* fetch the first framebuffer */ + struct limine_framebuffer *framebuffer = framebuffer_request.response->framebuffers[0]; + + /* assume framebuffer model is RGB w/32-bit pixels */ + for (size_t i = 0; i < 100; i++) { + volatile uint32_t *fb_ptr = framebuffer->address; + fb_ptr[i * (framebuffer->pitch / 4) + i] = 0xffffff; + } + + /* need to get an actual framebuffer driver working before we can use vga */ + + /* term_init(); - term_writestr("Hello World!\n"); + term_writestr("Hello World!"); + */ + + /* done so now hang */ + hcf(); } diff --git a/kernel/init/kernel.o b/kernel/init/kernel.o new file mode 100644 index 0000000000000000000000000000000000000000..6dc406ca0ee0efbf96b40e0cf556ed4c70b0f9c0 GIT binary patch literal 10968 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 U074h(tqS&0*~4z4-9+Q}U+NFf9smFU literal 0 HcmV?d00001 diff --git a/kernel/lib/string.c b/kernel/lib/string.c deleted file mode 100644 index ad444ae..0000000 --- a/kernel/lib/string.c +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include -#include - -size_t -strlen(const char* str) -{ - size_t len = 0; - while (str[len]) len++; - return len; -} diff --git a/kernel/linker.ld b/kernel/linker.ld new file mode 100644 index 0000000..3229850 --- /dev/null +++ b/kernel/linker.ld @@ -0,0 +1,68 @@ +/* Tell the linker that we want an x86_64 ELF64 output file */ +OUTPUT_FORMAT(elf64-x86-64) + +/* We want the symbol kmain to be our entry point */ +ENTRY(kernel_main) + +/* Define the program headers we want so the bootloader gives us the right */ +/* MMU permissions; this also allows us to exert more control over the linking */ +/* process. */ +PHDRS +{ + limine_requests PT_LOAD; + text PT_LOAD; + rodata PT_LOAD; + data PT_LOAD; +} + +SECTIONS +{ + /* We want to be placed in the topmost 2GiB of the address space, for optimisations */ + /* and because that is what the Limine spec mandates. */ + /* Any address in this region will do, but often 0xffffffff80000000 is chosen as */ + /* that is the beginning of the region. */ + . = 0xffffffff80000000; + + /* Define a section to contain the Limine requests and assign it to its own PHDR */ + .limine_requests : { + KEEP(*(.limine_requests_start)) + KEEP(*(.limine_requests)) + KEEP(*(.limine_requests_end)) + } :limine_requests + + /* Move to the next memory page for .text */ + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .text : { + *(.text .text.*) + } :text + + /* Move to the next memory page for .rodata */ + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .rodata : { + *(.rodata .rodata.*) + } :rodata + + /* Move to the next memory page for .data */ + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .data : { + *(.data .data.*) + } :data + + /* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */ + /* unnecessary zeros will be written to the binary. */ + /* If you need, for example, .init_array and .fini_array, those should be placed */ + /* above this. */ + .bss : { + *(.bss .bss.*) + *(COMMON) + } :data + + /* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */ + /DISCARD/ : { + *(.eh_frame*) + *(.note .note.*) + } +}