├── .clang-format ├── .gitignore ├── .gitmodules ├── bestos.sh ├── bootstrap.yml ├── compile_flags.txt ├── cross_file.txt ├── extra-patches └── gcc.patch ├── makefile ├── meta └── scripts │ └── make-image.sh ├── patches ├── binutils │ └── binutils.patch ├── gcc │ └── gcc.patch └── mlibc │ └── mlibc.patch └── src ├── apps ├── init.c ├── makefile └── sh.c ├── kernel ├── arch │ ├── arch.h │ ├── asm.h │ ├── devices │ │ ├── com.c │ │ ├── com.h │ │ ├── pic.c │ │ └── pic.h │ ├── gdt.asm │ ├── gdt.c │ ├── gdt.h │ ├── idt.asm │ ├── idt.c │ ├── idt.h │ ├── interrupts.c │ ├── memory.h │ ├── memory │ │ ├── pmm.c │ │ ├── pmm.h │ │ ├── vmm.c │ │ └── vmm.h │ └── sse.asm ├── bootstrap.c ├── elf.c ├── elf.h ├── fs │ ├── devfs.c │ ├── devfs.h │ ├── tmpfs.c │ ├── tmpfs.h │ ├── ustar.c │ ├── ustar.h │ ├── vfs.c │ └── vfs.h ├── main.c ├── sched.c ├── sched.h ├── stivale2.h ├── syscalls.c └── syscalls.h ├── lib ├── abi.h ├── alloc.c ├── alloc.h ├── base.h ├── errno.h ├── lock.h ├── mem.c ├── mem.h ├── print.c ├── print.h ├── str.c ├── str.h ├── vec.c └── vec.h ├── link.ld └── root └── boot └── limine.cfg /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | BasedOnStyle: LLVM 4 | UseTab: Never 5 | IndentWidth: 4 6 | TabWidth: 4 7 | BreakBeforeBraces: Allman 8 | AllowShortIfStatementsOnASingleLine: false 9 | IndentCaseLabels: false 10 | ColumnLimit: 0 11 | AccessModifierOffset: -4 12 | FixNamespaceComments: true 13 | SpaceBeforeInheritanceColon: true 14 | BreakInheritanceList: AfterColon 15 | IndentPPDirectives: AfterHash 16 | Language: Cpp 17 | 18 | ... 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.xz 2 | *.tar.xz 3 | ports 4 | sysroot 5 | build 6 | *.o 7 | *.iso 8 | bestOS.iso 9 | .vscode 10 | *.so 11 | src/root/usr 12 | src/root/bin/* 13 | *.elf 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "thirdparty/limine"] 2 | path = thirdparty/limine 3 | url = https://github.com/limine-bootloader/limine 4 | branch = latest-binary 5 | -------------------------------------------------------------------------------- /bestos.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | OPTIONS="rebuild-mlibc build-sysroot" 6 | 7 | usage() 8 | { 9 | echo "Usage: $0 [options...]" 10 | echo "" 11 | echo "Options:" 12 | echo " -a, --all Build tools, install the tools and build the system" 13 | echo " -c, --clean Do a clean build" 14 | echo " -e, --env Setup the environment" 15 | echo " -b, --build Build the system" 16 | echo " -r, --run Run the system in QEMU" 17 | echo " -i, --install Install everything to the system root" 18 | echo " -t, --tools Build tools required in a directory called sysroot" 19 | echo "Tools:" 20 | echo " $TOOLS" 21 | echo "" 22 | exit 1 23 | } 24 | 25 | eval_arg() 26 | { 27 | case $1 in 28 | "-a" | "--all") 29 | mkdir -p sysroot && cd sysroot && xbstrap init .. && xbstrap install -u --all && cd .. 30 | make -j 31 | mkdir -p src/root/usr/lib 32 | cp sysroot/system-root/usr/lib/* src/root/usr/lib 33 | ;; 34 | "-b" | "--build") 35 | make -j 36 | ;; 37 | 38 | "-c" | "--clean") 39 | make clean 40 | ;; 41 | 42 | "-h" | "--help") 43 | usage 44 | ;; 45 | 46 | "-r" | "--run") 47 | make run 48 | ;; 49 | 50 | "-t" | "--tools") 51 | mkdir -p sysroot && cd sysroot && xbstrap init .. && xbstrap install -u --all 52 | ;; 53 | "-e" | "--env") 54 | export PATH=$PATH:$PWD/sysroot/tools/host-gcc/bin 55 | export PATH=$PATH:$PWD/sysroot/tools/host-binutils/bin 56 | ;; 57 | 58 | "-i" | "--install") 59 | mkdir -p src/root/usr/lib 60 | cp sysroot/system-root/usr/lib/* src/root/usr/lib 61 | ;; 62 | 63 | *) 64 | echo "Unknown option '$1'!" 65 | echo "" 66 | usage 67 | ;; 68 | esac 69 | } 70 | 71 | 72 | if [ -z "$1" ]; then 73 | usage 74 | exit 1 75 | fi 76 | 77 | while [[ $1 == -* ]]; do 78 | eval_arg $1 79 | shift 80 | done 81 | -------------------------------------------------------------------------------- /bootstrap.yml: -------------------------------------------------------------------------------- 1 | # Shamelessly inspired (copied) from the one in lyre which was copied from qword which was copied from the one in bootstrap-managarm 2 | 3 | sources: 4 | - name: binutils 5 | subdir: 'ports' 6 | url: 'https://ftp.gnu.org/gnu/binutils/binutils-2.35.1.tar.xz' 7 | format: 'tar.xz' 8 | extract_path: 'binutils-2.35.1' 9 | patch-path-strip: 3 10 | tools_required: 11 | - host-autoconf-v2.69 12 | - host-automake-v1.15 13 | regenerate: 14 | - args: ['automake'] 15 | workdir: '@THIS_SOURCE_DIR@/ld' 16 | 17 | - name: gcc 18 | subdir: 'ports' 19 | url: 'https://ftp.gnu.org/gnu/gcc/gcc-10.2.0/gcc-10.2.0.tar.xz' 20 | format: 'tar.xz' 21 | extract_path: 'gcc-10.2.0' 22 | patch-path-strip: 3 23 | tools_required: 24 | - host-autoconf-v2.69 25 | - host-automake-v1.15 26 | regenerate: 27 | # download_prerequisites should probably move to some "post_checkout" step. 28 | - args: ['./contrib/download_prerequisites'] 29 | workdir: '@THIS_SOURCE_DIR@' 30 | - args: ['autoconf'] 31 | workdir: '@THIS_SOURCE_DIR@/gcc' 32 | - args: ['autoconf'] 33 | workdir: '@THIS_SOURCE_DIR@/libstdc++-v3' 34 | - args: ['sh', '-c', 'patch -p1 < ../../extra-patches/gcc.patch'] 35 | workdir: '@THIS_SOURCE_DIR@' 36 | 37 | - name: mlibc 38 | subdir: 'ports' 39 | url: 'https://github.com/managarm/mlibc/archive/2.1.0.tar.gz' 40 | format: 'tar.gz' 41 | extract_path: 'mlibc-2.1.0' 42 | patch-path-strip: 3 43 | 44 | tools: 45 | - name: host-autoconf-v2.69 46 | source: 47 | name: autoconf-v2.69 48 | subdir: 'ports' 49 | url: 'https://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.xz' 50 | format: 'tar.xz' 51 | extract_path: 'autoconf-2.69' 52 | patch-path-strip: 3 53 | configure: 54 | - args: ['@THIS_SOURCE_DIR@/configure', '--prefix=@PREFIX@'] 55 | compile: 56 | - args: ['make', '-j@PARALLELISM@'] 57 | install: 58 | - args: ['make', 'install'] 59 | 60 | - name: host-automake-v1.15 61 | source: 62 | name: automake-v1.15 63 | subdir: 'ports' 64 | url: 'https://ftp.gnu.org/gnu/automake/automake-1.15.1.tar.xz' 65 | format: 'tar.xz' 66 | extract_path: 'automake-1.15.1' 67 | patch-path-strip: 3 68 | tools_required: 69 | - host-autoconf-v2.69 70 | configure: 71 | - args: 72 | - '@THIS_SOURCE_DIR@/configure' 73 | - '--prefix=@PREFIX@' 74 | compile: 75 | - args: ['make', '-j@PARALLELISM@'] 76 | install: 77 | - args: ['make', 'install'] 78 | 79 | - name: host-binutils 80 | from_source: binutils 81 | configure: 82 | - args: 83 | - '@THIS_SOURCE_DIR@/configure' 84 | - '--prefix=@PREFIX@' 85 | - '--target=x86_64-bestos' 86 | - '--with-sysroot=@SYSROOT_DIR@' 87 | # On recent compilers, binutils 2.26 causes implicit-fallthrough warnings, among others. 88 | - '--disable-werror' 89 | # -g blows up the binary size. 90 | - 'CFLAGS=-O2 -pipe' 91 | compile: 92 | - args: ['make', '-j@PARALLELISM@'] 93 | install: 94 | - args: ['make', 'install'] 95 | 96 | - name: host-gcc 97 | from_source: gcc 98 | tools_required: 99 | - tool: host-binutils 100 | recursive: true 101 | configure: 102 | - args: 103 | - '@THIS_SOURCE_DIR@/configure' 104 | - '--prefix=@PREFIX@' 105 | - '--target=x86_64-bestos' 106 | - '--with-sysroot=@SYSROOT_DIR@' 107 | - '--enable-languages=c,c++' 108 | - '--disable-multilib' 109 | - '--enable-initfini-array' 110 | # -g blows up GCC's binary size. 111 | - 'CFLAGS=-O2 -pipe' 112 | - 'CXXFLAGS=-O2 -pipe' 113 | stages: 114 | - name: compiler 115 | pkgs_required: 116 | - mlibc-headers 117 | compile: 118 | - args: ['make', '-j@PARALLELISM@', 'all-gcc'] 119 | install: 120 | - args: ['make', 'install-gcc'] 121 | # GCC does *not* look for target-prefixed LD/AS. 122 | # Instead, it searches a list of prefix directories. Link AS/LD to make it happy. 123 | - args: ['mkdir', '-p', '@PREFIX@/x86_64-bestos/bin'] 124 | - args: ['ln', '-sf', '../../../host-binutils/x86_64-bestos/bin/as', 125 | '@PREFIX@/x86_64-bestos/bin/as'] 126 | - args: ['ln', '-sf', '../../../host-binutils/x86_64-bestos/bin/ld', 127 | '@PREFIX@/x86_64-bestos/bin/ld'] 128 | - name: libgcc 129 | tools_required: 130 | - tool: host-gcc 131 | stage_dependencies: [compiler] 132 | pkgs_required: 133 | - mlibc 134 | compile: 135 | - args: ['make', '-j@PARALLELISM@', 'all-target-libgcc'] 136 | install: 137 | - args: ['make', 'install-target-libgcc'] 138 | - name: libstdc++ 139 | tools_required: 140 | - tool: host-gcc 141 | stage_dependencies: [libgcc] 142 | compile: 143 | - args: ['make', '-j@PARALLELISM@', 'all-target-libstdc++-v3'] 144 | install: 145 | - args: ['make', 'install-target-libstdc++-v3'] 146 | 147 | packages: 148 | - name: mlibc-headers 149 | from_source: mlibc 150 | implict_package: true 151 | configure: 152 | - args: 153 | - 'meson' 154 | - '--cross-file' 155 | - '@SOURCE_ROOT@/cross_file.txt' 156 | - '--prefix=/usr' 157 | - '-Dheaders_only=true' 158 | - '@THIS_SOURCE_DIR@' 159 | build: 160 | - args: ['ninja'] 161 | - args: ['ninja', 'install'] 162 | environ: 163 | DESTDIR: '@THIS_COLLECT_DIR@' 164 | 165 | - name: mlibc 166 | from_source: mlibc 167 | tools_required: 168 | - tool: host-gcc 169 | stage_dependencies: [compiler] 170 | implict_package: true 171 | pkgs_required: 172 | - mlibc-headers 173 | configure: 174 | - args: 175 | - 'meson' 176 | - '--cross-file' 177 | - '@SOURCE_ROOT@/cross_file.txt' 178 | - '--prefix=/usr' 179 | - '--libdir=lib' 180 | - '--buildtype=debugoptimized' 181 | - '@THIS_SOURCE_DIR@' 182 | build: 183 | - args: ['ninja'] 184 | - args: ['ninja', 'install'] 185 | environ: 186 | DESTDIR: '@THIS_COLLECT_DIR@' -------------------------------------------------------------------------------- /compile_flags.txt: -------------------------------------------------------------------------------- 1 | -Isrc/kernel 2 | -Isrc 3 | -std=gnu99 4 | -Wno-incompatible-library-redeclaration -------------------------------------------------------------------------------- /cross_file.txt: -------------------------------------------------------------------------------- 1 | [binaries] 2 | c = 'x86_64-bestos-gcc' 3 | cpp = 'x86_64-bestos-g++' 4 | ar = 'x86_64-bestos-ar' 5 | strip = 'x86_64-bestos-strip' 6 | pkgconfig = 'pkg-config' 7 | 8 | [host_machine] 9 | system = 'bestos' 10 | cpu_family = 'x86_64' 11 | cpu = 'x86_64' 12 | endian = 'little' -------------------------------------------------------------------------------- /extra-patches/gcc.patch: -------------------------------------------------------------------------------- 1 | diff -urN --no-dereference gcc/gmp-6.1.0/configfsf.sub gcc-patched/gmp-6.1.0/configfsf.sub 2 | --- gcc/gmp-6.1.0/configfsf.sub 2015-11-01 16:19:48.000000000 +0100 3 | +++ gcc-patched/gmp-6.1.0/configfsf.sub 2020-01-12 17:05:30.887799494 +0100 4 | @@ -1399,7 +1399,8 @@ 5 | | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ 6 | | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ 7 | | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ 8 | - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) 9 | + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos* \ 10 | + | -bestos*) 11 | # Remember, each alternative MUST END IN *, to match a version number. 12 | ;; 13 | -qnx*) 14 | diff -urN --no-dereference gcc/isl-0.18/config.sub gcc-patched/isl-0.18/config.sub 15 | --- gcc/isl-0.18/config.sub 2016-01-24 21:50:53.000000000 +0100 16 | +++ gcc-patched/isl-0.18/config.sub 2020-01-12 17:06:18.480800646 +0100 17 | @@ -1385,7 +1385,8 @@ 18 | | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ 19 | | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ 20 | | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ 21 | - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) 22 | + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos* \ 23 | + | -bestos*) 24 | # Remember, each alternative MUST END IN *, to match a version number. 25 | ;; 26 | -qnx*) 27 | diff -urN --no-dereference gcc/mpc-1.0.3/config.sub gcc-patched/mpc-1.0.3/config.sub 28 | --- gcc/mpc-1.0.3/config.sub 2015-02-16 13:28:25.000000000 +0100 29 | +++ gcc-patched/mpc-1.0.3/config.sub 2020-01-12 17:09:12.181804852 +0100 30 | @@ -1393,7 +1393,8 @@ 31 | | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ 32 | | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ 33 | | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ 34 | - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) 35 | + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos* \ 36 | + | -bestos*) 37 | # Remember, each alternative MUST END IN *, to match a version number. 38 | ;; 39 | -qnx*) 40 | diff -urN --no-dereference gcc/mpfr-3.1.4/config.sub gcc-patched/mpfr-3.1.4/config.sub 41 | --- gcc/mpfr-3.1.4/config.sub 2016-03-06 12:33:18.000000000 +0100 42 | +++ gcc-patched/mpfr-3.1.4/config.sub 2020-01-12 17:07:52.696802927 +0100 43 | @@ -1399,7 +1399,8 @@ 44 | | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ 45 | | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ 46 | | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ 47 | - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) 48 | + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos* \ 49 | + | -bestos*) 50 | # Remember, each alternative MUST END IN *, to match a version number. 51 | ;; 52 | -qnx*) 53 | © 2022 GitHub, Inc. 54 | Terms 55 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | CC = x86_64-elf-gcc 2 | LD = x86_64-elf-ld 3 | AS = nasm 4 | 5 | ASMFILES := $(shell find src -name '*.asm') 6 | CFILES := $(shell find src/kernel src/lib -name '*.c') 7 | 8 | OBJ = $(patsubst %.c, $(BUILD_DIRECTORY)/%.c.o, $(CFILES)) \ 9 | $(patsubst %.asm, $(BUILD_DIRECTORY)/%.asm.o, $(ASMFILES)) 10 | 11 | TARGET = $(BUILD_DIRECTORY)/kernel.elf 12 | ISO = bestOS.iso 13 | MEMORY = 512M 14 | 15 | CHARDFLAGS := -nostdlib \ 16 | -g \ 17 | -O2 \ 18 | -fno-stack-protector \ 19 | -Wall \ 20 | -Wextra \ 21 | -Werror \ 22 | -ffreestanding \ 23 | -std=gnu99 \ 24 | -mcmodel=kernel \ 25 | -Isrc/kernel \ 26 | -Isrc \ 27 | -fno-pic \ 28 | -mno-red-zone \ 29 | -mno-sse \ 30 | -mno-sse2 \ 31 | 32 | LDHARDFLAGS := \ 33 | -nostdlib \ 34 | -static \ 35 | -z max-page-size=0x1000 \ 36 | -T src/link.ld 37 | 38 | NASMFLAGS := -felf64 39 | 40 | BUILD_DIRECTORY := build 41 | DIRECTORY_GUARD = @mkdir -p $(@D) 42 | 43 | .DEFAULT_GOAL = $(ISO) 44 | 45 | $(ISO): $(TARGET) 46 | $(SHELL) meta/scripts/make-image.sh > /dev/null 2>&1 47 | 48 | run: $(ISO) 49 | qemu-system-x86_64 -cdrom $< -enable-kvm -serial stdio -rtc base=localtime -m $(MEMORY) -no-shutdown -no-reboot 50 | 51 | 52 | debug: $(ISO) 53 | qemu-system-x86_64 -cdrom $< -d int -serial stdio -rtc base=localtime -m $(MEMORY) -M smm=off -no-shutdown -no-reboot 54 | 55 | gdb: $(ISO) 56 | qemu-system-x86_64 -cdrom $< -s -S -serial stdio -m $(MEMORY) -no-shutdown -no-reboot 57 | 58 | tcg: $(ISO) 59 | qemu-system-x86_64 -cdrom $< -serial stdio -rtc base=localtime -m $(MEMORY) -no-shutdown -no-reboot 60 | $(BUILD_DIRECTORY)/%.c.o: %.c 61 | $(DIRECTORY_GUARD) 62 | $(CC) $(CHARDFLAGS) -c $< -o $@ 63 | 64 | $(BUILD_DIRECTORY)/%.asm.o: %.asm 65 | $(DIRECTORY_GUARD) 66 | nasm $(NASMFLAGS) $< -o $@ 67 | 68 | $(TARGET): $(OBJ) 69 | $(LD) $(LDHARDFLAGS) $(OBJ) -o $@ 70 | 71 | .PHONY: clean 72 | clean: 73 | rm -rf $(BUILD_DIRECTORY) $(TARGET) $(ISO) 74 | -------------------------------------------------------------------------------- /meta/scripts/make-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | path="$(dirname $0)/../../" 4 | mkdir -p tmp/boot 5 | 6 | cp $path/build/kernel.elf ./tmp/boot 7 | cp -r $path/src/root/* ./tmp 8 | cd ./tmp 9 | tar -cf root.tar * 10 | mv root.tar boot 11 | cd .. 12 | 13 | cp $path/thirdparty/limine/limine.sys ./tmp/boot 14 | cp $path/thirdparty/limine/*.bin ./tmp/boot 15 | 16 | xorriso -as mkisofs -b limine-cd.bin -no-emul-boot -boot-load-size $(nproc --all) \ 17 | -boot-info-table --efi-boot limine-eltorito-efi.bin -efi-boot-part --efi-boot-image \ 18 | --protective-msdos-label ./tmp/boot -o $path/bestOS.iso 19 | 20 | $path/thirdparty/limine/limine-install-linux-x86_64 $path/bestOS.iso 21 | rm -rf ./tmp 22 | -------------------------------------------------------------------------------- /patches/binutils/binutils.patch: -------------------------------------------------------------------------------- 1 | diff --git a/ports/binutils-orig/bfd/config.bfd b/ports/binutils-workdir/bfd/config.bfd 2 | index 14523ca..e757576 100644 3 | --- a/ports/binutils-orig/bfd/config.bfd 4 | +++ b/ports/binutils-workdir/bfd/config.bfd 5 | @@ -722,6 +722,11 @@ case "${targ}" in 6 | targ_defvec=i386_elf32_vec 7 | targ_selvecs="iamcu_elf32_vec i386_pe_vec i386_pei_vec" 8 | ;; 9 | + x86_64-*-bestos*) 10 | + targ_defvec=x86_64_elf64_vec 11 | + targ_selvecs=i386_elf32_vec 12 | + want64=true 13 | + ;; 14 | i[3-7]86-*-interix*) 15 | targ_defvec=i386_pei_vec 16 | targ_selvecs="i386_pe_vec" 17 | diff --git a/ports/binutils-orig/bfd/dwarf2.c b/ports/binutils-workdir/bfd/dwarf2.c 18 | index b8f0008..1572a26 100644 19 | --- a/ports/binutils-orig/bfd/dwarf2.c 20 | +++ b/ports/binutils-workdir/bfd/dwarf2.c 21 | @@ -3404,7 +3404,7 @@ scan_unit_for_symbols (struct comp_unit *unit) 22 | else 23 | { 24 | func = NULL; 25 | - if (abbrev->tag == DW_TAG_variable) 26 | + if (abbrev->tag == DW_TAG_variable || abbrev->tag == DW_TAG_member) 27 | { 28 | size_t amt = sizeof (struct varinfo); 29 | var = (struct varinfo *) bfd_zalloc (abfd, amt); 30 | diff --git a/ports/binutils-orig/binutils/testsuite/gentestdlls.c b/ports/binutils-workdir/binutils/testsuite/gentestdlls.c 31 | index 7d19f3c..067272e 100644 32 | --- a/ports/binutils-orig/binutils/testsuite/gentestdlls.c 33 | +++ b/ports/binutils-workdir/binutils/testsuite/gentestdlls.c 34 | @@ -25,7 +25,7 @@ 35 | See: 36 | https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf */ 37 | 38 | -#include 39 | +//#include 40 | #include 41 | #include 42 | #include 43 | diff --git a/ports/binutils-orig/config.sub b/ports/binutils-workdir/config.sub 44 | index f02d43a..a6bdfbd 100755 45 | --- a/ports/binutils-orig/config.sub 46 | +++ b/ports/binutils-workdir/config.sub 47 | @@ -1366,7 +1366,7 @@ case $os in 48 | | skyos* | haiku* | rdos* | toppers* | drops* | es* \ 49 | | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ 50 | | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ 51 | - | nsk* | powerunix) 52 | + | nsk* | powerunix | bestos*) 53 | # Remember, each alternative MUST END IN *, to match a version number. 54 | ;; 55 | qnx*) 56 | diff --git a/ports/binutils-orig/gas/configure.tgt b/ports/binutils-workdir/gas/configure.tgt 57 | index 3372495..52ef6ac 100644 58 | --- a/ports/binutils-orig/gas/configure.tgt 59 | +++ b/ports/binutils-workdir/gas/configure.tgt 60 | @@ -218,6 +218,7 @@ case ${generic_target} in 61 | i386-*-beos*) fmt=elf ;; 62 | i386-*-elfiamcu) fmt=elf arch=iamcu ;; 63 | i386-*-elf*) fmt=elf ;; 64 | + i386-*-bestos*) fmt=elf ;; 65 | i386-*-fuchsia*) fmt=elf ;; 66 | i386-*-bsd*) fmt=aout em=386bsd ;; 67 | i386-*-netbsdpe*) fmt=coff em=pe ;; 68 | diff --git a/ports/binutils-orig/ld/configure.tgt b/ports/binutils-workdir/ld/configure.tgt 69 | index 87c7d9a..5ba2de0 100644 70 | --- a/ports/binutils-orig/ld/configure.tgt 71 | +++ b/ports/binutils-workdir/ld/configure.tgt 72 | @@ -319,6 +319,10 @@ i[3-7]86-*-bsd386) targ_emul=i386bsd 73 | i[3-7]86-*-bsdi*) targ_emul=i386bsd 74 | targ_extra_ofiles= 75 | ;; 76 | +x86_64-*-bestos*) 77 | + targ_emul=elf_x86_64 78 | + targ_extra_emuls=elf_i386 79 | + ;; 80 | i[3-7]86-*-linux-*) targ_emul=elf_i386 81 | targ_extra_emuls="elf_iamcu" 82 | targ64_extra_emuls="elf_x86_64 elf32_x86_64 elf_l1om elf_k1om" -------------------------------------------------------------------------------- /patches/gcc/gcc.patch: -------------------------------------------------------------------------------- 1 | diff --git a/ports/gcc-orig/config.sub b/ports/gcc-workdir/config.sub 2 | index a318a46..b4950e0 100755 3 | --- a/ports/gcc-orig/config.sub 4 | +++ b/ports/gcc-workdir/config.sub 5 | @@ -135,7 +135,7 @@ case $1 in 6 | | linux-newlib* | linux-musl* | linux-uclibc* | uclinux-uclibc* \ 7 | | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ 8 | | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ 9 | - | storm-chaos* | os2-emx* | rtmk-nova*) 10 | + | storm-chaos* | os2-emx* | rtmk-nova* | bestos*) 11 | basic_machine=$field1 12 | os=$maybe_os 13 | ;; 14 | @@ -1366,7 +1366,7 @@ case $os in 15 | | skyos* | haiku* | rdos* | toppers* | drops* | es* \ 16 | | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ 17 | | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ 18 | - | nsk* | powerunix) 19 | + | nsk* | powerunix | bestos*) 20 | # Remember, each alternative MUST END IN *, to match a version number. 21 | ;; 22 | qnx*) 23 | diff --git a/ports/gcc-orig/fixincludes/mkfixinc.sh b/ports/gcc-workdir/fixincludes/mkfixinc.sh 24 | index df90720..484f8bc 100755 25 | --- a/ports/gcc-orig/fixincludes/mkfixinc.sh 26 | +++ b/ports/gcc-workdir/fixincludes/mkfixinc.sh 27 | @@ -12,6 +12,7 @@ target=fixinc.sh 28 | # Check for special fix rules for particular targets 29 | case $machine in 30 | i?86-*-cygwin* | \ 31 | + x86_64-*-bestos* | \ 32 | i?86-*-mingw32* | \ 33 | x86_64-*-mingw32* | \ 34 | powerpc-*-eabisim* | \ 35 | diff --git a/ports/gcc-workdir/gcc/config/bestos.h b/ports/gcc-workdir/gcc/config/bestos.h 36 | new file mode 100644 37 | index 0000000..7caace5 38 | --- /dev/null 39 | +++ b/ports/gcc-workdir/gcc/config/bestos.h 40 | @@ -0,0 +1,29 @@ 41 | +#undef TARGET_BESTOS 42 | +#define TARGET_BESTOS 1 43 | + 44 | +#undef LIB_SPEC 45 | +#define LIB_SPEC "-lc -lm" 46 | + 47 | +#undef STARTFILE_SPEC 48 | +#define STARTFILE_SPEC "%{!shared:crt0.o%s} crti.o%s %{shared:crtbeginS.o%s;:crtbegin.o%s}" 49 | + 50 | +#undef ENDFILE_SPEC 51 | +#define ENDFILE_SPEC "%{shared:crtendS.o%s;:crtend.o%s} crtn.o%s" 52 | + 53 | +#define GNU_USER_LINK_EMULATION32 "elf_i386" 54 | +#define GNU_USER_LINK_EMULATION64 "elf_x86_64" 55 | +#define GNU_USER_LINK_EMULATIONX32 "elf32_x86_64" 56 | + 57 | +#define GNU_USER_DYNAMIC_LINKER32 "/usr/lib/ld_i386.so" 58 | +#define GNU_USER_DYNAMIC_LINKER64 "/usr/lib/ld.so" 59 | +#define GNU_USER_DYNAMIC_LINKERX32 "/usr/lib/ld32.so" 60 | + 61 | +#undef TARGET_OS_CPP_BUILTINS 62 | +#define TARGET_OS_CPP_BUILTINS() \ 63 | + do { \ 64 | + builtin_define ("__bestos__"); \ 65 | + builtin_define ("__unix__"); \ 66 | + builtin_assert ("system=bestos"); \ 67 | + builtin_assert ("system=unix"); \ 68 | + builtin_assert ("system=posix"); \ 69 | + } while (0); 70 | diff --git a/ports/gcc-orig/gcc/config.gcc b/ports/gcc-workdir/gcc/config.gcc 71 | index 6a34996..de7f3b0 100644 72 | --- a/ports/gcc-orig/gcc/config.gcc 73 | +++ b/ports/gcc-workdir/gcc/config.gcc 74 | @@ -773,6 +773,15 @@ case ${target} in 75 | esac 76 | use_gcc_stdint=wrap 77 | ;; 78 | +*-*-bestos*) 79 | + extra_options="$extra_options gnu-user.opt" 80 | + gas=yes 81 | + gnu_ld=yes 82 | + default_use_cxa_atexit=yes 83 | + use_gcc_stdint=wrap 84 | + tmake_file="${tmake_file} t-slibgcc" 85 | + thread_file='posix' 86 | + ;; 87 | *-*-fuchsia*) 88 | native_system_header_dir=/include 89 | ;; 90 | @@ -2202,6 +2211,9 @@ i[34567]86-*-mingw* | x86_64-*-mingw*) 91 | ;; 92 | esac 93 | ;; 94 | +x86_64-*-bestos*) 95 | + tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h gnu-user.h glibc-stdint.h i386/x86-64.h i386/gnu-user-common.h i386/gnu-user64.h bestos.h" 96 | + ;; 97 | x86_64-*-fuchsia*) 98 | tmake_file="${tmake_file} i386/t-x86_64-elf" 99 | tm_file="${tm_file} i386/unix.h i386/att.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h fuchsia.h" 100 | diff --git a/ports/gcc-orig/libgcc/config.host b/ports/gcc-workdir/libgcc/config.host 101 | index c529cc4..d1f469c 100644 102 | --- a/ports/gcc-orig/libgcc/config.host 103 | +++ b/ports/gcc-workdir/libgcc/config.host 104 | @@ -103,7 +103,7 @@ arm*-*-*) 105 | ;; 106 | avr-*-*) 107 | cpu_type=avr 108 | - ;; 109 | + ;; 110 | bfin*-*) 111 | cpu_type=bfin 112 | ;; 113 | @@ -248,6 +248,11 @@ case ${host} in 114 | tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip t-slibgcc t-slibgcc-fuchsia" 115 | extra_parts="crtbegin.o crtend.o" 116 | ;; 117 | +*-*-bestos*) 118 | + extra_parts="$extra_parts crti.o crtbegin.o crtbeginS.o crtend.o crtendS.o crtn.o" 119 | + tmake_file="$tmake_file t-crtstuff-pic" 120 | + tmake_file="$tmake_file t-slibgcc t-slibgcc-gld t-slibgcc-elf-ver t-libgcc-pic" 121 | + ;; 122 | *-*-linux* | frv-*-*linux* | *-*-kfreebsd*-gnu | *-*-gnu* | *-*-kopensolaris*-gnu | *-*-uclinuxfdpiceabi) 123 | tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip t-slibgcc t-slibgcc-gld t-slibgcc-elf-ver t-linux" 124 | extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o" 125 | @@ -711,6 +716,9 @@ x86_64-*-elf* | x86_64-*-rtems*) 126 | x86_64-*-fuchsia*) 127 | tmake_file="$tmake_file t-libgcc-pic" 128 | ;; 129 | +x86_64-*-bestos*) 130 | + extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o" 131 | + tmake_file="$tmake_file i386/t-crtstuff" 132 | + ;; 133 | i[34567]86-*-dragonfly*) 134 | tmake_file="${tmake_file} i386/t-dragonfly i386/t-crtstuff" 135 | md_unwind_header=i386/dragonfly-unwind.h 136 | @@ -927,7 +935,7 @@ lm32-*-rtems*) 137 | lm32-*-uclinux*) 138 | extra_parts="$extra_parts crtbegin.o crtendS.o crtbeginT.o" 139 | tmake_file="lm32/t-lm32 lm32/t-uclinux t-libgcc-pic t-softfp-sfdf t-softfp" 140 | - ;; 141 | + ;; 142 | m32r-*-elf*) 143 | tmake_file="$tmake_file m32r/t-m32r t-fdpbit" 144 | extra_parts="$extra_parts crtinit.o crtfini.o" 145 | diff --git a/ports/gcc-orig/libstdc++-v3/crossconfig.m4 b/ports/gcc-workdir/libstdc++-v3/crossconfig.m4 146 | index fe18288..51d20bc 100644 147 | --- a/ports/gcc-orig/libstdc++-v3/crossconfig.m4 148 | +++ b/ports/gcc-workdir/libstdc++-v3/crossconfig.m4 149 | @@ -131,6 +131,14 @@ case "${host}" in 150 | AC_CHECK_FUNCS(sockatmark) 151 | ;; 152 | 153 | + *-bestos*) 154 | + GLIBCXX_CHECK_COMPILER_FEATURES 155 | + GLIBCXX_CHECK_LINKER_FEATURES 156 | + GLIBCXX_CHECK_MATH_SUPPORT 157 | + GLIBCXX_CHECK_STDLIB_SUPPORT 158 | + AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc) 159 | + ;; 160 | + 161 | *-fuchsia*) 162 | SECTION_FLAGS='-ffunction-sections -fdata-sections' 163 | AC_SUBST(SECTION_FLAGS) 164 | diff --git a/ports/gcc-orig/libtool.m4 b/ports/gcc-workdir/libtool.m4 165 | index e194e89..90e0fce 100644 166 | --- a/ports/gcc-orig/libtool.m4 167 | +++ b/ports/gcc-workdir/libtool.m4 168 | @@ -2499,6 +2499,16 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | uclinuxfdpiceabi) 169 | dynamic_linker='GNU/Linux ld.so' 170 | ;; 171 | 172 | +bestos*) 173 | + version_type=linux 174 | + need_lib_prefix=no 175 | + need_version=no 176 | + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' 177 | + soname_spec='${libname}${release}${shared_ext}$major' 178 | + shlibpath_var=LD_LIBRARY_PATH 179 | + hardcode_into_libs=yes 180 | + ;; 181 | + 182 | netbsd*) 183 | version_type=sunos 184 | need_lib_prefix=no 185 | @@ -3098,6 +3108,10 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | uclinuxfdpiceabi) 186 | lt_cv_deplibs_check_method=pass_all 187 | ;; 188 | 189 | +bestos*) 190 | + lt_cv_deplibs_check_method=pass_all 191 | + ;; 192 | + 193 | netbsd*) 194 | if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then 195 | lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' -------------------------------------------------------------------------------- /patches/mlibc/mlibc.patch: -------------------------------------------------------------------------------- 1 | diff --git a/ports/mlibc-orig/meson.build b/ports/mlibc-workdir/meson.build 2 | index b781895..8ebcb71 100644 3 | --- a/ports/mlibc-orig/meson.build 4 | +++ b/ports/mlibc-workdir/meson.build 5 | @@ -48,7 +48,7 @@ if not headers_only 6 | c_compiler = meson.get_compiler('c') 7 | 8 | add_project_arguments('-nostdinc', '-fno-builtin', language: ['c', 'cpp']) 9 | - add_project_arguments('-std=c++20', language: 'cpp') 10 | + add_project_arguments('-std=gnu++20', language: 'cpp') 11 | add_project_arguments('-fno-rtti', '-fno-exceptions', language: 'cpp') 12 | add_project_arguments('-Wall', '-Wextra', language: ['c', 'cpp']) 13 | add_project_link_arguments('-nostdlib', language: ['c', 'cpp']) 14 | @@ -110,6 +110,10 @@ elif host_machine.system() == 'qword' 15 | rtdl_include_dirs += include_directories('sysdeps/qword/include') 16 | libc_include_dirs += include_directories('sysdeps/qword/include') 17 | subdir('sysdeps/qword') 18 | +elif host_machine.system() == 'bestos' 19 | + rtdl_include_dirs += include_directories('sysdeps/bestos/include') 20 | + libc_include_dirs += include_directories('sysdeps/bestos/include') 21 | + subdir('sysdeps/bestos') 22 | elif host_machine.system() == 'sigma' 23 | #disable_linux_option = true 24 | rtdl_include_dirs += include_directories('sysdeps/sigma/include') 25 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/crt-x86_64/crt0.S b/ports/mlibc-workdir/sysdeps/bestos/crt-x86_64/crt0.S 26 | new file mode 100644 27 | index 0000000..0a0a4a0 28 | --- /dev/null 29 | +++ b/ports/mlibc-workdir/ports/mlibc-workdir/sysdeps/bestos/crt-x86_64/crt0.S 30 | @@ -0,0 +1,7 @@ 31 | + 32 | +.section .text 33 | +.global _start 34 | +_start: 35 | + mov $main, %rdi 36 | + call __mlibc_entry 37 | + 38 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/generic/entry.cpp b/ports/mlibc-workdir/sysdeps/bestos/generic/entry.cpp 39 | new file mode 100644 40 | index 0000000..ee7a794 41 | --- /dev/null 42 | +++ b/ports/mlibc-workdir/sysdeps/bestos/generic/entry.cpp 43 | @@ -0,0 +1,34 @@ 44 | + 45 | +#include 46 | +#include 47 | +#include 48 | +#include 49 | + 50 | +// defined by the POSIX library 51 | +void __mlibc_initLocale(); 52 | + 53 | +extern "C" uintptr_t *__dlapi_entrystack(); 54 | + 55 | +extern char **environ; 56 | +static mlibc::exec_stack_data __mlibc_stack_data; 57 | + 58 | +struct LibraryGuard { 59 | + LibraryGuard(); 60 | +}; 61 | + 62 | +static LibraryGuard guard; 63 | + 64 | +LibraryGuard::LibraryGuard() { 65 | + __mlibc_initLocale(); 66 | + 67 | + // Parse the exec() stack. 68 | + mlibc::parse_exec_stack(__dlapi_entrystack(), &__mlibc_stack_data); 69 | + mlibc::set_startup_data(__mlibc_stack_data.argc, __mlibc_stack_data.argv, 70 | + __mlibc_stack_data.envp); 71 | +} 72 | + 73 | +extern "C" void __mlibc_entry(int (*main_fn)(int argc, char *argv[], char *env[])) { 74 | + auto result = main_fn(__mlibc_stack_data.argc, __mlibc_stack_data.argv, environ); 75 | + exit(result); 76 | +} 77 | + 78 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/generic/generic.cpp b/ports/mlibc-workdir/sysdeps/bestos/generic/generic.cpp 79 | new file mode 100644 80 | index 0000000..d64e08d 81 | --- /dev/null 82 | +++ b/ports/mlibc-workdir/sysdeps/bestos/generic/generic.cpp 83 | @@ -0,0 +1,179 @@ 84 | +#include 85 | +#include 86 | +#include 87 | +#include 88 | +#include 89 | +#include 90 | +#include 91 | + 92 | +#define STUB_ONLY { __ensure(!"STUB_ONLY function was called"); __builtin_unreachable(); } 93 | +#define SYSCALL1(NUM, ARG0) ({ \ 94 | + asm volatile ("int $0x42" \ 95 | + : "=a"(ret), "=d"(errno) \ 96 | + : "a"(NUM), "D"(ARG0) \ 97 | + : "rcx", "r11", "memory"); \ 98 | +}) 99 | +#define SYSCALL2(NUM, ARG0, ARG1) ({ \ 100 | + asm volatile ("int $0x42" \ 101 | + : "=a"(ret), "=d"(errno) \ 102 | + : "a"(NUM), "D"(ARG0), "S"(ARG1) \ 103 | + : "rcx", "r11", "memory"); \ 104 | +}) 105 | + 106 | +#define SYSCALL3(NUM, ARG0, ARG1, ARG2) ({ \ 107 | + asm volatile ("int $0x42" \ 108 | + : "=a"(ret), "=d"(errno) \ 109 | + : "a"(NUM), "D"(ARG0), "S"(ARG1), "d"(ARG2) \ 110 | + : "rcx", "r11", "memory"); \ 111 | +}) 112 | + 113 | +#define SYSCALL4(NUM, ARG0, ARG1, ARG2, ARG3) ({ \ 114 | + register typeof(ARG3) arg3 asm("r10") = ARG3; \ 115 | + asm volatile ("int $0x42" \ 116 | + : "=a"(ret), "=d"(errno) \ 117 | + : "a"(NUM), "D"(ARG0), "S"(ARG1), "d"(ARG2), \ 118 | + "r"(arg3) \ 119 | + : "rcx", "r11", "memory"); \ 120 | +}) 121 | + 122 | +#define SYSCALL6(NUM, ARG0, ARG1, ARG2, ARG3, ARG4, ARG5) ({ \ 123 | + register typeof(ARG3) arg3 asm("r10") = ARG3; \ 124 | + register typeof(ARG4) arg4 asm("r8") = ARG4; \ 125 | + register typeof(ARG5) arg5 asm("r9") = ARG5; \ 126 | + asm volatile ("int $0x42" \ 127 | + : "=a"(ret), "=d"(errno) \ 128 | + : "a"(NUM), "D"(ARG0), "S"(ARG1), "d"(ARG2), \ 129 | + "r"(arg3), "r"(arg4), "r"(arg5) \ 130 | + : "rcx", "r11", "memory"); \ 131 | +}) 132 | +#define SYSCALL_LOG 0 133 | +#define SYSCALL_MMAP 1 134 | +#define SYSCALL_SET_FS_BASE 2 135 | +#define SYSCALL_OPENAT 3 136 | +#define SYSCALL_READ 4 137 | +#define SYSCALL_WRITE 5 138 | +#define SYSCALL_CLOSE 6 139 | +#define SYSCALL_SEEK 7 140 | +#define SYSCALL_EXIT 8 141 | +#define SYSCALL_EXECVE 9 142 | + 143 | +namespace mlibc { 144 | + 145 | +void sys_libc_log(const char *message) { 146 | + int ret, errno; 147 | + SYSCALL1(SYSCALL_LOG, message); 148 | +} 149 | + 150 | +void sys_libc_panic() { 151 | + sys_libc_log("\nMLIBC PANIC\n"); 152 | + for (;;); 153 | +} 154 | + 155 | +void sys_exit(int status) { 156 | + int ret, errno; 157 | + SYSCALL1(SYSCALL_EXIT, status); 158 | +} 159 | + 160 | +int sys_tcb_set(void *pointer) { 161 | + int ret, errno; 162 | + SYSCALL1(SYSCALL_SET_FS_BASE, pointer); 163 | + return 0; 164 | +} 165 | + 166 | +int sys_futex_wait(int *pointer, int expected) STUB_ONLY 167 | +int sys_futex_wake(int *pointer) STUB_ONLY 168 | + 169 | +int sys_ioctl(int fd, unsigned long request, void *arg, int *result) STUB_ONLY 170 | +int sys_isatty(int fd) 171 | +{ 172 | + if(fd == 0 || fd == 1 || fd == 2) return 0; 173 | + return ENOTTY; 174 | +} 175 | +int sys_openat(int dirfd, const char *path, int flags, int *fd) { 176 | + int ret; 177 | + int errno; 178 | + SYSCALL4(SYSCALL_OPENAT, dirfd, path, flags, 0); 179 | + if (ret == -1) 180 | + return errno; 181 | + *fd = ret; 182 | + return 0; 183 | +} 184 | + 185 | +int sys_open(const char *path, int flags, int *fd) { 186 | + return sys_openat(AT_FDCWD, path, flags, fd); 187 | +} 188 | +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) STUB_ONLY 189 | +int sys_close(int fd) { 190 | + int ret, errno; 191 | + SYSCALL1(SYSCALL_CLOSE, fd); 192 | + if (ret == -1) 193 | + return errno; 194 | + return 0; 195 | +} 196 | + 197 | +int sys_gethostname(char *buffer, size_t bufsize) { 198 | + const char *hostname = "bestos"; 199 | + for (size_t i = 0; i < bufsize; i++) { 200 | + buffer[i] = hostname[i]; 201 | + if (hostname[i] == 0) 202 | + break; 203 | + } 204 | + return 0; 205 | +} 206 | +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { 207 | + off_t ret; 208 | + int errno; 209 | + SYSCALL3(SYSCALL_SEEK, fd, offset, whence); 210 | + if (ret == -1) 211 | + return errno; 212 | + *new_offset = ret; 213 | + return 0; 214 | +} 215 | + 216 | +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { 217 | + ssize_t ret; 218 | + int errno; 219 | + SYSCALL3(SYSCALL_READ, fd, buf, count); 220 | + if (ret == -1) 221 | + return errno; 222 | + *bytes_read = ret; 223 | + return 0; 224 | +} 225 | + 226 | +int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written) { 227 | + ssize_t ret; 228 | + int errno; 229 | + SYSCALL3(SYSCALL_WRITE, fd, buf, count); 230 | + if (ret == -1) 231 | + return errno; 232 | + *bytes_written = ret; 233 | + return 0; 234 | +} 235 | + 236 | +int sys_vm_map(void *hint, size_t size, int prot, int flags, 237 | + int fd, off_t offset, void **window) { 238 | + void *ret; 239 | + int errno; 240 | + SYSCALL6(SYSCALL_MMAP, hint, size, prot, flags, fd, offset); 241 | + if (ret == NULL) 242 | + return errno; 243 | + *window = ret; 244 | + return 0; 245 | +} 246 | + 247 | +int sys_vm_unmap(void *pointer, size_t size) STUB_ONLY 248 | + 249 | +int sys_anon_allocate(size_t size, void **pointer) { 250 | + int errno = sys_vm_map(NULL, size, PROT_EXEC | PROT_READ | PROT_WRITE, 251 | + MAP_ANONYMOUS, -1, 0, pointer); 252 | + return errno; 253 | +} 254 | +int sys_execve(const char *path, char *const argv[], char *const envp[]) { 255 | + int errno, ret; 256 | + SYSCALL3(SYSCALL_EXECVE, path, argv, envp); 257 | + return errno; 258 | +} 259 | +int sys_anon_free(void *pointer, size_t size) STUB_ONLY 260 | +int sys_clock_get(int clock, time_t *secs, long *nanos) STUB_ONLY 261 | + 262 | +} // namespace mlibc 263 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/abi.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/abi.h 264 | new file mode 120000 265 | index 0000000..c945860 266 | --- /dev/null 267 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/abi.h 268 | @@ -0,0 +1 @@ 269 | +../../../../abis/mlibc/abi.h 270 | \ No newline at end of file 271 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/auxv.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/auxv.h 272 | new file mode 120000 273 | index 0000000..b7bb109 274 | --- /dev/null 275 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/auxv.h 276 | @@ -0,0 +1 @@ 277 | +../../../../abis/qword/auxv.h 278 | \ No newline at end of file 279 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/blkcnt_t.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/blkcnt_t.h 280 | new file mode 120000 281 | index 0000000..e9d9f1b 282 | --- /dev/null 283 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/blkcnt_t.h 284 | @@ -0,0 +1 @@ 285 | +../../../../abis/mlibc/blkcnt_t.h 286 | \ No newline at end of file 287 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/blksize_t.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/blksize_t.h 288 | new file mode 120000 289 | index 0000000..c6dfb6e 290 | --- /dev/null 291 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/blksize_t.h 292 | @@ -0,0 +1 @@ 293 | +../../../../abis/mlibc/blksize_t.h 294 | \ No newline at end of file 295 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/dev_t.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/dev_t.h 296 | new file mode 120000 297 | index 0000000..0c1143b 298 | --- /dev/null 299 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/dev_t.h 300 | @@ -0,0 +1 @@ 301 | +../../../../abis/mlibc/dev_t.h 302 | \ No newline at end of file 303 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/errno.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/errno.h 304 | new file mode 120000 305 | index 0000000..589859f 306 | --- /dev/null 307 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/errno.h 308 | @@ -0,0 +1 @@ 309 | +../../../../abis/mlibc/errno.h 310 | \ No newline at end of file 311 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/fcntl.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/fcntl.h 312 | new file mode 120000 313 | index 0000000..ea5323a 314 | --- /dev/null 315 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/fcntl.h 316 | @@ -0,0 +1 @@ 317 | +../../../../abis/mlibc/fcntl.h 318 | \ No newline at end of file 319 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/gid_t.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/gid_t.h 320 | new file mode 120000 321 | index 0000000..6a77218 322 | --- /dev/null 323 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/gid_t.h 324 | @@ -0,0 +1 @@ 325 | +../../../../abis/mlibc/gid_t.h 326 | \ No newline at end of file 327 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/in.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/in.h 328 | new file mode 120000 329 | index 0000000..b58c683 330 | --- /dev/null 331 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/in.h 332 | @@ -0,0 +1 @@ 333 | +../../../../abis/mlibc/in.h 334 | \ No newline at end of file 335 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/ino_t.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/ino_t.h 336 | new file mode 120000 337 | index 0000000..10d644e 338 | --- /dev/null 339 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/ino_t.h 340 | @@ -0,0 +1 @@ 341 | +../../../../abis/mlibc/ino_t.h 342 | \ No newline at end of file 343 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/limits.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/limits.h 344 | new file mode 120000 345 | index 0000000..1aa5894 346 | --- /dev/null 347 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/limits.h 348 | @@ -0,0 +1 @@ 349 | +../../../../abis/mlibc/limits.h 350 | \ No newline at end of file 351 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/mode_t.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/mode_t.h 352 | new file mode 120000 353 | index 0000000..29d7733 354 | --- /dev/null 355 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/mode_t.h 356 | @@ -0,0 +1 @@ 357 | +../../../../abis/mlibc/mode_t.h 358 | \ No newline at end of file 359 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/nlink_t.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/nlink_t.h 360 | new file mode 120000 361 | index 0000000..7618c27 362 | --- /dev/null 363 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/nlink_t.h 364 | @@ -0,0 +1 @@ 365 | +../../../../abis/mlibc/nlink_t.h 366 | \ No newline at end of file 367 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/pid_t.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/pid_t.h 368 | new file mode 120000 369 | index 0000000..3fd26a7 370 | --- /dev/null 371 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/pid_t.h 372 | @@ -0,0 +1 @@ 373 | +../../../../abis/mlibc/pid_t.h 374 | \ No newline at end of file 375 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/reboot.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/reboot.h 376 | new file mode 120000 377 | index 0000000..ecc3ddb 378 | --- /dev/null 379 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/reboot.h 380 | @@ -0,0 +1 @@ 381 | +../../../../abis/linux/x86_64/reboot.h 382 | \ No newline at end of file 383 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/resource.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/resource.h 384 | new file mode 120000 385 | index 0000000..3e59c75 386 | --- /dev/null 387 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/resource.h 388 | @@ -0,0 +1 @@ 389 | +../../../../abis/mlibc/resource.h 390 | \ No newline at end of file 391 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/seek-whence.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/seek-whence.h 392 | new file mode 120000 393 | index 0000000..3bd41ef 394 | --- /dev/null 395 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/seek-whence.h 396 | @@ -0,0 +1 @@ 397 | +../../../../abis/mlibc/seek-whence.h 398 | \ No newline at end of file 399 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/signal.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/signal.h 400 | new file mode 120000 401 | index 0000000..b20e511 402 | --- /dev/null 403 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/signal.h 404 | @@ -0,0 +1 @@ 405 | +../../../../abis/mlibc/signal.h 406 | \ No newline at end of file 407 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/socket.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/socket.h 408 | new file mode 120000 409 | index 0000000..0e1d6be 410 | --- /dev/null 411 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/socket.h 412 | @@ -0,0 +1 @@ 413 | +../../../../abis/mlibc/socket.h 414 | \ No newline at end of file 415 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/stat.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/stat.h 416 | new file mode 120000 417 | index 0000000..82642c3 418 | --- /dev/null 419 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/stat.h 420 | @@ -0,0 +1 @@ 421 | +../../../../abis/mlibc/stat.h 422 | \ No newline at end of file 423 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/termios.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/termios.h 424 | new file mode 120000 425 | index 0000000..cfcfe76 426 | --- /dev/null 427 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/termios.h 428 | @@ -0,0 +1 @@ 429 | +../../../../abis/mlibc/termios.h 430 | \ No newline at end of file 431 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/time.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/time.h 432 | new file mode 120000 433 | index 0000000..97f3d52 434 | --- /dev/null 435 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/time.h 436 | @@ -0,0 +1 @@ 437 | +../../../../abis/mlibc/time.h 438 | \ No newline at end of file 439 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/uid_t.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/uid_t.h 440 | new file mode 120000 441 | index 0000000..1113eba 442 | --- /dev/null 443 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/uid_t.h 444 | @@ -0,0 +1 @@ 445 | +../../../../abis/mlibc/uid_t.h 446 | \ No newline at end of file 447 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/vm-flags.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/vm-flags.h 448 | new file mode 120000 449 | index 0000000..f1a985e 450 | --- /dev/null 451 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/vm-flags.h 452 | @@ -0,0 +1 @@ 453 | +../../../../abis/mlibc/vm-flags.h 454 | \ No newline at end of file 455 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/wait.h b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/wait.h 456 | new file mode 120000 457 | index 0000000..6d911c7 458 | --- /dev/null 459 | +++ b/ports/mlibc-workdir/sysdeps/bestos/include/abi-bits/wait.h 460 | @@ -0,0 +1 @@ 461 | +../../../../abis/mlibc/wait.h 462 | \ No newline at end of file 463 | diff --git a/ports/mlibc-workdir/sysdeps/bestos/meson.build b/ports/mlibc-workdir/sysdeps/bestos/meson.build 464 | new file mode 100644 465 | index 0000000..0169278 466 | --- /dev/null 467 | +++ b/ports/mlibc-workdir/sysdeps/bestos/meson.build 468 | @@ -0,0 +1,52 @@ 469 | + 470 | +rtdl_sources += files( 471 | + 'generic/generic.cpp' 472 | +) 473 | + 474 | +libc_sources += files( 475 | + 'generic/entry.cpp', 476 | + 'generic/generic.cpp' 477 | +) 478 | + 479 | +if not no_headers 480 | + install_headers( 481 | + 'include/abi-bits/abi.h', 482 | + 'include/abi-bits/auxv.h', 483 | + 'include/abi-bits/seek-whence.h', 484 | + 'include/abi-bits/vm-flags.h', 485 | + 'include/abi-bits/errno.h', 486 | + 'include/abi-bits/fcntl.h', 487 | + 'include/abi-bits/in.h', 488 | + 'include/abi-bits/reboot.h', 489 | + 'include/abi-bits/resource.h', 490 | + 'include/abi-bits/stat.h', 491 | + 'include/abi-bits/signal.h', 492 | + 'include/abi-bits/socket.h', 493 | + 'include/abi-bits/termios.h', 494 | + 'include/abi-bits/time.h', 495 | + 'include/abi-bits/blkcnt_t.h', 496 | + 'include/abi-bits/blksize_t.h', 497 | + 'include/abi-bits/dev_t.h', 498 | + 'include/abi-bits/gid_t.h', 499 | + 'include/abi-bits/ino_t.h', 500 | + 'include/abi-bits/mode_t.h', 501 | + 'include/abi-bits/nlink_t.h', 502 | + 'include/abi-bits/pid_t.h', 503 | + 'include/abi-bits/uid_t.h', 504 | + 'include/abi-bits/wait.h', 505 | + 'include/abi-bits/limits.h', 506 | + subdir: 'abi-bits' 507 | + ) 508 | +endif 509 | + 510 | + 511 | +if not headers_only 512 | + crt = custom_target('crt0', 513 | + build_by_default: true, 514 | + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], 515 | + input: 'crt-x86_64/crt0.S', 516 | + output: 'crt0.o', 517 | + install: true, 518 | + install_dir: get_option('libdir') 519 | + ) 520 | +endif 521 | + 522 | -------------------------------------------------------------------------------- /src/apps/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) 6 | { 7 | 8 | puts("Welcome to bestOS, starting shell.."); 9 | 10 | char hostname[10]; 11 | gethostname(hostname, 10); 12 | 13 | while (1) 14 | { 15 | char *command = malloc(256); 16 | 17 | printf("user@%s$ ", hostname); 18 | 19 | fflush(stdout); 20 | 21 | read(0, command, 256); 22 | 23 | printf("running: %s\n", command); 24 | 25 | free(command); 26 | } 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /src/apps/makefile: -------------------------------------------------------------------------------- 1 | CC = ../../sysroot/tools/host-gcc/bin/x86_64-bestos-gcc 2 | 3 | all: ../root/bin/sh ../root/bin/init 4 | .DEFAULT = all 5 | 6 | ../root/bin/init: init.c 7 | mkdir -p $(@D) 8 | $(CC) -o $@ $< 9 | 10 | ../root/bin/sh: sh.c 11 | mkdir -p $(@D) 12 | $(CC) -o $@ $< 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/apps/sh.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | printf("Hello I am da shell\n"); 6 | 7 | return 0; 8 | } -------------------------------------------------------------------------------- /src/kernel/arch/arch.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_H 2 | #define ARCH_H 3 | #include 4 | #include 5 | 6 | #define PAGE_SIZE 4096 7 | // lmao 8 | #define USER_STACK_TOP (uintptr_t)((uintptr_t)((uintptr_t)1 << (uintptr_t)47) - 8192) 9 | 10 | typedef struct PACKED 11 | { 12 | uint64_t r15; 13 | uint64_t r14; 14 | uint64_t r13; 15 | uint64_t r12; 16 | uint64_t r11; 17 | uint64_t r10; 18 | uint64_t r9; 19 | uint64_t r8; 20 | uint64_t rbp; 21 | uint64_t rdi; 22 | uint64_t rsi; 23 | uint64_t rdx; 24 | uint64_t rcx; 25 | uint64_t rbx; 26 | uint64_t rax; 27 | 28 | uint64_t intno; 29 | uint64_t err; 30 | 31 | uint64_t rip; 32 | uint64_t cs; 33 | uint64_t rflags; 34 | uint64_t rsp; 35 | uint64_t ss; 36 | } Stack; 37 | 38 | #define STACK_SIZE 0x4000 39 | 40 | #endif -------------------------------------------------------------------------------- /src/kernel/arch/asm.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static inline void asm_cli(void) { asm volatile("cli"); } 4 | 5 | static inline void asm_sti(void) { asm volatile("sti"); } 6 | 7 | static inline void asm_hlt(void) { asm volatile("hlt"); } 8 | 9 | static inline void asm_pause(void) { asm volatile("pause"); } 10 | 11 | static inline uint8_t asm_in8(uint16_t port) 12 | { 13 | uint8_t data; 14 | asm volatile("inb %1, %0" 15 | : "=a"(data) 16 | : "d"(port)); 17 | return data; 18 | } 19 | 20 | static inline uint16_t asm_in16(uint16_t port) 21 | { 22 | uint16_t data; 23 | asm volatile("inw %1, %0" 24 | : "=a"(data) 25 | : "d"(port)); 26 | return data; 27 | } 28 | 29 | static inline uint32_t asm_in32(uint16_t port) 30 | { 31 | uint32_t data; 32 | asm volatile("inl %1, %0" 33 | : "=a"(data) 34 | : "d"(port)); 35 | return data; 36 | } 37 | 38 | static inline void asm_out8(uint16_t port, uint8_t data) 39 | { 40 | asm volatile("outb %0, %1" 41 | : 42 | : "a"(data), "d"(port)); 43 | } 44 | 45 | static inline void asm_out16(uint16_t port, uint16_t data) 46 | { 47 | asm volatile("outw %0, %1" 48 | : 49 | : "a"(data), "d"(port)); 50 | } 51 | 52 | static inline void asm_out32(uint16_t port, uint32_t data) 53 | { 54 | asm volatile("outl %0, %1" 55 | : 56 | : "a"(data), "d"(port)); 57 | } 58 | 59 | #define ASM_MAKE_CRN(N) \ 60 | static inline uint64_t asm_read_cr##N(void) \ 61 | { \ 62 | uint64_t value = 0; \ 63 | asm volatile("mov %%cr" #N ", %0" \ 64 | : "=r"(value)); \ 65 | return value; \ 66 | } \ 67 | \ 68 | static inline void asm_write_cr##N(uint64_t value) \ 69 | { \ 70 | asm volatile("mov %0, %%cr" #N ::"a"(value)); \ 71 | } 72 | 73 | ASM_MAKE_CRN(0); 74 | ASM_MAKE_CRN(1); 75 | ASM_MAKE_CRN(2); 76 | ASM_MAKE_CRN(3); 77 | 78 | static inline void asm_write_msr(uint32_t msr, uint64_t value) 79 | { 80 | uint32_t edx = value >> 32; 81 | uint32_t eax = (uint32_t)value; 82 | asm volatile("wrmsr" 83 | : 84 | : "a"(eax), "d"(edx), "c"(msr) 85 | : "memory"); 86 | } 87 | -------------------------------------------------------------------------------- /src/kernel/arch/devices/com.c: -------------------------------------------------------------------------------- 1 | #include "lib/print.h" 2 | #include 3 | #include 4 | 5 | #define PORT 0x3F8 6 | 7 | static int is_transmit_empty() 8 | { 9 | return asm_in8(PORT + 5) & 0x20; 10 | } 11 | 12 | static int serial_received() 13 | { 14 | return asm_in8(PORT + 5) & 1; 15 | } 16 | 17 | void com_initialize() 18 | { 19 | asm_out8(PORT + 1, 0x00); 20 | asm_out8(PORT + 3, 0x80); 21 | asm_out8(PORT + 0, 0x03); 22 | asm_out8(PORT + 1, 0x00); 23 | asm_out8(PORT + 3, 0x03); 24 | asm_out8(PORT + 2, 0xC7); 25 | asm_out8(PORT + 4, 0x0B); 26 | } 27 | void com_putc(char c) 28 | { 29 | while (is_transmit_empty() == 0) 30 | ; 31 | asm_out8(PORT, c); 32 | } 33 | 34 | void com_write_string(char *str) 35 | { 36 | while (*str) 37 | { 38 | com_putc(*str++); 39 | } 40 | } 41 | 42 | char com_getc() 43 | { 44 | while (serial_received() == 0) 45 | ; 46 | return asm_in8(PORT); 47 | } 48 | 49 | void host_print(char *str, size_t s) 50 | { 51 | (void)s; 52 | 53 | com_write_string(str); 54 | } 55 | 56 | char host_getc() 57 | { 58 | return com_getc(); 59 | } -------------------------------------------------------------------------------- /src/kernel/arch/devices/com.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_COM_H 2 | #define KERNEL_COM_H 3 | 4 | void com_initialize(void); 5 | void com_write_string(char *s); 6 | char com_getc(); 7 | 8 | void com_putc(char c); 9 | 10 | #endif -------------------------------------------------------------------------------- /src/kernel/arch/devices/pic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void pic_remap(void) 6 | { 7 | asm_out8(0x20, 0x11); 8 | asm_out8(0xA0, 0x11); 9 | asm_out8(0x21, 0x20); 10 | asm_out8(0xA1, 0x28); 11 | asm_out8(0x21, 0x04); 12 | asm_out8(0xA1, 0x02); 13 | asm_out8(0x21, 0x01); 14 | asm_out8(0xA1, 0x01); 15 | asm_out8(0x21, 0x0); 16 | asm_out8(0xA1, 0x0); 17 | } 18 | 19 | void pic_initialize(void) 20 | { 21 | pic_remap(); 22 | 23 | int divisor = 1193180 / 1000; 24 | 25 | asm_out8(0x43, 0x36); 26 | asm_out8(0x40, divisor & 0xff); 27 | asm_out8(0x40, (divisor >> 8) & 0xFF); 28 | } 29 | 30 | void pic_eoi(int intno) 31 | { 32 | if (intno >= 40) 33 | { 34 | asm_out8(0xA0, 0x20); 35 | } 36 | 37 | asm_out8(0x20, 0x20); 38 | } 39 | -------------------------------------------------------------------------------- /src/kernel/arch/devices/pic.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_PIC_H 2 | #define KERNEL_PIC_H 3 | 4 | void pic_initialize(void); 5 | void pic_eoi(int intno); 6 | 7 | #endif -------------------------------------------------------------------------------- /src/kernel/arch/gdt.asm: -------------------------------------------------------------------------------- 1 | bits 64 2 | 3 | global gdt_update 4 | gdt_update: 5 | lgdt [rdi] 6 | mov ax, 0x30 7 | mov ss, ax 8 | mov ds, ax 9 | mov es, ax 10 | pop rdi 11 | mov rax, 0x28 12 | push rax 13 | push rdi 14 | retfq 15 | 16 | global tss_update 17 | tss_update: 18 | mov ax, 0x48 19 | ltr ax 20 | ret -------------------------------------------------------------------------------- /src/kernel/arch/gdt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | Gdt gdt = { 5 | {{0x0000, 0, 0, 0x00, 0x00, 0}, // NULL 6 | {0xFFFF, 0, 0, 0x9A, 0x00, 0}, // 16 Bit code 7 | {0xFFFF, 0, 0, 0x92, 0x00, 0}, // 16 Bit data 8 | {0xFFFF, 0, 0, 0x9A, 0xCF, 0}, // 32 Bit code 9 | {0xFFFF, 0, 0, 0x92, 0xCF, 0}, // 32 Bit data 10 | {0x0000, 0, 0, 0x9A, 0x20, 0}, // 64 Bit code 11 | {0x0000, 0, 0, 0x92, 0x00, 0}, // 64 Bit data 12 | {0x0000, 0, 0, 0xF2, 0x00, 0}, // User data 13 | {0x0000, 0, 0, 0xFA, 0x20, 0}}, // User code 14 | {0x0000, 0, 0, 0x89, 0x00, 0, 0, 0}}; // TSS 15 | 16 | GdtPointer gdtr = {}; 17 | 18 | static Tss tss = { 19 | .reserved = 0, 20 | .rsp = {}, 21 | .reserved0 = 0, 22 | .ist = {}, 23 | .reserved1 = 0, 24 | .reserved2 = 0, 25 | .reserved3 = 0, 26 | .iopb_offset = 0, 27 | }; 28 | 29 | TssEntry make_tss_entry(uintptr_t tss) 30 | { 31 | return (TssEntry){ 32 | .length = sizeof(TssEntry), 33 | .base0 = (tss & 0xffff), 34 | .base1 = ((tss >> 16) & 0xff), 35 | .flags1 = 0b10001001, 36 | .flags2 = 0, 37 | .base2 = ((tss >> 24) & 0xff), 38 | .base3 = (tss >> 32), 39 | .reserved = 0, 40 | }; 41 | } 42 | 43 | extern void gdt_update(uint64_t); 44 | extern void tss_update(); 45 | 46 | void gdt_initialize(uint8_t *stack, size_t size) 47 | { 48 | gdtr.base = (uint64_t)&gdt; 49 | gdtr.limit = sizeof(gdt) - 1; 50 | 51 | gdt.tss = make_tss_entry((uintptr_t)&tss); 52 | 53 | memset(&tss, 0, sizeof(tss)); 54 | 55 | tss.rsp[0] = (uintptr_t)(stack + size); 56 | 57 | tss.iopb_offset = sizeof(tss); 58 | 59 | gdt_update((uint64_t)&gdtr); 60 | tss_update(); 61 | } -------------------------------------------------------------------------------- /src/kernel/arch/gdt.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_GDT_H 2 | #define KERNEL_GDT_H 3 | #include 4 | 5 | typedef struct PACKED 6 | { 7 | uint16_t limit; 8 | uintptr_t base; 9 | } GdtPointer; 10 | 11 | typedef struct PACKED 12 | { 13 | uint16_t limit0; 14 | uint16_t base0; 15 | uint8_t base1; 16 | uint8_t access; 17 | uint8_t granularity; 18 | uint8_t base2; 19 | } GdtDescriptor; 20 | 21 | typedef struct 22 | { 23 | uint16_t length; 24 | uint16_t base0; 25 | uint8_t base1; 26 | uint8_t flags1; 27 | uint8_t flags2; 28 | uint8_t base2; 29 | uint32_t base3; 30 | uint32_t reserved; 31 | } TssEntry; 32 | 33 | typedef struct 34 | { 35 | GdtDescriptor entries[9]; 36 | TssEntry tss; 37 | } Gdt; 38 | 39 | typedef struct PACKED 40 | { 41 | uint32_t reserved; 42 | 43 | uint64_t rsp[3]; 44 | 45 | uint64_t reserved0; 46 | 47 | uint64_t ist[7]; 48 | 49 | uint32_t reserved1; 50 | uint32_t reserved2; 51 | uint16_t reserved3; 52 | 53 | uint16_t iopb_offset; 54 | } Tss; 55 | 56 | void gdt_initialize(uint8_t *stack, size_t size); 57 | 58 | #endif -------------------------------------------------------------------------------- /src/kernel/arch/idt.asm: -------------------------------------------------------------------------------- 1 | bits 64 2 | %macro INTERRUPT_NAME 1 3 | dq __interrupt%1 4 | %endmacro 5 | 6 | %macro INTERRUPT_ERR 1 7 | __interrupt%1: 8 | push qword %1 9 | jmp __interrupt_common 10 | %endmacro 11 | 12 | %macro INTERRUPT_NOERR 1 13 | __interrupt%1: 14 | push qword 0 ; no error 15 | push qword %1 16 | jmp __interrupt_common 17 | %endmacro 18 | 19 | %macro pushaq 0 20 | push rax 21 | push rbx 22 | push rcx 23 | push rdx 24 | push rsi 25 | push rdi 26 | push rbp 27 | push r8 28 | push r9 29 | push r10 30 | push r11 31 | push r12 32 | push r13 33 | push r14 34 | push r15 35 | %endmacro 36 | 37 | %macro popaq 0 38 | pop r15 39 | pop r14 40 | pop r13 41 | pop r12 42 | pop r11 43 | pop r10 44 | pop r9 45 | pop r8 46 | pop rbp 47 | pop rdi 48 | pop rsi 49 | pop rdx 50 | pop rcx 51 | pop rbx 52 | pop rax 53 | %endmacro 54 | 55 | extern interrupts_handler 56 | 57 | __interrupt_common: 58 | 59 | cld 60 | 61 | pushaq 62 | 63 | mov rdi, rsp 64 | 65 | call interrupts_handler 66 | 67 | mov rsp, rax 68 | 69 | popaq 70 | 71 | add rsp, 16 ; pop errcode and int number 72 | 73 | iretq 74 | 75 | INTERRUPT_NOERR 0 76 | INTERRUPT_NOERR 1 77 | INTERRUPT_NOERR 2 78 | INTERRUPT_NOERR 3 79 | INTERRUPT_NOERR 4 80 | INTERRUPT_NOERR 5 81 | INTERRUPT_NOERR 6 82 | INTERRUPT_NOERR 7 83 | INTERRUPT_ERR 8 84 | INTERRUPT_NOERR 9 85 | INTERRUPT_ERR 10 86 | INTERRUPT_ERR 11 87 | INTERRUPT_ERR 12 88 | INTERRUPT_ERR 13 89 | INTERRUPT_ERR 14 90 | INTERRUPT_NOERR 15 91 | INTERRUPT_NOERR 16 92 | INTERRUPT_ERR 17 93 | INTERRUPT_NOERR 18 94 | INTERRUPT_NOERR 19 95 | INTERRUPT_NOERR 20 96 | INTERRUPT_NOERR 21 97 | INTERRUPT_NOERR 22 98 | INTERRUPT_NOERR 23 99 | INTERRUPT_NOERR 24 100 | INTERRUPT_NOERR 25 101 | INTERRUPT_NOERR 26 102 | INTERRUPT_NOERR 27 103 | INTERRUPT_NOERR 28 104 | INTERRUPT_NOERR 29 105 | INTERRUPT_ERR 30 106 | INTERRUPT_NOERR 31 107 | 108 | %assign i 32 109 | %rep 224 110 | INTERRUPT_NOERR i 111 | %assign i i+1 112 | %endrep 113 | 114 | 115 | section .data 116 | global __interrupt_vector 117 | 118 | __interrupt_vector: 119 | %assign i 0 120 | %rep 256 121 | INTERRUPT_NAME i 122 | %assign i i+1 123 | %endrep 124 | 125 | global idt_flush 126 | idt_flush: 127 | lidt [rdi] 128 | ret -------------------------------------------------------------------------------- /src/kernel/arch/idt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern void idt_flush(uintptr_t idt_ptr); 5 | 6 | static IdtDescriptor idt[256]; 7 | 8 | static IdtPointer idtr; 9 | 10 | extern uintptr_t __interrupt_vector[]; 11 | 12 | static IdtDescriptor idt_make_entry(uint64_t offset, uint8_t type) 13 | { 14 | return (IdtDescriptor){ 15 | .offset_lo = offset & 0xFFFF, 16 | .selector = 0x28, 17 | .ist = 0, 18 | .type_attr = type, 19 | .offset_mid = (offset >> 16) & 0xFFFF, 20 | .offset_hi = (offset >> 32) & 0xFFFFFFFF, 21 | .zero = 0}; 22 | } 23 | 24 | void install_isr(void) 25 | { 26 | foreach (i, 256) 27 | { 28 | idt[i] = idt_make_entry(__interrupt_vector[i], INTGATE); 29 | } 30 | idt[66] = idt_make_entry(__interrupt_vector[66], TRAPGATE); 31 | } 32 | 33 | void idt_initialize() 34 | { 35 | idtr.size = (256 * sizeof(IdtDescriptor)) - 1; 36 | 37 | idtr.addr = (uint64_t)idt; 38 | 39 | install_isr(); 40 | 41 | idt_flush((uintptr_t)&idtr); 42 | 43 | asm_sti(); 44 | } -------------------------------------------------------------------------------- /src/kernel/arch/idt.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_IDT_H 2 | #define KERNEL_IDT_H 3 | #include 4 | 5 | #define INTGATE 0x8e 6 | #define TRAPGATE 0xef 7 | 8 | typedef struct PACKED 9 | { 10 | uint16_t size; 11 | uint64_t addr; 12 | } IdtPointer; 13 | 14 | typedef struct PACKED 15 | { 16 | uint16_t offset_lo; 17 | uint16_t selector; 18 | uint8_t ist; 19 | uint8_t type_attr; 20 | uint16_t offset_mid; 21 | uint32_t offset_hi; 22 | uint32_t zero; 23 | } IdtDescriptor; 24 | 25 | void idt_initialize(void); 26 | 27 | #endif -------------------------------------------------------------------------------- /src/kernel/arch/interrupts.c: -------------------------------------------------------------------------------- 1 | #include "syscalls.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | Task *prev_task = NULL; 9 | 10 | uint64_t interrupts_handler(uint64_t rsp) 11 | { 12 | Stack *stack = (Stack *)rsp; 13 | 14 | if (stack->intno < 32) 15 | { 16 | log("\033[1;31mPANIC !!! \033[0mit's not a bug, it's a feature (%x)", stack->intno); 17 | 18 | while (1) 19 | { 20 | asm_cli(); 21 | asm_hlt(); 22 | } 23 | } 24 | 25 | if (stack->intno == 32) 26 | { 27 | if (sched_started()) 28 | { 29 | if (prev_task) 30 | { 31 | prev_task->stack = *stack; 32 | asm volatile(" fxsave %0 " ::"m"(prev_task->fpu_storage)); 33 | } 34 | 35 | Task *new_task = sched_tick(); 36 | 37 | prev_task = new_task; 38 | 39 | *stack = new_task->stack; 40 | 41 | asm volatile("fxrstor %0" 42 | : 43 | : "m"(new_task->fpu_storage) 44 | : "memory"); 45 | 46 | asm_write_cr3((uint64_t)new_task->pagemap - MMAP_KERNEL_BASE); 47 | } 48 | } 49 | 50 | if (stack->intno == 0x42) 51 | { 52 | syscall_dispatch(stack->rax, stack); 53 | } 54 | 55 | else 56 | { 57 | pic_eoi(stack->intno); 58 | } 59 | 60 | return rsp; 61 | } -------------------------------------------------------------------------------- /src/kernel/arch/memory.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_MEMORY_H 2 | #define KERNEL_MEMORY_H 3 | 4 | #define MMAP_IO_BASE ((uintptr_t)0xffff800000000000) 5 | #define MMAP_KERNEL_BASE ((uintptr_t)0xffffffff80000000) 6 | 7 | #include 8 | #include 9 | 10 | #endif -------------------------------------------------------------------------------- /src/kernel/arch/memory/pmm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define BIT_SET(BIT, MAP) (MAP[(BIT) / 8] |= (1 << ((BIT) % 8))) 8 | #define BIT_CLEAR(BIT, MAP) (MAP[(BIT) / 8] &= ~(1 << ((BIT) % 8))) 9 | #define BIT_TEST(BIT, MAP) ((MAP[(BIT) / 8] >> ((BIT) % 8)) & 1) 10 | 11 | static uintptr_t highest_page = 0; 12 | static size_t usable_pages = 0; 13 | 14 | struct 15 | { 16 | uint8_t *data; 17 | size_t size; 18 | } bitmap; 19 | 20 | void clear_page(void *addr) 21 | { 22 | BIT_CLEAR((uint64_t)addr / PAGE_SIZE, bitmap.data); 23 | usable_pages++; 24 | } 25 | 26 | void set_page(void *addr) 27 | { 28 | BIT_SET((uint64_t)addr / PAGE_SIZE, bitmap.data); 29 | usable_pages--; 30 | } 31 | 32 | void set_pages(void *addr, size_t page_count) 33 | { 34 | size_t i; 35 | for (i = 0; i < page_count; i++) 36 | { 37 | set_page((void *)(addr + (i * PAGE_SIZE))); 38 | } 39 | } 40 | 41 | void pmm_free(void *addr, size_t pages) 42 | { 43 | size_t i; 44 | for (i = 0; i < pages; i++) 45 | { 46 | clear_page((void *)(addr + (i * PAGE_SIZE))); 47 | } 48 | } 49 | 50 | void *pmm_allocate(size_t pages) 51 | { 52 | if (pages > bitmap.size) 53 | { 54 | log("pmm_allocate(%d): allocation too big", bitmap.size); 55 | return NULL; 56 | } 57 | 58 | for (size_t i = 0; i < highest_page / PAGE_SIZE; i++) 59 | { 60 | for (size_t j = 0; j < pages; j++) 61 | { 62 | if (BIT_TEST(i, bitmap.data)) 63 | { 64 | break; 65 | } 66 | 67 | else if (j == pages - 1) 68 | { 69 | void *ret = (void *)(i * PAGE_SIZE); 70 | 71 | set_pages(ret, pages); 72 | 73 | return ret; 74 | } 75 | } 76 | } 77 | 78 | return NULL; 79 | } 80 | 81 | void *pmm_allocate_zero(size_t pages) 82 | { 83 | void *ret = pmm_allocate(pages); 84 | 85 | memset(ret + MMAP_IO_BASE, 0, pages * PAGE_SIZE); 86 | 87 | return ret; 88 | } 89 | 90 | void pmm_initialize(struct stivale2_struct *bootinfo) 91 | { 92 | uintptr_t top = 0; 93 | 94 | struct stivale2_struct_tag_memmap *memory_map = stivale2_get_tag(bootinfo, STIVALE2_STRUCT_TAG_MEMMAP_ID); 95 | 96 | foreach (i, memory_map->entries) 97 | { 98 | struct stivale2_mmap_entry *entry = &memory_map->memmap[i]; 99 | 100 | if (entry->type != STIVALE2_MMAP_USABLE && entry->type != STIVALE2_MMAP_BOOTLOADER_RECLAIMABLE && entry->type != STIVALE2_MMAP_KERNEL_AND_MODULES) 101 | { 102 | continue; 103 | } 104 | 105 | top = entry->base + entry->length; 106 | 107 | if (top > highest_page) 108 | { 109 | highest_page = top; 110 | } 111 | } 112 | 113 | size_t bitmap_size = ALIGN_UP(ALIGN_DOWN(highest_page, PAGE_SIZE) / PAGE_SIZE / 8, PAGE_SIZE); 114 | 115 | if (bitmap_size == 0) 116 | { 117 | log("PANIC bitmap_size == 0"); 118 | 119 | while (1) 120 | { 121 | asm_hlt(); 122 | } 123 | } 124 | 125 | bitmap.size = bitmap_size; 126 | 127 | foreach (i, memory_map->entries) 128 | { 129 | struct stivale2_mmap_entry *entry = &memory_map->memmap[i]; 130 | 131 | if (entry->type == STIVALE2_MMAP_USABLE && entry->length >= bitmap_size) 132 | { 133 | bitmap.data = (uint8_t *)(entry->base + MMAP_IO_BASE); 134 | entry->base += bitmap_size; 135 | entry->length -= bitmap_size; 136 | break; 137 | } 138 | } 139 | 140 | memset(bitmap.data, 0xff, bitmap.size); 141 | 142 | foreach (i, memory_map->entries) 143 | { 144 | if (memory_map->memmap[i].type == STIVALE2_MMAP_USABLE) 145 | { 146 | pmm_free((void *)memory_map->memmap[i].base, memory_map->memmap[i].length / PAGE_SIZE); 147 | } 148 | } 149 | } -------------------------------------------------------------------------------- /src/kernel/arch/memory/pmm.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_PMM_H 2 | #define KERNEL_PMM_H 3 | #include 4 | #include 5 | 6 | void pmm_free(void *addr, size_t pages); 7 | void pmm_initialize(struct stivale2_struct *stivale); 8 | void *pmm_allocate_zero(size_t pages); 9 | void *pmm_allocate(size_t pages); 10 | #endif -------------------------------------------------------------------------------- /src/kernel/arch/memory/vmm.c: -------------------------------------------------------------------------------- 1 | #include "arch/memory/vmm.h" 2 | #include "arch/memory/pmm.h" 3 | #include "stivale2.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define PML_ENTRY(addr, offset) (size_t)(addr & ((uintptr_t)0x1ff << offset)) >> offset; 10 | 11 | uintptr_t *kernel_pagemap = 0; 12 | static uint32_t lock = 0; 13 | 14 | static uint64_t *get_next_level(uint64_t *table, size_t index, uint64_t flags) 15 | { 16 | if (!(table[index] & 1)) 17 | { 18 | table[index] = (uint64_t)pmm_allocate_zero(1); 19 | table[index] |= flags; 20 | } 21 | 22 | return (uint64_t *)((table[index] & ~(0x1ff)) + MMAP_IO_BASE); 23 | } 24 | 25 | uint64_t *vmm_get_kernel_pagemap() 26 | { 27 | return kernel_pagemap; 28 | } 29 | 30 | void flush_tlb(void *addr) 31 | { 32 | asm volatile("invlpg (%0)" ::"r"(addr)); 33 | } 34 | 35 | void vmm_map(uint64_t *pagemap, uintptr_t physical_address, uintptr_t virtual_address, uint64_t flags) 36 | { 37 | spin_lock(&lock); 38 | size_t level4 = PML_ENTRY(virtual_address, 39); 39 | size_t level3 = PML_ENTRY(virtual_address, 30); 40 | size_t level2 = PML_ENTRY(virtual_address, 21); 41 | size_t level1 = PML_ENTRY(virtual_address, 12); 42 | 43 | uint64_t *pml3 = get_next_level(pagemap, level4, flags); 44 | uint64_t *pml2 = get_next_level(pml3, level3, flags); 45 | uint64_t *pml1 = get_next_level(pml2, level2, flags); 46 | 47 | pml1[level1] = physical_address | flags; 48 | 49 | flush_tlb((void *)virtual_address); 50 | spin_release(&lock); 51 | } 52 | 53 | void vmm_unmap(uint64_t *pagemap, uintptr_t virtual_address, uint64_t flags) 54 | { 55 | size_t level4 = PML_ENTRY(virtual_address, 39); 56 | size_t level3 = PML_ENTRY(virtual_address, 30); 57 | size_t level2 = PML_ENTRY(virtual_address, 21); 58 | size_t level1 = PML_ENTRY(virtual_address, 12); 59 | 60 | uint64_t *pml3 = get_next_level(pagemap, level4, flags); 61 | uint64_t *pml2 = get_next_level(pml3, level3, flags); 62 | uint64_t *pml1 = get_next_level(pml2, level2, flags); 63 | 64 | pml1[level1] = 0; 65 | } 66 | 67 | void vmm_map_range(uint64_t *pagemap, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags) 68 | { 69 | for (uintptr_t i = start; i < end; i += PAGE_SIZE) 70 | { 71 | vmm_map(pagemap, i, i + offset, flags); 72 | } 73 | } 74 | 75 | void vmm_load_pagemap(uint64_t *pagemap) 76 | { 77 | asm_write_cr3((uint64_t)pagemap); 78 | } 79 | 80 | void vmm_initialize(struct stivale2_struct *stivale2_struct) 81 | { 82 | 83 | struct stivale2_struct_tag_memmap *memory_map = stivale2_get_tag(stivale2_struct, STIVALE2_STRUCT_TAG_MEMMAP_ID); 84 | 85 | kernel_pagemap = (uint64_t *)pmm_allocate_zero(1); 86 | 87 | vmm_map_range(kernel_pagemap, 0, 0x8000000, MMAP_KERNEL_BASE, 0b11); 88 | vmm_map_range(kernel_pagemap, 0, 0x100000000, MMAP_IO_BASE, 0b11); 89 | 90 | foreach (i, memory_map->entries) 91 | { 92 | struct stivale2_mmap_entry entry = memory_map->memmap[i]; 93 | 94 | if (entry.type == STIVALE2_MMAP_USABLE) 95 | { 96 | foreachr(p, entry.length, PAGE_SIZE) 97 | { 98 | vmm_map(kernel_pagemap, p, p + MMAP_IO_BASE, 0b11); 99 | } 100 | } 101 | } 102 | 103 | vmm_load_pagemap(kernel_pagemap); 104 | } 105 | 106 | void vmm_mmap(uint64_t *pagemap, size_t hint, size_t size, size_t flags, size_t *used_pages, size_t *ret) 107 | { 108 | size_t actual_flags = flags & 0xFFFFFFFF; 109 | 110 | if ((actual_flags & MAP_ANONYMOUS) == 0) 111 | { 112 | log("TODO: add support for other things than map_anonymous\n"); 113 | while (1) 114 | ; 115 | } 116 | 117 | size_t pages = ALIGN_UP(size, PAGE_SIZE) / PAGE_SIZE; 118 | 119 | uintptr_t virt; 120 | 121 | if (actual_flags & MAP_FIXED) 122 | { 123 | virt = hint; 124 | } 125 | else 126 | { 127 | virt = (*used_pages) * 4096 + ALLOC_BASE; 128 | 129 | (*used_pages) += pages; 130 | } 131 | 132 | foreach (i, pages) 133 | { 134 | void *ret = pmm_allocate_zero(1); 135 | if (!ret) 136 | { 137 | log("ERROR: pmm returned null"); 138 | } 139 | vmm_map(pagemap, (uintptr_t)ret, virt + i * 4096, 0b111); 140 | } 141 | 142 | *ret = virt; 143 | } -------------------------------------------------------------------------------- /src/kernel/arch/memory/vmm.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_VMM_H 2 | #define KERNEL_VMM_H 3 | #include 4 | #include 5 | 6 | #define PROT_NONE 0x00 7 | #define PROT_READ 0x01 8 | #define PROT_WRITE 0x02 9 | #define PROT_EXEC 0x04 10 | 11 | #define MAP_PRIVATE 0x01 12 | #define MAP_SHARED 0x02 13 | #define MAP_FIXED 0x04 14 | #define MAP_ANON 0x08 15 | #define MAP_ANONYMOUS 0x08 16 | #define ALLOC_BASE 0x1000000 17 | 18 | void vmm_initialize(struct stivale2_struct *boot); 19 | 20 | void vmm_map(uint64_t *pagemap, uintptr_t phys, uintptr_t virt, uint64_t flags); 21 | 22 | void vmm_unmap(uint64_t *pagemap, uintptr_t virt, uint64_t flags); 23 | 24 | void vmm_load_pagemap(uint64_t *pagemap); 25 | 26 | uint64_t *vmm_get_kernel_pagemap(); 27 | 28 | void vmm_mmap(uint64_t *pagemap, size_t hint, size_t size, size_t flags, size_t *used_pages, size_t *ret); 29 | 30 | #endif -------------------------------------------------------------------------------- /src/kernel/arch/sse.asm: -------------------------------------------------------------------------------- 1 | global enable_sse 2 | 3 | enable_sse: 4 | fninit 5 | mov rax, cr0 6 | and ax, 0xFFFB 7 | or ax, 0x2 8 | mov cr0, rax 9 | mov rax, cr4 10 | or ax, 3 << 9 11 | mov cr4, rax 12 | ret 13 | -------------------------------------------------------------------------------- /src/kernel/bootstrap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static uint8_t stack[8192]; 6 | 7 | void _start(struct stivale2_struct *stivale2_struct); 8 | void kernel_main(struct stivale2_struct *stivale2_struct, uint8_t *stack, size_t stack_size); 9 | 10 | __attribute__((section(".stivale2hdr"), used)) static struct stivale2_header stivale_hdr = { 11 | .entry_point = (uintptr_t)_start, 12 | 13 | .stack = (uintptr_t)stack + sizeof(stack), 14 | 15 | .flags = (1 << 1), 16 | 17 | .tags = (uintptr_t)0}; 18 | 19 | void *stivale2_get_tag(struct stivale2_struct *stivale2_struct, uint64_t id) 20 | { 21 | struct stivale2_tag *current_tag = (struct stivale2_tag *)stivale2_struct->tags; 22 | 23 | for (;;) 24 | { 25 | if (!current_tag) 26 | { 27 | return NULL; 28 | } 29 | 30 | if (current_tag->identifier == id) 31 | { 32 | return current_tag; 33 | } 34 | 35 | current_tag = (void *)current_tag->next; 36 | } 37 | } 38 | 39 | bool do_nerd_logs = false; 40 | 41 | bool nerd_logs() 42 | { 43 | return do_nerd_logs; 44 | } 45 | 46 | static int errno = 0; 47 | 48 | void set_errno(int val) 49 | { 50 | errno = val; 51 | } 52 | 53 | int get_errno() 54 | { 55 | return errno; 56 | } 57 | 58 | void _start(struct stivale2_struct *stivale2_struct) 59 | { 60 | struct stivale2_struct_tag_cmdline *cmdline = stivale2_get_tag(stivale2_struct, STIVALE2_STRUCT_TAG_CMDLINE_ID); 61 | 62 | if (str_eq((char *)cmdline->cmdline, "log")) 63 | { 64 | do_nerd_logs = true; 65 | } 66 | 67 | kernel_main(stivale2_struct, stack, 8192); 68 | } 69 | -------------------------------------------------------------------------------- /src/kernel/elf.c: -------------------------------------------------------------------------------- 1 | #include "arch/arch.h" 2 | #include 3 | #include 4 | #include 5 | 6 | uint64_t elf_load_program(uint64_t elf_base, uintptr_t base, Task *task, Auxval *auxval, char **ld_path) 7 | { 8 | Elf64Header *elf_header = malloc(sizeof(Elf64Header)); 9 | memcpy(elf_header, (void *)elf_base, sizeof(Elf64Header)); 10 | 11 | Elf64ProgramHeader *prog_header = (Elf64ProgramHeader *)(elf_base + elf_header->program_header_table_file_offset); 12 | 13 | auxval->at_phdr = 0; 14 | auxval->at_phent = sizeof(Elf64ProgramHeader); 15 | auxval->at_phnum = elf_header->program_header_table_entry_count; 16 | 17 | for (size_t i = 0; i < elf_header->program_header_table_entry_count; i++) 18 | { 19 | if (prog_header->type == ELF_PROGRAM_HEADER_INTERPRET) 20 | { 21 | 22 | if (!ld_path) 23 | { 24 | break; 25 | } 26 | 27 | *ld_path = malloc(prog_header->file_size + 1); 28 | 29 | memcpy(*ld_path, (void *)(elf_base + prog_header->file_offset), prog_header->file_size); 30 | 31 | (*ld_path)[prog_header->file_size] = 0; 32 | } 33 | 34 | else if (prog_header->type == 6) 35 | { 36 | auxval->at_phdr = base + prog_header->virtual_address; 37 | } 38 | 39 | else if (prog_header->type == ELF_PROGRAM_HEADER_LOAD) 40 | { 41 | size_t misalign = prog_header->virtual_address & (PAGE_SIZE - 1); 42 | size_t page_count = DIV_ROUNDUP(misalign + prog_header->memory_size, PAGE_SIZE); 43 | 44 | void *new_addr = pmm_allocate_zero(page_count); 45 | 46 | for (size_t j = 0; j < page_count * PAGE_SIZE; j += PAGE_SIZE) 47 | { 48 | vmm_map(task->pagemap, j + (uint64_t)new_addr, base + j + prog_header->virtual_address, 0b111); 49 | } 50 | 51 | memcpy((void *)((uint64_t)new_addr + MMAP_IO_BASE + misalign), (void *)(elf_base + prog_header->file_offset), prog_header->file_size); 52 | memset((void *)((uint64_t)new_addr + MMAP_IO_BASE + misalign + prog_header->file_size), 0, prog_header->memory_size - prog_header->file_size); 53 | } 54 | 55 | prog_header = (Elf64ProgramHeader *)((uint8_t *)prog_header + elf_header->program_header_table_entry_size); 56 | } 57 | 58 | auxval->at_entry = base + elf_header->entry; 59 | 60 | Elf64SectionHeader *shdr = (Elf64SectionHeader *)(elf_header + elf_header->section_header_table_file_offset); 61 | 62 | for (size_t i = 0; i < elf_header->section_header_table_entry_count; i++) 63 | { 64 | Elf64SectionHeader *section = &shdr[i]; 65 | 66 | if (section->type == ELF_SECTION_HEADER_NOBITS) 67 | { 68 | if (!section->entry_size) 69 | continue; 70 | if (section->flags & 0x02) 71 | { 72 | void *mem = malloc(section->entry_size); 73 | 74 | memset(mem, 0, section->entry_size); 75 | 76 | section->file_offset = (uintptr_t)mem - (uintptr_t)elf_header; 77 | } 78 | } 79 | } 80 | 81 | return base + elf_header->entry; 82 | } 83 | -------------------------------------------------------------------------------- /src/kernel/elf.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define ELF_HEADER_MAGIC "\177ELF" 5 | 6 | typedef enum 7 | { 8 | ELF_CLASS_INVALID = 0, 9 | ELF_CLASS_32 = 1, 10 | ELF_CLASS_64 = 2, 11 | } ElfClass; 12 | 13 | typedef enum 14 | { 15 | ELF_ENCODING_INVALID = 0, 16 | ELF_ENCODING_LITTLE_ENDIAN = 1, 17 | ELF_ENCODING_BIG_ENDIAN = 2, 18 | } ElfEncoding; 19 | 20 | typedef enum 21 | { 22 | ELF_TYPE_NONE = 0, 23 | ELF_TYPE_RELOCATABLE = 1, 24 | ELF_TYPE_EXECUTABLE = 2, 25 | ELF_TYPE_DYNAMIC = 3, 26 | ELF_TYPE_CORE = 4, 27 | } ElfType; 28 | 29 | typedef enum 30 | { 31 | ELF_SECTION_HEADER_NULL = 0, 32 | ELF_SECTION_HEADER_PROGBITS = 1, 33 | ELF_SECTION_HEADER_SYMTAB = 2, 34 | ELF_SECTION_HEADER_STRTAB = 3, 35 | ELF_SECTION_HEADER_RELA = 4, 36 | ELF_SECTION_HEADER_NOBITS = 8, 37 | ELF_SECTION_HEADER_REL = 9, 38 | } ElfSectionHeaderType; 39 | 40 | typedef enum 41 | { 42 | ELF_PROGRAM_HEADER_NULL = 0, 43 | ELF_PROGRAM_HEADER_LOAD = 1, 44 | ELF_PROGRAM_HEADER_DYNAMIC = 2, 45 | ELF_PROGRAM_HEADER_INTERPRET = 3, 46 | ELF_PROGRAM_HEADER_NOTE = 4, 47 | 48 | } ElfProgramHeaderType; 49 | typedef enum 50 | { 51 | ELF_PROGRAM_HEADER_EXECUTABLE = 1 << 0, 52 | ELF_PROGRAM_HEADER_WRITABLE = 1 << 1, 53 | ELF_PROGRAM_HEADER_READABLE = 1 << 2, 54 | } ElfProgramHeaderFlags; 55 | 56 | typedef struct PACKED 57 | { 58 | uint8_t magics[4]; 59 | uint8_t elf_class; 60 | uint8_t data_encoding; 61 | uint8_t version; 62 | uint8_t os; 63 | uint8_t abi_version; 64 | uint8_t _padding[7]; 65 | } Elf64Ident; 66 | 67 | typedef struct PACKED 68 | { 69 | Elf64Ident ident; 70 | 71 | uint16_t object_type; 72 | uint16_t machine_type; 73 | uint32_t object_version; 74 | 75 | uint64_t entry; 76 | 77 | uint64_t program_header_table_file_offset; 78 | uint64_t section_header_table_file_offset; 79 | 80 | uint32_t flags; 81 | 82 | uint16_t elf_header_size; 83 | 84 | uint16_t program_header_table_entry_size; 85 | uint16_t program_header_table_entry_count; 86 | 87 | uint16_t section_header_table_entry_size; 88 | uint16_t section_header_table_entry_count; 89 | 90 | uint16_t section_header_string_table_idx; 91 | } Elf64Header; 92 | 93 | typedef struct PACKED 94 | { 95 | uint32_t type; 96 | uint32_t flags; 97 | 98 | uint64_t file_offset; 99 | uint64_t virtual_address; 100 | uint64_t physical_address; 101 | 102 | uint64_t file_size; 103 | uint64_t memory_size; 104 | 105 | uint64_t alignment; 106 | } Elf64ProgramHeader; 107 | typedef struct 108 | { 109 | uintptr_t at_entry; 110 | uintptr_t at_phdr; 111 | uintptr_t at_phent; 112 | uintptr_t at_phnum; 113 | } Auxval; 114 | 115 | typedef struct PACKED 116 | { 117 | uint32_t name; 118 | uint32_t type; 119 | uint64_t flags; 120 | 121 | uint64_t virtual_address; 122 | uint64_t file_offset; 123 | uint64_t file_size; 124 | uint32_t link; 125 | uint32_t info; 126 | uint64_t addralign; 127 | uint64_t entry_size; 128 | } Elf64SectionHeader; 129 | 130 | inline bool elf_validate(Elf64Header const *header) 131 | { 132 | return header->ident.magics[0] == '\177' && 133 | header->ident.magics[1] == 'E' && 134 | header->ident.magics[2] == 'L' && 135 | header->ident.magics[3] == 'F'; 136 | } 137 | 138 | uint64_t elf_load_program(uint64_t elf_base, uintptr_t base, Task *task, Auxval *auxval, char **ld_path); 139 | -------------------------------------------------------------------------------- /src/kernel/fs/devfs.c: -------------------------------------------------------------------------------- 1 | #include "arch/devices/com.h" 2 | #include "fs/vfs.h" 3 | #include 4 | #include 5 | #include 6 | 7 | int devfs_read(VfsNode *node, size_t offset, size_t count, void *buffer) 8 | { 9 | (void)offset; 10 | 11 | if (str_eq(node->name, "tty")) 12 | { 13 | char *buf = malloc(count); 14 | 15 | size_t i = 0; 16 | char curr_char = 0; 17 | 18 | while (curr_char != '\r') 19 | { 20 | curr_char = com_getc(); 21 | 22 | buf[i++] = curr_char; 23 | 24 | com_putc(curr_char); 25 | } 26 | 27 | buf[i] = -1; 28 | curr_char = 0; 29 | 30 | com_putc('\n'); 31 | 32 | memcpy(buffer, buf, i); 33 | 34 | free(buf); 35 | 36 | return i; 37 | } 38 | 39 | return -1; 40 | } 41 | 42 | uint32_t write_lock = 0; 43 | 44 | int devfs_write(VfsNode *node, size_t count, void *buffer) 45 | { 46 | if (str_eq(node->name, "tty")) 47 | { 48 | 49 | spin_lock(&write_lock); 50 | 51 | char *buf = (char *)buffer; 52 | 53 | for (size_t i = 0; i < count; i++) 54 | { 55 | char c = buf[i]; 56 | 57 | com_putc(c); 58 | } 59 | 60 | spin_release(&write_lock); 61 | 62 | node->cursor += count; 63 | node->stat.st_size += count; 64 | 65 | return count; 66 | } 67 | return -1; 68 | } 69 | 70 | Filesystem devfs() 71 | { 72 | return (Filesystem){.read = devfs_read, .name = "DEVFS", .write = devfs_write}; 73 | } 74 | 75 | void devfs_init() 76 | { 77 | vfs_mount("/dev", devfs()); 78 | vfs_open(vfs_get_root(), "/dev/tty", O_CREAT); 79 | } -------------------------------------------------------------------------------- /src/kernel/fs/devfs.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_DEVFS_H 2 | #define KERNEL_DEVFS_H 3 | #include 4 | 5 | void devfs_init(); 6 | 7 | #endif -------------------------------------------------------------------------------- /src/kernel/fs/tmpfs.c: -------------------------------------------------------------------------------- 1 | #include "fs/vfs.h" 2 | #include "lib/mem.h" 3 | #include 4 | #include 5 | 6 | void tmpfs_create_file(char *name, uintptr_t address, size_t size) 7 | { 8 | VfsNode *ret = malloc(sizeof(VfsNode)); 9 | 10 | ret->name = strdup(basename(name)); 11 | 12 | ret->type = VFS_FILE; 13 | 14 | ret->parent = vfs_get_parent(vfs_get_root(), name); 15 | 16 | ret->mountpoint = ret->parent->mountpoint; 17 | 18 | ret->stat.st_size = size; 19 | 20 | void *new_addr = malloc(size + 1); 21 | 22 | ret->address = (uintptr_t)new_addr; 23 | 24 | ret->internal_address = address; 25 | 26 | vec_push(&ret->parent->children, ret); 27 | } 28 | 29 | int tmpfs_read(VfsNode *node, size_t offset, size_t count, void *buffer) 30 | { 31 | if (!node->init) 32 | { 33 | memcpy((void *)node->address, (void *)node->internal_address, node->stat.st_size); 34 | 35 | ((char *)node->address)[node->stat.st_size - 1] = -1; 36 | 37 | node->init = true; 38 | } 39 | 40 | if (!buffer) 41 | return -1; 42 | 43 | memcpy(buffer, (void *)(node->address + offset), count); 44 | 45 | node->cursor += count; 46 | 47 | return count; 48 | } 49 | 50 | int tmpfs_write(VfsNode *node, size_t count, void *buffer) 51 | { 52 | 53 | if (node->o_mode & O_APPEND) 54 | { 55 | node->cursor = node->stat.st_size; 56 | 57 | node->address = (uintptr_t)realloc((void *)node->address, node->stat.st_size + count + 1); 58 | 59 | memcpy((void *)node->address + node->cursor, buffer, count); 60 | 61 | node->stat.st_size += count; 62 | 63 | return 0; 64 | } 65 | 66 | else 67 | { 68 | if ((int)node->cursor >= node->stat.st_size) 69 | { 70 | node->address = (uintptr_t)realloc((void *)node->address, node->stat.st_size + count + 1); 71 | } 72 | 73 | memcpy((void *)node->address + node->cursor, buffer, count); 74 | 75 | node->stat.st_size += count; 76 | node->cursor += count; 77 | } 78 | 79 | return count; 80 | } 81 | 82 | Filesystem tmpfs() 83 | { 84 | return (Filesystem){.read = tmpfs_read, .write = tmpfs_write, .name = "tmpfs"}; 85 | } 86 | -------------------------------------------------------------------------------- /src/kernel/fs/tmpfs.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_TMPFS_H 2 | #define KERNEL_TMPFS_H 3 | #include 4 | #include 5 | 6 | void tmpfs_create_file(char *name, uintptr_t address, size_t size); 7 | 8 | Filesystem tmpfs(); 9 | 10 | #endif -------------------------------------------------------------------------------- /src/kernel/fs/ustar.c: -------------------------------------------------------------------------------- 1 | #include "fs/tmpfs.h" 2 | #include "fs/vfs.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static uint64_t addr = 0; 10 | 11 | struct tar_header 12 | { 13 | char name[100]; 14 | char mode[8]; 15 | char uid[8]; 16 | char gid[8]; 17 | char size[12]; 18 | char mtime[12]; 19 | char chksum[8]; 20 | char typeflag[1]; 21 | }; 22 | 23 | unsigned int getsize(const char *in) 24 | { 25 | 26 | unsigned int size = 0; 27 | unsigned int j; 28 | unsigned int count = 1; 29 | 30 | for (j = 11; j > 0; j--, count *= 8) 31 | size += ((in[j - 1] - '0') * count); 32 | 33 | return size; 34 | } 35 | 36 | uintptr_t create_tmpfs_files(uintptr_t address) 37 | { 38 | size_t size = 0; 39 | 40 | size_t i; 41 | 42 | for (i = 0;; i++) 43 | { 44 | struct tar_header *header = (struct tar_header *)address; 45 | 46 | if (header->name[0] == '\0') 47 | break; 48 | 49 | if (header->typeflag[0] == '5') 50 | { 51 | char *name = strdup(header->name); 52 | 53 | name[strlen(name) - 1] = '\0'; 54 | 55 | char *new_name = malloc(strlen(name) + 2); 56 | 57 | new_name[0] = '/'; 58 | 59 | memcpy(new_name + 1, name, strlen(name)); 60 | 61 | vfs_mkdir(new_name); 62 | } 63 | 64 | else 65 | { 66 | char *new_name = malloc(strlen(header->name) + 2); 67 | 68 | new_name[0] = '/'; 69 | 70 | memcpy(new_name + 1, header->name, strlen(header->name)); 71 | 72 | tmpfs_create_file(new_name, (uintptr_t)header + 512, getsize(header->size)); 73 | } 74 | 75 | size = getsize(header->size); 76 | 77 | address += ((size / 512) + 1) * 512; 78 | 79 | if (size % 512) 80 | { 81 | address += 512; 82 | } 83 | } 84 | 85 | return 0xc001c0de; 86 | } 87 | 88 | void ustar_initialize(uint64_t _addr) 89 | { 90 | addr = _addr; 91 | create_tmpfs_files(addr); 92 | } 93 | 94 | int ustar_read(VfsNode *node, size_t offset, size_t count, void *buffer) 95 | { 96 | memcpy(buffer, (void *)(node->address + offset), count); 97 | 98 | return count; 99 | } 100 | 101 | int ustar_write(VfsNode *node, size_t offset, size_t count, void *buffer) 102 | { 103 | UNUSED(node); 104 | UNUSED(offset); 105 | UNUSED(count); 106 | UNUSED(buffer); 107 | 108 | log("USTAR can't write."); 109 | return -1; 110 | } 111 | 112 | Filesystem ustar_fs() 113 | { 114 | Filesystem fs = {.read = ustar_read, .name = "ustar"}; 115 | 116 | return fs; 117 | } 118 | -------------------------------------------------------------------------------- /src/kernel/fs/ustar.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_USTAR_H 2 | #define KERNEL_USTAR_H 3 | #include 4 | 5 | void ustar_initialize(uint64_t addr); 6 | 7 | Filesystem ustar_fs(); 8 | 9 | #endif -------------------------------------------------------------------------------- /src/kernel/fs/vfs.c: -------------------------------------------------------------------------------- 1 | #include "lib/vec.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | Mountpoint mountpoints[64] = {}; 8 | size_t mountpoints_n = 0; 9 | VfsNode *root = NULL; 10 | 11 | VfsNode *vfs_mkdir(char *path) 12 | { 13 | VfsNode *node = malloc(sizeof(VfsNode)); 14 | 15 | node->type = VFS_DIRECTORY; 16 | 17 | vec_init(&node->children); 18 | 19 | if (!str_eq(path, "/")) 20 | { 21 | node->parent = vfs_get_parent(root, path); 22 | node->name = basename(path); 23 | 24 | if (!node->parent) 25 | { 26 | set_errno(ENOENT); 27 | return NULL; 28 | } 29 | 30 | node->mountpoint = root->mountpoint; 31 | 32 | VfsNode *prev_dir = malloc(sizeof(VfsNode)); 33 | 34 | prev_dir->type = VFS_DIRECTORY; 35 | 36 | prev_dir->name = ".."; 37 | prev_dir->points_to = node->parent; 38 | 39 | VfsNode *curr_dir = malloc(sizeof(VfsNode)); 40 | 41 | curr_dir->type = VFS_DIRECTORY; 42 | curr_dir->name = "."; 43 | curr_dir->points_to = node; 44 | 45 | vec_push(&node->children, prev_dir); 46 | vec_push(&node->children, curr_dir); 47 | vec_push(&node->parent->children, node); 48 | } 49 | 50 | else 51 | { 52 | node->parent = node; 53 | node->mountpoint = malloc(sizeof(Mountpoint)); 54 | node->name = "/"; 55 | } 56 | 57 | if (nerd_logs()) 58 | { 59 | log("added directory %s, parent is %s", node->name, node->parent == root ? "/" : node->parent->name); 60 | } 61 | 62 | return node; 63 | } 64 | 65 | int vfs_mount(char *where, Filesystem fs) 66 | { 67 | if (!root) 68 | { 69 | VfsNode *tmp = vfs_mkdir(where); 70 | 71 | root = tmp; 72 | 73 | root->mountpoint->fs = fs; 74 | 75 | root->mountpoint->root = root; 76 | 77 | mountpoints[mountpoints_n++] = *root->mountpoint; 78 | 79 | return 0; 80 | } 81 | 82 | VfsNode *node = vfs_mkdir(where); 83 | node->mountpoint = malloc(sizeof(Mountpoint)); 84 | 85 | node->mountpoint->fs = fs; 86 | 87 | mountpoints[mountpoints_n++] = *node->mountpoint; 88 | 89 | return 0; 90 | } 91 | 92 | vec_str_t vfs_parse_path(char *path) 93 | { 94 | vec_str_t segments; 95 | 96 | vec_init(&segments); 97 | 98 | char *segment = strtok(strdup(path), "/"); 99 | 100 | while (segment) 101 | { 102 | vec_push(&segments, strdup(segment)); 103 | 104 | segment = strtok(NULL, "/"); 105 | } 106 | 107 | return segments; 108 | } 109 | 110 | VfsNode *vfs_find_node(VfsNode *start, char *name) 111 | { 112 | if (start->points_to) 113 | { 114 | for (int i = 0; i < start->points_to->children.length; i++) 115 | { 116 | if (str_eq(name, start->points_to->children.data[i]->name)) 117 | { 118 | return start->points_to->children.data[i]; 119 | } 120 | } 121 | } 122 | 123 | for (int i = 0; i < start->children.length; i++) 124 | { 125 | if (str_eq(name, start->children.data[i]->name)) 126 | { 127 | return start->children.data[i]; 128 | } 129 | } 130 | 131 | return NULL; 132 | } 133 | 134 | VfsNode *vfs_get_parent(VfsNode *start, char *path) 135 | { 136 | VfsNode *node = start; 137 | 138 | vec_str_t segments = vfs_parse_path(path); 139 | 140 | for (int i = 0; i < segments.length - 1; i++) 141 | { 142 | if (strlen(segments.data[i]) != 0) 143 | { 144 | 145 | if (i + 2 == segments.length) 146 | { 147 | return node; 148 | } 149 | 150 | node = vfs_find_node(node, segments.data[i + 1]); 151 | } 152 | 153 | else 154 | { 155 | if (segments.length == 2) 156 | { 157 | return start; 158 | } 159 | 160 | node = vfs_find_node(start, segments.data[i + 1]); 161 | } 162 | } 163 | 164 | if (!node) 165 | set_errno(ENOENT); 166 | 167 | return node; 168 | } 169 | 170 | VfsNode *vfs_get_root() 171 | { 172 | return root; 173 | } 174 | 175 | VfsNode *vfs_open(VfsNode *start, char *path, int flags) 176 | { 177 | 178 | /// FIXME: use start 179 | (void)start; 180 | VfsNode *parent = vfs_get_parent(root, path); 181 | 182 | if (!parent) 183 | { 184 | set_errno(ENOENT); 185 | return NULL; 186 | } 187 | 188 | VfsNode *node = vfs_find_node(parent, basename(path)); 189 | 190 | if (!(flags & O_DIRECTORY) && node) 191 | { 192 | if (node->type == VFS_DIRECTORY) 193 | { 194 | set_errno(EISDIR); 195 | return NULL; 196 | } 197 | } 198 | 199 | if (flags & O_CREAT) 200 | { 201 | if (node) 202 | { 203 | node->o_mode = flags; 204 | 205 | return node; 206 | } 207 | 208 | VfsNode *ret = malloc(sizeof(VfsNode)); 209 | 210 | ret->name = strdup(basename(path)); 211 | 212 | ret->type = VFS_FILE; 213 | 214 | ret->parent = parent; 215 | 216 | ret->o_mode = flags; 217 | 218 | ret->mountpoint = ret->parent->mountpoint; 219 | 220 | ret->address = (uintptr_t)malloc(2); 221 | 222 | vec_push(&ret->parent->children, ret); 223 | 224 | return ret; 225 | } 226 | 227 | if (!node) 228 | { 229 | set_errno(ENOENT); 230 | return NULL; 231 | } 232 | 233 | node->o_mode = flags; 234 | 235 | if (node->points_to) 236 | return node->points_to; 237 | 238 | return node; 239 | } 240 | 241 | int vfs_read(VfsNode *vfs_node, size_t offset, size_t count, void *buf) 242 | { 243 | return vfs_node->mountpoint->fs.read(vfs_node, offset, count, buf); 244 | } 245 | 246 | int vfs_write(VfsNode *vfs_node, size_t count, void *buf) 247 | { 248 | if (vfs_node->mountpoint->fs.write(vfs_node, count, buf) != -1) 249 | return count; 250 | return -1; 251 | } 252 | -------------------------------------------------------------------------------- /src/kernel/fs/vfs.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_VFS_H 2 | #define KERNEL_VFS_H 3 | #include 4 | #include 5 | 6 | struct mountpoint; 7 | 8 | typedef enum 9 | { 10 | VFS_FILE, 11 | VFS_DIRECTORY, 12 | } VfsNodeType; 13 | 14 | typedef struct vfs_node 15 | { 16 | VfsNodeType type; 17 | 18 | char *name; 19 | 20 | struct vfs_node *parent; 21 | struct vfs_node *points_to; 22 | 23 | vec_t(struct vfs_node *) children; 24 | 25 | struct mountpoint *mountpoint; 26 | 27 | struct stat stat; 28 | 29 | size_t cursor; 30 | int o_mode; 31 | 32 | uintptr_t address; 33 | uintptr_t internal_address; 34 | 35 | bool init; 36 | 37 | } VfsNode; 38 | 39 | typedef struct 40 | { 41 | int (*read)(VfsNode *vfs_node, size_t offset, size_t count, void *buf); 42 | int (*write)(VfsNode *vfs_node, size_t count, void *buf); 43 | uintptr_t (*open)(char *path); 44 | char *name; 45 | } Filesystem; 46 | 47 | typedef struct mountpoint 48 | { 49 | Filesystem fs; 50 | VfsNode *root; 51 | } Mountpoint; 52 | 53 | int vfs_mount(char *where, Filesystem fs); 54 | 55 | VfsNode *vfs_open(VfsNode *parent, char *path, int flags); 56 | 57 | int vfs_read(VfsNode *vfs_node, size_t offset, size_t count, void *buf); 58 | 59 | VfsNode *vfs_mkdir(char *path); 60 | 61 | VfsNode *vfs_get_root(); 62 | 63 | VfsNode *vfs_get_parent(VfsNode *start, char *path); 64 | 65 | int vfs_write(VfsNode *vfs_node, size_t count, void *buf); 66 | 67 | VfsNode *vfs_find_node(VfsNode *start, char *name); 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/kernel/main.c: -------------------------------------------------------------------------------- 1 | #include "fs/vfs.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | extern void enable_sse(); 20 | 21 | void *stivale2_get_tag(struct stivale2_struct *stivale2_struct, uint64_t id); 22 | 23 | static uint32_t lock = 0; 24 | 25 | void *liballoc_alloc(int s) 26 | { 27 | return pmm_allocate_zero(s) + MMAP_IO_BASE; 28 | } 29 | 30 | int liballoc_free(void *p, int s) 31 | { 32 | pmm_free(p - MMAP_IO_BASE, s); 33 | return 0; 34 | } 35 | int liballoc_lock() 36 | { 37 | spin_lock(&lock); 38 | return 0; 39 | } 40 | 41 | int liballoc_unlock() 42 | { 43 | spin_release(&lock); 44 | return 0; 45 | } 46 | 47 | void print_files(VfsNode *node) 48 | { 49 | for (int i = 0; i < node->children.length; i++) 50 | { 51 | log("\t %s: %s", node->children.data[i]->type == VFS_DIRECTORY ? "directory" : "file", node->children.data[i]->name); 52 | } 53 | } 54 | 55 | void kernel_main(struct stivale2_struct *stivale2_struct, uint8_t *stack, size_t stack_size) 56 | { 57 | 58 | enable_sse(); 59 | com_initialize(); 60 | 61 | log("Welcome to bestOS: An agile, cloud-ready, blockchain-powered, web-scale operating system"); 62 | log("Version: Professional, license_key: 0x%x", 0xc001c0de); 63 | 64 | struct stivale2_struct_tag_modules *modules = stivale2_get_tag(stivale2_struct, STIVALE2_STRUCT_TAG_MODULES_ID); 65 | 66 | gdt_initialize(stack, stack_size); 67 | pic_initialize(); 68 | idt_initialize(); 69 | 70 | pmm_initialize(stivale2_struct); 71 | vmm_initialize(stivale2_struct); 72 | 73 | vfs_mount("/", tmpfs()); 74 | 75 | for (size_t i = 0; i < modules->module_count; i++) 76 | { 77 | if (str_eq("ustar ", (char *)(modules->modules[i].begin + 257))) 78 | { 79 | ustar_initialize(modules->modules[i].begin); 80 | } 81 | } 82 | 83 | devfs_init(); 84 | 85 | if (nerd_logs()) 86 | print_files(vfs_get_root()); 87 | 88 | sched_init(); 89 | 90 | const char *argv[] = {"/bin/sh", NULL}; 91 | const char *envp[] = {"PATH=/bin", NULL}; 92 | 93 | sched_new_elf_process("/bin/init", argv, envp, "/dev/tty", "/dev/tty", "/dev/tty"); 94 | 95 | sched_start(); 96 | 97 | for (;;) 98 | { 99 | asm_hlt(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/kernel/sched.c: -------------------------------------------------------------------------------- 1 | #include "arch/memory/pmm.h" 2 | #include "fs/vfs.h" 3 | #include "lib/vec.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static size_t current_pid = 0; 11 | static size_t current_tick = 9; 12 | static size_t index = 0; 13 | 14 | // QWORD's abi 15 | #define AT_ENTRY 10 16 | #define AT_PHDR 20 17 | #define AT_PHENT 21 18 | #define AT_PHNUM 22 19 | #define AT_RANDOM 25 20 | #define AT_EXECFN 31 21 | 22 | Task *current_task; 23 | 24 | vec_t(Task *) processes; 25 | 26 | Task *task_init(uintptr_t entry_point) 27 | { 28 | Task *new = malloc(sizeof(Task)); 29 | 30 | vec_init(&new->descriptors); 31 | 32 | new->pid = current_pid++; 33 | 34 | uintptr_t *stack = pmm_allocate_zero(STACK_SIZE / PAGE_SIZE); 35 | 36 | asm volatile(" fxsave %0 " ::"m"(new->fpu_storage)); 37 | 38 | new->sp = stack; 39 | new->cwd = vfs_get_root(); 40 | new->current_fd = 0; 41 | 42 | new->pagemap = pmm_allocate_zero(1) + MMAP_KERNEL_BASE; 43 | 44 | uint64_t *prev_pagemap = (uint64_t *)((uintptr_t)vmm_get_kernel_pagemap() + MMAP_KERNEL_BASE); 45 | 46 | for (int i = 256; i < 512; i++) 47 | { 48 | new->pagemap[i] = prev_pagemap[i]; 49 | } 50 | 51 | // Map task's stack 52 | for (size_t i = 0; i < (STACK_SIZE / 4096); i++) 53 | { 54 | uint64_t phys_addr = i * PAGE_SIZE + (uintptr_t)stack; 55 | 56 | uint64_t virt_addr = i * PAGE_SIZE + (USER_STACK_TOP - STACK_SIZE); 57 | 58 | vmm_map(new->pagemap, phys_addr, virt_addr, 0b111); 59 | } 60 | 61 | new->stack.rsp = USER_STACK_TOP; 62 | new->stack.rip = entry_point; 63 | new->stack.rflags = 0x202; 64 | 65 | new->stack.cs = 0x43; 66 | new->stack.ss = 0x3b; 67 | 68 | return new; 69 | } 70 | 71 | bool started = false; 72 | 73 | bool sched_started() 74 | { 75 | return started; 76 | } 77 | 78 | void sched_start() 79 | { 80 | started = true; 81 | } 82 | 83 | static uint32_t lock = 0; 84 | 85 | Task *sched_tick() 86 | { 87 | while (processes.length == 0) 88 | { 89 | asm_hlt(); 90 | } 91 | 92 | spin_lock(&lock); 93 | 94 | if (current_tick + 1 >= SWITCH_TICK) 95 | { 96 | current_tick = 0; 97 | 98 | if ((int)index == processes.length) 99 | index = 0; 100 | 101 | current_task = processes.data[index++]; 102 | 103 | spin_release(&lock); 104 | 105 | return current_task; 106 | } 107 | 108 | current_tick++; 109 | 110 | spin_release(&lock); 111 | return current_task; 112 | } 113 | 114 | void sched_init(void) 115 | { 116 | vec_init(&processes); 117 | current_tick = SWITCH_TICK - 1; 118 | } 119 | 120 | void sched_push(Task *t) 121 | { 122 | 123 | spin_lock(&lock); 124 | 125 | vec_push(&processes, t); 126 | 127 | spin_release(&lock); 128 | } 129 | 130 | void sched_remove(Task *t) 131 | { 132 | spin_lock(&lock); 133 | vec_remove(&processes, t); 134 | spin_release(&lock); 135 | } 136 | 137 | Task *sched_current_task() 138 | { 139 | return current_task; 140 | } 141 | 142 | int sched_get_last_pid() 143 | { 144 | return current_pid; 145 | } 146 | 147 | void sched_set_tick(int t) 148 | { 149 | current_tick = t; 150 | } 151 | 152 | void sched_set_index(int i) 153 | { 154 | index = i; 155 | } 156 | 157 | void sched_new_elf_process(char *path, const char **argv, const char **envp, char *stdin, char *stdout, char *stderr) 158 | { 159 | char *ld_path = NULL; 160 | Auxval val = {}; 161 | Task *t = task_init(0); 162 | 163 | VfsNode *elf_file = vfs_open(vfs_get_root(), path, O_RDWR); 164 | 165 | void *elf_buffer = malloc(elf_file->stat.st_size); 166 | 167 | vfs_read(elf_file, 0, elf_file->stat.st_size, elf_buffer); 168 | 169 | t->stack.rip = elf_load_program((uintptr_t)elf_buffer, 0, t, &val, &ld_path); 170 | 171 | if (stdin && stdout && stderr) 172 | { 173 | VfsNode *stdin_node = vfs_open(vfs_get_root(), stdin, O_RDWR); 174 | VfsNode *stdout_node = vfs_open(vfs_get_root(), stdout, O_RDWR); 175 | VfsNode *stderr_node = vfs_open(vfs_get_root(), stderr, O_RDWR); 176 | 177 | if (!stdin_node || !stdout_node || !stderr_node) 178 | { 179 | log("ERROR: couldn't open stdio files"); 180 | } 181 | 182 | FileDescriptor stdin_fd = {.file = stdin_node, .fd = 0}; 183 | FileDescriptor stdout_fd = {.file = stdout_node, .fd = 1}; 184 | FileDescriptor stderr_fd = {.file = stderr_node, .fd = 2}; 185 | 186 | vec_push(&t->descriptors, stdin_fd); 187 | vec_push(&t->descriptors, stdout_fd); 188 | vec_push(&t->descriptors, stderr_fd); 189 | 190 | t->current_fd = 3; 191 | } 192 | 193 | size_t *stack = (size_t *)((uintptr_t)t->sp + STACK_SIZE + MMAP_IO_BASE); 194 | 195 | // ----- The following code is from mint's lyre, all copyright goes to them (idk if thats how you do it im not a lawyer) ---- 196 | uintptr_t stack_top = (uintptr_t)stack; 197 | 198 | /* Push all strings onto the stack. */ 199 | size_t nenv = 0; 200 | for (char **elem = (char **)envp; *elem; elem++) 201 | { 202 | stack = (void *)stack - (strlen(*elem) + 1); 203 | strcpy((char *)stack, *elem); 204 | nenv++; 205 | } 206 | 207 | size_t nargs = 0; 208 | for (char **elem = (char **)argv; *elem; elem++) 209 | { 210 | stack = (void *)stack - (strlen(*elem) + 1); 211 | strcpy((char *)stack, *elem); 212 | nargs++; 213 | } 214 | 215 | /* Align strp to 16-byte so that the following calculation becomes easier. */ 216 | stack = (void *)stack - ((uintptr_t)stack & 0xf); 217 | 218 | /* Make sure the *final* stack pointer is 16-byte aligned. 219 | - The auxv takes a multiple of 16-bytes; ignore that. 220 | - There are 2 markers that each take 8-byte; ignore that, too. 221 | - Then, there is argc and (nargs + nenv)-many pointers to args/environ. 222 | Those are what we *really* care about. */ 223 | if ((nargs + nenv + 1) & 1) 224 | stack--; 225 | 226 | // clang-format off 227 | *(--stack) = 0; *(--stack) = 0; /* Zero auxiliary vector entry */ 228 | stack -= 2; *stack = AT_ENTRY; *(stack + 1) = val.at_entry; 229 | stack -= 2; *stack = AT_PHDR; *(stack + 1) = val.at_phdr; 230 | stack -= 2; *stack = AT_PHENT; *(stack + 1) = val.at_phent; 231 | stack -= 2; *stack = AT_PHNUM; *(stack + 1) = val.at_phnum; 232 | // clang-format on 233 | 234 | uintptr_t sa = t->stack.rsp; 235 | 236 | *(--stack) = 0; /* Marker for end of environ */ 237 | stack -= nenv; 238 | for (size_t i = 0; i < nenv; i++) 239 | { 240 | sa -= strlen(envp[i]) + 1; 241 | stack[i] = sa; 242 | } 243 | 244 | *(--stack) = 0; /* Marker for end of argv */ 245 | 246 | stack -= nargs; 247 | for (size_t i = 0; i < nargs; i++) 248 | { 249 | sa -= strlen(argv[i]) + 1; 250 | stack[i] = sa; 251 | } 252 | 253 | *(--stack) = nargs; /* argc */ 254 | 255 | size_t skip = (stack_top - (uintptr_t)stack); 256 | 257 | t->stack.rsp -= skip; 258 | 259 | if (ld_path) 260 | { 261 | VfsNode *ld_file = vfs_open(vfs_get_root(), ld_path, O_RDWR); 262 | 263 | void *ld_file_buf = malloc(ld_file->stat.st_size); 264 | 265 | vfs_read(ld_file, 0, ld_file->stat.st_size, ld_file_buf); 266 | 267 | if (nerd_logs()) 268 | { 269 | log("ld.so: %s", ld_path); 270 | } 271 | 272 | if (!ld_file) 273 | { 274 | log("ERROR: couldn't find ld.so"); 275 | while (1) 276 | ; 277 | } 278 | 279 | Auxval ld_val = {}; 280 | 281 | elf_load_program((uintptr_t)ld_file_buf, 0x40000000, t, &ld_val, NULL); 282 | 283 | free(ld_path); 284 | free(ld_file_buf); 285 | 286 | t->stack.rip = ld_val.at_entry; 287 | } 288 | 289 | free(elf_buffer); 290 | 291 | sched_push(t); 292 | } -------------------------------------------------------------------------------- /src/kernel/sched.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_SCHED_H 2 | #define KERNEL_SCHED_H 3 | #include 4 | #include 5 | 6 | #define SWITCH_TICK 10 7 | 8 | typedef struct 9 | { 10 | int fd; 11 | VfsNode *file; 12 | } FileDescriptor; 13 | 14 | typedef struct task 15 | { 16 | struct task *parent; 17 | 18 | int current_fd; 19 | 20 | vec_t(FileDescriptor) descriptors; 21 | 22 | VfsNode *cwd; 23 | 24 | int pid; 25 | 26 | uintptr_t *sp; 27 | uintptr_t *pagemap; 28 | size_t used_pages; 29 | 30 | Stack stack; 31 | 32 | int state; // 0 = alive, 1 = waiting for death, -1 = dead 33 | int exit_code; 34 | 35 | void *fpu_storage; 36 | 37 | } Task; 38 | 39 | Task *task_init(uintptr_t entry_point); 40 | 41 | void sched_push(Task *t); 42 | void sched_init(void); 43 | Task *sched_tick(void); 44 | 45 | bool sched_started(); 46 | void sched_start(); 47 | 48 | void sched_remove(Task *t); 49 | 50 | void sched_new_elf_process(char *path, const char **argv, const char **envp, char *stdin, char *stdout, char *stderr); 51 | 52 | Task *sched_current_task(); 53 | 54 | void sched_set_tick(int t); 55 | void sched_set_index(int i); 56 | int sched_get_last_pid(); 57 | 58 | #endif -------------------------------------------------------------------------------- /src/kernel/stivale2.h: -------------------------------------------------------------------------------- 1 | #ifndef __STIVALE__STIVALE2_H__ 2 | #define __STIVALE__STIVALE2_H__ 3 | 4 | #include 5 | 6 | #if (defined(_STIVALE2_SPLIT_64) && defined(__i386__)) || defined(_STIVALE2_SPLIT_64_FORCE) 7 | 8 | # define _stivale2_split64(NAME) \ 9 | union \ 10 | { \ 11 | uint32_t NAME; \ 12 | uint32_t NAME##_lo; \ 13 | }; \ 14 | uint32_t NAME##_hi 15 | 16 | #else 17 | 18 | # define _stivale2_split64(NAME) \ 19 | uint64_t NAME 20 | 21 | #endif 22 | 23 | // Anchor for non ELF kernels 24 | struct stivale2_anchor 25 | { 26 | uint8_t anchor[15]; 27 | uint8_t bits; 28 | _stivale2_split64(phys_load_addr); 29 | _stivale2_split64(phys_bss_start); 30 | _stivale2_split64(phys_bss_end); 31 | _stivale2_split64(phys_stivale2hdr); 32 | }; 33 | 34 | struct stivale2_tag 35 | { 36 | uint64_t identifier; 37 | _stivale2_split64(next); 38 | }; 39 | 40 | /* --- Header --------------------------------------------------------------- */ 41 | /* Information passed from the kernel to the bootloader */ 42 | 43 | struct stivale2_header 44 | { 45 | _stivale2_split64(entry_point); 46 | _stivale2_split64(stack); 47 | uint64_t flags; 48 | _stivale2_split64(tags); 49 | }; 50 | 51 | #define STIVALE2_HEADER_TAG_ANY_VIDEO_ID 0xc75c9fa92a44c4db 52 | 53 | struct stivale2_header_tag_any_video 54 | { 55 | struct stivale2_tag tag; 56 | uint64_t preference; 57 | }; 58 | 59 | #define STIVALE2_HEADER_TAG_FRAMEBUFFER_ID 0x3ecc1bc43d0f7971 60 | 61 | struct stivale2_header_tag_framebuffer 62 | { 63 | struct stivale2_tag tag; 64 | uint16_t framebuffer_width; 65 | uint16_t framebuffer_height; 66 | uint16_t framebuffer_bpp; 67 | uint16_t unused; 68 | }; 69 | 70 | #define STIVALE2_HEADER_TAG_FB_MTRR_ID 0x4c7bb07731282e00 71 | 72 | #define STIVALE2_HEADER_TAG_SLIDE_HHDM_ID 0xdc29269c2af53d1d 73 | 74 | struct stivale2_header_tag_slide_hhdm 75 | { 76 | struct stivale2_tag tag; 77 | uint64_t flags; 78 | _stivale2_split64(alignment); 79 | }; 80 | 81 | #define STIVALE2_HEADER_TAG_TERMINAL_ID 0xa85d499b1823be72 82 | 83 | struct stivale2_header_tag_terminal 84 | { 85 | struct stivale2_tag tag; 86 | uint64_t flags; 87 | _stivale2_split64(callback); 88 | }; 89 | 90 | #define STIVALE2_TERM_CB_DEC 10 91 | #define STIVALE2_TERM_CB_BELL 20 92 | #define STIVALE2_TERM_CB_PRIVATE_ID 30 93 | #define STIVALE2_TERM_CB_STATUS_REPORT 40 94 | #define STIVALE2_TERM_CB_POS_REPORT 50 95 | #define STIVALE2_TERM_CB_KBD_LEDS 60 96 | #define STIVALE2_TERM_CB_MODE 70 97 | #define STIVALE2_TERM_CB_LINUX 80 98 | 99 | #define STIVALE2_TERM_CTX_SIZE ((uint64_t)(-1)) 100 | #define STIVALE2_TERM_CTX_SAVE ((uint64_t)(-2)) 101 | #define STIVALE2_TERM_CTX_RESTORE ((uint64_t)(-3)) 102 | #define STIVALE2_TERM_FULL_REFRESH ((uint64_t)(-4)) 103 | 104 | #define STIVALE2_HEADER_TAG_SMP_ID 0x1ab015085f3273df 105 | 106 | struct stivale2_header_tag_smp 107 | { 108 | struct stivale2_tag tag; 109 | uint64_t flags; 110 | }; 111 | 112 | #define STIVALE2_HEADER_TAG_5LV_PAGING_ID 0x932f477032007e8f 113 | 114 | #define STIVALE2_HEADER_TAG_UNMAP_NULL_ID 0x92919432b16fe7e7 115 | 116 | /* --- Struct --------------------------------------------------------------- */ 117 | /* Information passed from the bootloader to the kernel */ 118 | 119 | struct stivale2_struct 120 | { 121 | #define STIVALE2_BOOTLOADER_BRAND_SIZE 64 122 | char bootloader_brand[STIVALE2_BOOTLOADER_BRAND_SIZE]; 123 | 124 | #define STIVALE2_BOOTLOADER_VERSION_SIZE 64 125 | char bootloader_version[STIVALE2_BOOTLOADER_VERSION_SIZE]; 126 | 127 | uint64_t tags; 128 | }; 129 | 130 | #define STIVALE2_STRUCT_TAG_PMRS_ID 0x5df266a64047b6bd 131 | 132 | #define STIVALE2_PMR_EXECUTABLE ((uint64_t)1 << 0) 133 | #define STIVALE2_PMR_WRITABLE ((uint64_t)1 << 1) 134 | #define STIVALE2_PMR_READABLE ((uint64_t)1 << 2) 135 | 136 | struct stivale2_pmr 137 | { 138 | uint64_t base; 139 | uint64_t length; 140 | uint64_t permissions; 141 | }; 142 | 143 | struct stivale2_struct_tag_pmrs 144 | { 145 | struct stivale2_tag tag; 146 | uint64_t entries; 147 | struct stivale2_pmr pmrs[]; 148 | }; 149 | 150 | #define STIVALE2_STRUCT_TAG_KERNEL_BASE_ADDRESS_ID 0x060d78874a2a8af0 151 | 152 | struct stivale2_struct_tag_kernel_base_address 153 | { 154 | struct stivale2_tag tag; 155 | uint64_t physical_base_address; 156 | uint64_t virtual_base_address; 157 | }; 158 | 159 | #define STIVALE2_STRUCT_TAG_CMDLINE_ID 0xe5e76a1b4597a781 160 | 161 | struct stivale2_struct_tag_cmdline 162 | { 163 | struct stivale2_tag tag; 164 | uint64_t cmdline; 165 | }; 166 | 167 | #define STIVALE2_STRUCT_TAG_MEMMAP_ID 0x2187f79e8612de07 168 | 169 | #define STIVALE2_MMAP_USABLE 1 170 | #define STIVALE2_MMAP_RESERVED 2 171 | #define STIVALE2_MMAP_ACPI_RECLAIMABLE 3 172 | #define STIVALE2_MMAP_ACPI_NVS 4 173 | #define STIVALE2_MMAP_BAD_MEMORY 5 174 | #define STIVALE2_MMAP_BOOTLOADER_RECLAIMABLE 0x1000 175 | #define STIVALE2_MMAP_KERNEL_AND_MODULES 0x1001 176 | #define STIVALE2_MMAP_FRAMEBUFFER 0x1002 177 | 178 | struct stivale2_mmap_entry 179 | { 180 | uint64_t base; 181 | uint64_t length; 182 | uint32_t type; 183 | uint32_t unused; 184 | }; 185 | 186 | struct stivale2_struct_tag_memmap 187 | { 188 | struct stivale2_tag tag; 189 | uint64_t entries; 190 | struct stivale2_mmap_entry memmap[]; 191 | }; 192 | 193 | #define STIVALE2_STRUCT_TAG_FRAMEBUFFER_ID 0x506461d2950408fa 194 | 195 | #define STIVALE2_FBUF_MMODEL_RGB 1 196 | 197 | struct stivale2_struct_tag_framebuffer 198 | { 199 | struct stivale2_tag tag; 200 | uint64_t framebuffer_addr; 201 | uint16_t framebuffer_width; 202 | uint16_t framebuffer_height; 203 | uint16_t framebuffer_pitch; 204 | uint16_t framebuffer_bpp; 205 | uint8_t memory_model; 206 | uint8_t red_mask_size; 207 | uint8_t red_mask_shift; 208 | uint8_t green_mask_size; 209 | uint8_t green_mask_shift; 210 | uint8_t blue_mask_size; 211 | uint8_t blue_mask_shift; 212 | uint8_t unused; 213 | }; 214 | 215 | #define STIVALE2_STRUCT_TAG_EDID_ID 0x968609d7af96b845 216 | 217 | struct stivale2_struct_tag_edid 218 | { 219 | struct stivale2_tag tag; 220 | uint64_t edid_size; 221 | uint8_t edid_information[]; 222 | }; 223 | 224 | #define STIVALE2_STRUCT_TAG_TEXTMODE_ID 0x38d74c23e0dca893 225 | 226 | struct stivale2_struct_tag_textmode 227 | { 228 | struct stivale2_tag tag; 229 | uint64_t address; 230 | uint16_t unused; 231 | uint16_t rows; 232 | uint16_t cols; 233 | uint16_t bytes_per_char; 234 | }; 235 | 236 | #define STIVALE2_STRUCT_TAG_FB_MTRR_ID 0x6bc1a78ebe871172 237 | 238 | #define STIVALE2_STRUCT_TAG_TERMINAL_ID 0xc2b3f4c3233b0974 239 | 240 | struct stivale2_struct_tag_terminal 241 | { 242 | struct stivale2_tag tag; 243 | uint32_t flags; 244 | uint16_t cols; 245 | uint16_t rows; 246 | uint64_t term_write; 247 | uint64_t max_length; 248 | }; 249 | 250 | #define STIVALE2_STRUCT_TAG_MODULES_ID 0x4b6fe466aade04ce 251 | 252 | struct stivale2_module 253 | { 254 | uint64_t begin; 255 | uint64_t end; 256 | 257 | #define STIVALE2_MODULE_STRING_SIZE 128 258 | char string[STIVALE2_MODULE_STRING_SIZE]; 259 | }; 260 | 261 | struct stivale2_struct_tag_modules 262 | { 263 | struct stivale2_tag tag; 264 | uint64_t module_count; 265 | struct stivale2_module modules[]; 266 | }; 267 | 268 | #define STIVALE2_STRUCT_TAG_RSDP_ID 0x9e1786930a375e78 269 | 270 | struct stivale2_struct_tag_rsdp 271 | { 272 | struct stivale2_tag tag; 273 | uint64_t rsdp; 274 | }; 275 | 276 | #define STIVALE2_STRUCT_TAG_EPOCH_ID 0x566a7bed888e1407 277 | 278 | struct stivale2_struct_tag_epoch 279 | { 280 | struct stivale2_tag tag; 281 | uint64_t epoch; 282 | }; 283 | 284 | #define STIVALE2_STRUCT_TAG_FIRMWARE_ID 0x359d837855e3858c 285 | 286 | #define STIVALE2_FIRMWARE_BIOS (1 << 0) 287 | 288 | struct stivale2_struct_tag_firmware 289 | { 290 | struct stivale2_tag tag; 291 | uint64_t flags; 292 | }; 293 | 294 | #define STIVALE2_STRUCT_TAG_EFI_SYSTEM_TABLE_ID 0x4bc5ec15845b558e 295 | 296 | struct stivale2_struct_tag_efi_system_table 297 | { 298 | struct stivale2_tag tag; 299 | uint64_t system_table; 300 | }; 301 | 302 | #define STIVALE2_STRUCT_TAG_KERNEL_FILE_ID 0xe599d90c2975584a 303 | 304 | struct stivale2_struct_tag_kernel_file 305 | { 306 | struct stivale2_tag tag; 307 | uint64_t kernel_file; 308 | }; 309 | 310 | #define STIVALE2_STRUCT_TAG_KERNEL_FILE_V2_ID 0x37c13018a02c6ea2 311 | 312 | struct stivale2_struct_tag_kernel_file_v2 313 | { 314 | struct stivale2_tag tag; 315 | uint64_t kernel_file; 316 | uint64_t kernel_size; 317 | }; 318 | 319 | #define STIVALE2_STRUCT_TAG_BOOT_VOLUME_ID 0x9b4358364c19ee62 320 | 321 | struct stivale2_guid 322 | { 323 | uint32_t a; 324 | uint16_t b; 325 | uint16_t c; 326 | uint8_t d[8]; 327 | }; 328 | 329 | struct stivale2_struct_tag_boot_volume 330 | { 331 | struct stivale2_tag tag; 332 | uint64_t flags; 333 | struct stivale2_guid guid; 334 | struct stivale2_guid part_guid; 335 | }; 336 | 337 | #define STIVALE2_STRUCT_TAG_KERNEL_SLIDE_ID 0xee80847d01506c57 338 | 339 | struct stivale2_struct_tag_kernel_slide 340 | { 341 | struct stivale2_tag tag; 342 | uint64_t kernel_slide; 343 | }; 344 | 345 | #define STIVALE2_STRUCT_TAG_SMBIOS_ID 0x274bd246c62bf7d1 346 | 347 | struct stivale2_struct_tag_smbios 348 | { 349 | struct stivale2_tag tag; 350 | uint64_t flags; 351 | uint64_t smbios_entry_32; 352 | uint64_t smbios_entry_64; 353 | }; 354 | 355 | #define STIVALE2_STRUCT_TAG_SMP_ID 0x34d1d96339647025 356 | 357 | struct stivale2_smp_info 358 | { 359 | uint32_t processor_id; 360 | uint32_t lapic_id; 361 | uint64_t target_stack; 362 | uint64_t goto_address; 363 | uint64_t extra_argument; 364 | }; 365 | 366 | struct stivale2_struct_tag_smp 367 | { 368 | struct stivale2_tag tag; 369 | uint64_t flags; 370 | uint32_t bsp_lapic_id; 371 | uint32_t unused; 372 | uint64_t cpu_count; 373 | struct stivale2_smp_info smp_info[]; 374 | }; 375 | 376 | #define STIVALE2_STRUCT_TAG_PXE_SERVER_INFO 0x29d1e96239247032 377 | 378 | struct stivale2_struct_tag_pxe_server_info 379 | { 380 | struct stivale2_tag tag; 381 | uint32_t server_ip; 382 | }; 383 | 384 | #define STIVALE2_STRUCT_TAG_MMIO32_UART 0xb813f9b8dbc78797 385 | 386 | struct stivale2_struct_tag_mmio32_uart 387 | { 388 | struct stivale2_tag tag; 389 | uint64_t addr; 390 | }; 391 | 392 | #define STIVALE2_STRUCT_TAG_DTB 0xabb29bd49a2833fa 393 | 394 | struct stivale2_struct_tag_dtb 395 | { 396 | struct stivale2_tag tag; 397 | uint64_t addr; 398 | uint64_t size; 399 | }; 400 | 401 | #define STIVALE2_STRUCT_TAG_HHDM_ID 0xb0ed257db18cb58f 402 | 403 | struct stivale2_struct_tag_hhdm 404 | { 405 | struct stivale2_tag tag; 406 | uint64_t addr; 407 | }; 408 | 409 | void *stivale2_get_tag(struct stivale2_struct *stivale2_struct, uint64_t id); 410 | 411 | #undef _stivale2_split64 412 | 413 | #endif 414 | -------------------------------------------------------------------------------- /src/kernel/syscalls.c: -------------------------------------------------------------------------------- 1 | #include "arch/memory/vmm.h" 2 | #include "fs/vfs.h" 3 | #include "lib/lock.h" 4 | #include "lib/vec.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define AT_FDCWD -100 11 | 12 | typedef int64_t Syscall(Stack *params); 13 | 14 | uint32_t lock; 15 | 16 | int64_t sys_log(Stack *stack) 17 | { 18 | spin_lock(&lock); 19 | 20 | log((char *)stack->rdi); 21 | 22 | spin_release(&lock); 23 | 24 | return 0; 25 | } 26 | 27 | int64_t sys_mmap(Stack *stack) 28 | { 29 | size_t ret = 0; 30 | 31 | vmm_mmap(sched_current_task()->pagemap, stack->rdi, stack->rsi, stack->r10, &sched_current_task()->used_pages, &ret); 32 | 33 | stack->rax = ret; 34 | return ret; 35 | } 36 | 37 | int64_t sys_set_fs(Stack *stack) 38 | { 39 | asm_write_msr(0xc0000100, (uintptr_t)stack->rdi); 40 | 41 | return 0; 42 | } 43 | 44 | FileDescriptor get_fd(int fd) 45 | { 46 | if (fd - 1 > sched_current_task()->descriptors.length) 47 | { 48 | log("INVALID FD: %d", fd); 49 | } 50 | 51 | return sched_current_task()->descriptors.data[fd]; 52 | } 53 | 54 | int64_t sys_openat(Stack *stack) 55 | { 56 | int dirfd = (int)stack->rdi; 57 | const char *path = (const char *)stack->rsi; 58 | mode_t mode = (mode_t)stack->r10; 59 | 60 | VfsNode *parent = NULL; 61 | 62 | if (dirfd == AT_FDCWD) 63 | { 64 | parent = vfs_get_parent(sched_current_task()->cwd, (char *)path); 65 | } 66 | 67 | else 68 | { 69 | parent = vfs_get_parent(get_fd(dirfd).file, (char *)path); 70 | } 71 | 72 | if (!parent) 73 | { 74 | set_errno(ENOENT); 75 | stack->rax = (uint64_t)-1; 76 | return -1; 77 | } 78 | 79 | FileDescriptor new_fd = {.file = vfs_open(parent, (char *)path, mode), .fd = sched_current_task()->current_fd++}; 80 | 81 | vec_push(&sched_current_task()->descriptors, new_fd); 82 | 83 | if (nerd_logs()) 84 | { 85 | log("opened file \"%s\" in dir \"%s\" with fd %d", path, parent->name, new_fd.fd); 86 | } 87 | 88 | stack->rax = new_fd.fd; 89 | 90 | return new_fd.fd; 91 | } 92 | 93 | int64_t sys_read(Stack *stack) 94 | { 95 | 96 | int fd = (int)stack->rdi; 97 | void *buf = (void *)stack->rsi; 98 | size_t count = (size_t)stack->rdx; 99 | 100 | ssize_t ret = vfs_read(get_fd(fd).file, get_fd(fd).file->cursor, count, buf); 101 | get_fd(fd).file->cursor += count; 102 | 103 | stack->rax = (uint64_t)ret; 104 | 105 | return ret; 106 | } 107 | 108 | int64_t sys_write(Stack *stack) 109 | { 110 | int fd = (int)stack->rdi; 111 | void *buf = (void *)stack->rsi; 112 | size_t count = (size_t)stack->rdx; 113 | 114 | ssize_t ret = vfs_write(get_fd(fd).file, count, buf); 115 | 116 | stack->rax = (uint64_t)ret; 117 | return ret; 118 | } 119 | 120 | int64_t sys_close(Stack *stack) 121 | { 122 | int fildes = (int)stack->rdi; 123 | 124 | vec_splice(&sched_current_task()->descriptors, fildes, 1); 125 | 126 | VfsNode *file = get_fd(fildes).file; 127 | 128 | file->init = false; 129 | file->cursor = 0; 130 | 131 | free((void *)file->address); 132 | 133 | sched_current_task()->current_fd--; 134 | 135 | if (nerd_logs()) 136 | { 137 | log("closed fd %d", fildes); 138 | } 139 | stack->rax = 0; 140 | return 0; 141 | } 142 | 143 | #define SEEK_CUR 1 144 | #define SEEK_END 2 145 | #define SEEK_SET 3 146 | 147 | int64_t sys_seek(Stack *stack) 148 | { 149 | int fd = (int)stack->rdi; 150 | off_t offset = (off_t)stack->rsi; 151 | int whence = (int)stack->rdx; 152 | 153 | VfsNode *file = get_fd(fd).file; 154 | off_t base = 0; 155 | switch (whence) 156 | { 157 | case SEEK_SET: 158 | base = offset; 159 | break; 160 | case SEEK_CUR: 161 | base = file->cursor + offset; 162 | break; 163 | case SEEK_END: 164 | base = file->stat.st_size + offset; 165 | break; 166 | default: 167 | set_errno(EINVAL); 168 | stack->rax = (uint64_t)-1; 169 | return -1; 170 | } 171 | 172 | file->cursor = base; 173 | stack->rax = (uint64_t)base; 174 | return base; 175 | } 176 | 177 | int64_t sys_exit(Stack *stack) 178 | { 179 | int status = (int)stack->rdi; 180 | 181 | sched_remove(sched_current_task()); 182 | 183 | sched_current_task()->state = -1; 184 | sched_current_task()->exit_code = status; 185 | 186 | pmm_free(sched_current_task()->sp, STACK_SIZE / PAGE_SIZE); 187 | pmm_free((void *)((uintptr_t)sched_current_task()->pagemap - MMAP_KERNEL_BASE), 1); 188 | vec_deinit(&sched_current_task()->descriptors); 189 | 190 | for (;;) 191 | ; 192 | } 193 | 194 | int64_t sys_execve(Stack *stack) 195 | { 196 | const char *path = (const char *)stack->rdi; 197 | const char **argv = (const char **)stack->rsi; 198 | const char **envp = (const char **)stack->rdx; 199 | 200 | sched_new_elf_process((char *)path, argv, envp, NULL, NULL, NULL); 201 | sched_set_index(sched_get_last_pid() - 2); 202 | sched_set_tick(SWITCH_TICK - 1); 203 | 204 | stack->rax = 0; 205 | return 0; 206 | } 207 | 208 | Syscall *syscalls[] = { 209 | [SYSCALL_LOG] = sys_log, 210 | [SYSCALL_MMAP] = sys_mmap, 211 | [SYSCALL_SET_FS_BASE] = sys_set_fs, 212 | [SYSCALL_OPENAT] = sys_openat, 213 | [SYSCALL_READ] = sys_read, 214 | [SYSCALL_WRITE] = sys_write, 215 | [SYSCALL_CLOSE] = sys_close, 216 | [SYSCALL_SEEK] = sys_seek, 217 | [SYSCALL_EXIT] = sys_exit, 218 | [SYSCALL_EXECVE] = sys_execve, 219 | }; 220 | 221 | int64_t syscall_dispatch(int num, Stack *args) 222 | { 223 | 224 | syscalls[num](args); 225 | 226 | if (get_errno() > 0) 227 | { 228 | args->rdx = get_errno(); 229 | 230 | args->rax = (uint64_t)-1; 231 | 232 | set_errno(0); 233 | 234 | return args->rdx; 235 | } 236 | 237 | return 0; 238 | } -------------------------------------------------------------------------------- /src/kernel/syscalls.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_SYSCALL_H 2 | #define KERNEL_SYSCALL_H 3 | 4 | #define SYSCALL_LOG 0 5 | #define SYSCALL_MMAP 1 6 | #define SYSCALL_SET_FS_BASE 2 7 | #define SYSCALL_OPENAT 3 8 | #define SYSCALL_READ 4 9 | #define SYSCALL_WRITE 5 10 | #define SYSCALL_CLOSE 6 11 | #define SYSCALL_SEEK 7 12 | #define SYSCALL_EXIT 8 13 | #define SYSCALL_EXECVE 9 14 | 15 | #include 16 | 17 | int64_t syscall_dispatch(int num, Stack *args); 18 | 19 | #endif -------------------------------------------------------------------------------- /src/lib/abi.h: -------------------------------------------------------------------------------- 1 | #ifndef LIB_ABI_H 2 | #define LIB_ABI_H 3 | #include 4 | 5 | // from https://github.com/lyre-os/lyre/blob/9837904d7407ae41173b3160523f4c732a063a2e/kernel/lib/types.h 6 | 7 | #define NAME_MAX 256 8 | 9 | typedef int64_t ssize_t; 10 | typedef int64_t off_t; 11 | 12 | typedef uint64_t dev_t; 13 | typedef uint64_t ino_t; 14 | typedef int32_t mode_t; 15 | typedef int32_t nlink_t; 16 | typedef int64_t blksize_t; 17 | typedef int64_t blkcnt_t; 18 | 19 | typedef int32_t pid_t; 20 | typedef int32_t tid_t; 21 | typedef int32_t uid_t; 22 | typedef int32_t gid_t; 23 | 24 | typedef int64_t time_t; 25 | typedef int64_t clockid_t; 26 | 27 | struct timespec 28 | { 29 | time_t tv_sec; 30 | long tv_nsec; 31 | }; 32 | 33 | #define O_ACCMODE 0x0007 34 | #define O_EXEC 1 35 | #define O_RDONLY 2 36 | #define O_RDWR 3 37 | #define O_SEARCH 4 38 | #define O_WRONLY 5 39 | 40 | #define O_APPEND 0x0008 41 | #define O_CREAT 0x0010 42 | #define O_DIRECTORY 0x0020 43 | #define O_EXCL 0x0040 44 | #define O_NOCTTY 0x0080 45 | #define O_NOFOLLOW 0x0100 46 | #define O_TRUNC 0x0200 47 | #define O_NONBLOCK 0x0400 48 | #define O_DSYNC 0x0800 49 | #define O_RSYNC 0x1000 50 | #define O_SYNC 0x2000 51 | #define O_CLOEXEC 0x4000 52 | 53 | #define S_IFMT 0x0F000 54 | #define S_IFBLK 0x06000 55 | #define S_IFCHR 0x02000 56 | #define S_IFIFO 0x01000 57 | #define S_IFREG 0x08000 58 | #define S_IFDIR 0x04000 59 | #define S_IFLNK 0x0A000 60 | #define S_IFSOCK 0x0C000 61 | #define S_IFPIPE 0x03000 62 | 63 | #define S_ISBLK(m) (((m)&S_IFMT) == S_IFBLK) 64 | #define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR) 65 | #define S_ISFIFO(m) (((m)&S_IFMT) == S_IFIFO) 66 | #define S_ISREG(m) (((m)&S_IFMT) == S_IFREG) 67 | #define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) 68 | #define S_ISLNK(m) (((m)&S_IFMT) == S_IFLNK) 69 | #define S_ISSOCK(m) (((m)&S_IFMT) == S_IFSOCK) 70 | 71 | #define DT_UNKNOWN 0 72 | #define DT_FIFO 1 73 | #define DT_CHR 2 74 | #define DT_DIR 4 75 | #define DT_BLK 6 76 | #define DT_REG 8 77 | #define DT_LNK 10 78 | #define DT_SOCK 12 79 | #define DT_WHT 14 80 | 81 | struct stat 82 | { 83 | dev_t st_dev; 84 | ino_t st_ino; 85 | mode_t st_mode; 86 | nlink_t st_nlink; 87 | uid_t st_uid; 88 | gid_t st_gid; 89 | dev_t st_rdev; 90 | off_t st_size; 91 | struct timespec st_atim; 92 | struct timespec st_mtim; 93 | struct timespec st_ctim; 94 | blksize_t st_blksize; 95 | blkcnt_t st_blocks; 96 | }; 97 | 98 | struct dirent 99 | { 100 | ino_t d_ino; 101 | off_t d_off; 102 | unsigned short d_reclen; 103 | unsigned char d_type; 104 | char d_name[1024]; 105 | }; 106 | 107 | #endif -------------------------------------------------------------------------------- /src/lib/alloc.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /** Durand's Ridiculously Amazing Super Duper Memory functions. */ 4 | 5 | //#define DEBUG 6 | 7 | #define LIBALLOC_MAGIC 0xc001c0de 8 | #define MAXCOMPLETE 5 9 | #define MAXEXP 32 10 | #define MINEXP 8 11 | 12 | #define MODE_BEST 0 13 | #define MODE_INSTANT 1 14 | 15 | #define MODE MODE_BEST 16 | 17 | #ifdef DEBUG 18 | # include 19 | #endif 20 | 21 | struct boundary_tag *l_freePages[MAXEXP]; //< Allowing for 2^MAXEXP blocks 22 | int l_completePages[MAXEXP]; //< Allowing for 2^MAXEXP blocks 23 | 24 | #ifdef DEBUG 25 | unsigned int l_allocated = 0; //< The real amount of memory allocated. 26 | unsigned int l_inuse = 0; //< The amount of memory in use (malloc'ed). 27 | #endif 28 | 29 | static int l_initialized = 0; //< Flag to indicate initialization. 30 | static int l_pageSize = 4096; //< Individual page size 31 | static int l_pageCount = 16; //< Minimum number of pages to allocate. 32 | 33 | // *********** HELPER FUNCTIONS ******************************* 34 | 35 | /** Returns the exponent required to manage 'size' amount of memory. 36 | * 37 | * Returns n where 2^n <= size < 2^(n+1) 38 | */ 39 | static inline int getexp(size_t size) 40 | { 41 | if (size < (1 << MINEXP)) 42 | { 43 | #ifdef DEBUG 44 | printf("getexp returns -1 for %i less than MINEXP\n", size); 45 | #endif 46 | return -1; // Smaller than the quantum. 47 | } 48 | 49 | size_t shift = MINEXP; 50 | 51 | while (shift < MAXEXP) 52 | { 53 | if ((size_t)(1 << shift) > size) 54 | break; 55 | shift += 1; 56 | } 57 | 58 | #ifdef DEBUG 59 | printf("getexp returns %i (%i bytes) for %i size\n", shift - 1, (1 << (shift - 1)), size); 60 | #endif 61 | 62 | return shift - 1; 63 | } 64 | 65 | static void *liballoc_memset(void *s, int c, size_t n) 66 | { 67 | size_t i; 68 | for (i = 0; i < n; i++) 69 | ((char *)s)[i] = c; 70 | 71 | return s; 72 | } 73 | 74 | static void *liballoc_memcpy(void *s1, const void *s2, size_t n) 75 | { 76 | char *cdest; 77 | char *csrc; 78 | unsigned int *ldest = (unsigned int *)s1; 79 | unsigned int *lsrc = (unsigned int *)s2; 80 | 81 | while (n >= sizeof(unsigned int)) 82 | { 83 | *ldest++ = *lsrc++; 84 | n -= sizeof(unsigned int); 85 | } 86 | 87 | cdest = (char *)ldest; 88 | csrc = (char *)lsrc; 89 | 90 | while (n > 0) 91 | { 92 | *cdest++ = *csrc++; 93 | n -= 1; 94 | } 95 | 96 | return s1; 97 | } 98 | 99 | #ifdef DEBUG 100 | static void dump_array() 101 | { 102 | int i = 0; 103 | struct boundary_tag *tag = NULL; 104 | 105 | printf("------ Free pages array ---------\n"); 106 | printf("System memory allocated: %i\n", l_allocated); 107 | printf("Memory in used (malloc'ed): %i\n", l_inuse); 108 | 109 | for (i = 0; i < MAXEXP; i++) 110 | { 111 | printf("%.2i(%i): ", i, l_completePages[i]); 112 | 113 | tag = l_freePages[i]; 114 | while (tag != NULL) 115 | { 116 | if (tag->split_left != NULL) 117 | printf("*"); 118 | printf("%i", tag->real_size); 119 | if (tag->split_right != NULL) 120 | printf("*"); 121 | 122 | printf(" "); 123 | tag = tag->next; 124 | } 125 | printf("\n"); 126 | } 127 | 128 | printf("'*' denotes a split to the left/right of a tag\n"); 129 | fflush(stdout); 130 | } 131 | #endif 132 | 133 | static inline void insert_tag(struct boundary_tag *tag, int index) 134 | { 135 | int realIndex; 136 | 137 | if (index < 0) 138 | { 139 | realIndex = getexp(tag->real_size - sizeof(struct boundary_tag)); 140 | if (realIndex < MINEXP) 141 | realIndex = MINEXP; 142 | } 143 | else 144 | realIndex = index; 145 | 146 | tag->index = realIndex; 147 | 148 | if (l_freePages[realIndex] != NULL) 149 | { 150 | l_freePages[realIndex]->prev = tag; 151 | tag->next = l_freePages[realIndex]; 152 | } 153 | 154 | l_freePages[realIndex] = tag; 155 | } 156 | 157 | static inline void remove_tag(struct boundary_tag *tag) 158 | { 159 | if (l_freePages[tag->index] == tag) 160 | l_freePages[tag->index] = tag->next; 161 | 162 | if (tag->prev != NULL) 163 | tag->prev->next = tag->next; 164 | if (tag->next != NULL) 165 | tag->next->prev = tag->prev; 166 | 167 | tag->next = NULL; 168 | tag->prev = NULL; 169 | tag->index = -1; 170 | } 171 | 172 | static inline struct boundary_tag *melt_left(struct boundary_tag *tag) 173 | { 174 | struct boundary_tag *left = tag->split_left; 175 | 176 | left->real_size += tag->real_size; 177 | left->split_right = tag->split_right; 178 | 179 | if (tag->split_right != NULL) 180 | tag->split_right->split_left = left; 181 | 182 | return left; 183 | } 184 | 185 | static inline struct boundary_tag *absorb_right(struct boundary_tag *tag) 186 | { 187 | struct boundary_tag *right = tag->split_right; 188 | 189 | remove_tag(right); // Remove right from free pages. 190 | 191 | tag->real_size += right->real_size; 192 | 193 | tag->split_right = right->split_right; 194 | if (right->split_right != NULL) 195 | right->split_right->split_left = tag; 196 | 197 | return tag; 198 | } 199 | 200 | static inline struct boundary_tag *split_tag(struct boundary_tag *tag) 201 | { 202 | unsigned int remainder = tag->real_size - sizeof(struct boundary_tag) - tag->size; 203 | 204 | struct boundary_tag *new_tag = 205 | (struct boundary_tag *)((uintptr_t)tag + sizeof(struct boundary_tag) + tag->size); 206 | 207 | new_tag->magic = LIBALLOC_MAGIC; 208 | new_tag->real_size = remainder; 209 | 210 | new_tag->next = NULL; 211 | new_tag->prev = NULL; 212 | 213 | new_tag->split_left = tag; 214 | new_tag->split_right = tag->split_right; 215 | 216 | if (new_tag->split_right != NULL) 217 | new_tag->split_right->split_left = new_tag; 218 | tag->split_right = new_tag; 219 | 220 | tag->real_size -= new_tag->real_size; 221 | 222 | insert_tag(new_tag, -1); 223 | 224 | return new_tag; 225 | } 226 | 227 | // *************************************************************** 228 | 229 | static struct boundary_tag *allocate_new_tag(unsigned int size) 230 | { 231 | size_t pages; 232 | unsigned int usage; 233 | struct boundary_tag *tag; 234 | 235 | // This is how much space is required. 236 | usage = size + sizeof(struct boundary_tag); 237 | 238 | // Perfect amount of space 239 | pages = usage / l_pageSize; 240 | if ((usage % l_pageSize) != 0) 241 | pages += 1; 242 | 243 | // Make sure it's >= the minimum size. 244 | if ((int)pages < l_pageCount) 245 | pages = l_pageCount; 246 | 247 | tag = (struct boundary_tag *)liballoc_alloc(pages); 248 | 249 | if (tag == NULL) 250 | return NULL; // uh oh, we ran out of memory. 251 | 252 | tag->magic = LIBALLOC_MAGIC; 253 | tag->size = size; 254 | tag->real_size = pages * l_pageSize; 255 | tag->index = -1; 256 | 257 | tag->next = NULL; 258 | tag->prev = NULL; 259 | tag->split_left = NULL; 260 | tag->split_right = NULL; 261 | 262 | #ifdef DEBUG 263 | printf("Resource allocated %x of %i pages (%i bytes) for %i size.\n", tag, pages, pages * l_pageSize, size); 264 | 265 | l_allocated += pages * l_pageSize; 266 | 267 | printf("Total memory usage = %i KB\n", (int)((l_allocated / (1024)))); 268 | #endif 269 | 270 | return tag; 271 | } 272 | 273 | void *malloc(size_t size) 274 | { 275 | int index; 276 | void *ptr; 277 | struct boundary_tag *tag = NULL; 278 | 279 | liballoc_lock(); 280 | 281 | if (l_initialized == 0) 282 | { 283 | #ifdef DEBUG 284 | printf("%s\n", "liballoc initializing."); 285 | #endif 286 | for (index = 0; index < MAXEXP; index++) 287 | { 288 | l_freePages[index] = NULL; 289 | l_completePages[index] = 0; 290 | } 291 | l_initialized = 1; 292 | } 293 | 294 | index = getexp(size) + MODE; 295 | if (index < MINEXP) 296 | index = MINEXP; 297 | 298 | // Find one big enough. 299 | tag = l_freePages[index]; // Start at the front of the list. 300 | while (tag != NULL) 301 | { 302 | // If there's enough space in this tag. 303 | if ((tag->real_size - sizeof(struct boundary_tag)) >= (size + sizeof(struct boundary_tag))) 304 | { 305 | #ifdef DEBUG 306 | printf("Tag search found %i >= %i\n", (tag->real_size - sizeof(struct boundary_tag)), (size + sizeof(struct boundary_tag))); 307 | #endif 308 | break; 309 | } 310 | 311 | tag = tag->next; 312 | } 313 | 314 | // No page found. Make one. 315 | if (tag == NULL) 316 | { 317 | if ((tag = allocate_new_tag(size)) == NULL) 318 | { 319 | liballoc_unlock(); 320 | return NULL; 321 | } 322 | 323 | index = getexp(tag->real_size - sizeof(struct boundary_tag)); 324 | } 325 | else 326 | { 327 | remove_tag(tag); 328 | 329 | if ((tag->split_left == NULL) && (tag->split_right == NULL)) 330 | l_completePages[index] -= 1; 331 | } 332 | 333 | // We have a free page. Remove it from the free pages list. 334 | 335 | tag->size = size; 336 | 337 | // Removed... see if we can re-use the excess space. 338 | 339 | #ifdef DEBUG 340 | printf("Found tag with %i bytes available (requested %i bytes, leaving %i), which has exponent: %i (%i bytes)\n", tag->real_size - sizeof(struct boundary_tag), size, tag->real_size - size - sizeof(struct boundary_tag), index, 1 << index); 341 | #endif 342 | 343 | unsigned int remainder = tag->real_size - size - sizeof(struct boundary_tag) * 2; // Support a new tag + remainder 344 | 345 | if (((int)(remainder) > 0) /*&& ( (tag->real_size - remainder) >= (1<= 0) 350 | { 351 | #ifdef DEBUG 352 | printf("Seems to be splittable: %i >= 2^%i .. %i\n", remainder, childIndex, (1 << childIndex)); 353 | #endif 354 | 355 | struct boundary_tag *new_tag = split_tag(tag); 356 | 357 | new_tag = new_tag; // Get around the compiler warning about unused variables. 358 | 359 | #ifdef DEBUG 360 | printf("Old tag has become %i bytes, new tag is now %i bytes (%i exp)\n", tag->real_size, new_tag->real_size, new_tag->index); 361 | #endif 362 | } 363 | } 364 | 365 | ptr = (void *)((uintptr_t)tag + sizeof(struct boundary_tag)); 366 | 367 | #ifdef DEBUG 368 | l_inuse += size; 369 | printf("malloc: %x, %i, %i\n", ptr, (int)l_inuse / 1024, (int)l_allocated / 1024); 370 | dump_array(); 371 | #endif 372 | 373 | liballoc_unlock(); 374 | return ptr; 375 | } 376 | 377 | void free(void *ptr) 378 | { 379 | int index; 380 | struct boundary_tag *tag; 381 | 382 | if (ptr == NULL) 383 | return; 384 | 385 | liballoc_lock(); 386 | 387 | tag = (struct boundary_tag *)((uintptr_t)ptr - sizeof(struct boundary_tag)); 388 | 389 | if (tag->magic != LIBALLOC_MAGIC) 390 | { 391 | liballoc_unlock(); // release the lock 392 | return; 393 | } 394 | 395 | #ifdef DEBUG 396 | l_inuse -= tag->size; 397 | printf("free: %x, %i, %i\n", ptr, (int)l_inuse / 1024, (int)l_allocated / 1024); 398 | #endif 399 | 400 | // MELT LEFT... 401 | while ((tag->split_left != NULL) && (tag->split_left->index >= 0)) 402 | { 403 | #ifdef DEBUG 404 | printf("Melting tag left into available memory. Left was %i, becomes %i (%i)\n", tag->split_left->real_size, tag->split_left->real_size + tag->real_size, tag->split_left->real_size); 405 | #endif 406 | tag = melt_left(tag); 407 | remove_tag(tag); 408 | } 409 | 410 | // MELT RIGHT... 411 | while ((tag->split_right != NULL) && (tag->split_right->index >= 0)) 412 | { 413 | #ifdef DEBUG 414 | printf("Melting tag right into available memory. This was was %i, becomes %i (%i)\n", tag->real_size, tag->split_right->real_size + tag->real_size, tag->split_right->real_size); 415 | #endif 416 | tag = absorb_right(tag); 417 | } 418 | 419 | // Where is it going back to? 420 | index = getexp(tag->real_size - sizeof(struct boundary_tag)); 421 | if (index < MINEXP) 422 | index = MINEXP; 423 | 424 | // A whole, empty block? 425 | if ((tag->split_left == NULL) && (tag->split_right == NULL)) 426 | { 427 | 428 | if (l_completePages[index] == MAXCOMPLETE) 429 | { 430 | // Too many standing by to keep. Free this one. 431 | unsigned int pages = tag->real_size / l_pageSize; 432 | 433 | if ((tag->real_size % l_pageSize) != 0) 434 | pages += 1; 435 | if ((int)pages < l_pageCount) 436 | pages = l_pageCount; 437 | 438 | liballoc_free(tag, pages); 439 | 440 | #ifdef DEBUG 441 | l_allocated -= pages * l_pageSize; 442 | printf("Resource freeing %x of %i pages\n", tag, pages); 443 | dump_array(); 444 | #endif 445 | 446 | liballoc_unlock(); 447 | return; 448 | } 449 | 450 | l_completePages[index] += 1; // Increase the count of complete pages. 451 | } 452 | 453 | // .......... 454 | 455 | insert_tag(tag, index); 456 | 457 | #ifdef DEBUG 458 | printf("Returning tag with %i bytes (requested %i bytes), which has exponent: %i\n", tag->real_size, tag->size, index); 459 | dump_array(); 460 | #endif 461 | 462 | liballoc_unlock(); 463 | } 464 | 465 | void *calloc(size_t nobj, size_t size) 466 | { 467 | int real_size; 468 | void *p; 469 | 470 | real_size = nobj * size; 471 | 472 | p = malloc(real_size); 473 | 474 | liballoc_memset(p, 0, real_size); 475 | 476 | return p; 477 | } 478 | 479 | void *realloc(void *p, size_t size) 480 | { 481 | void *ptr; 482 | struct boundary_tag *tag; 483 | int real_size; 484 | 485 | if (size == 0) 486 | { 487 | free(p); 488 | return NULL; 489 | } 490 | if (p == NULL) 491 | return malloc(size); 492 | 493 | liballoc_lock(); // lockit 494 | tag = (struct boundary_tag *)((uintptr_t)p - sizeof(struct boundary_tag)); 495 | real_size = tag->size; 496 | liballoc_unlock(); 497 | 498 | if (real_size > (int)size) 499 | real_size = size; 500 | 501 | ptr = malloc(size); 502 | liballoc_memcpy(ptr, p, real_size); 503 | free(p); 504 | 505 | return ptr; 506 | } 507 | -------------------------------------------------------------------------------- /src/lib/alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIBALLOC_H 2 | #define _LIBALLOC_H 3 | #include 4 | 5 | // If we are told to not define our own size_t, then we 6 | // skip the define. 7 | #ifndef _ALLOC_SKIP_DEFINE 8 | 9 | # ifndef NULL 10 | # define NULL 0 11 | # endif 12 | 13 | #endif 14 | 15 | #ifdef __cplusplus 16 | extern "C" 17 | { 18 | #endif 19 | 20 | /** This is a boundary tag which is prepended to the 21 | * page or section of a page which we have allocated. It is 22 | * used to identify valid memory blocks that the 23 | * application is trying to free. 24 | */ 25 | struct boundary_tag 26 | { 27 | unsigned int magic; //< It's a kind of ... 28 | unsigned int size; //< Requested size. 29 | unsigned int real_size; //< Actual size. 30 | int index; //< Location in the page table. 31 | 32 | struct boundary_tag *split_left; //< Linked-list info for broken pages. 33 | struct boundary_tag *split_right; //< The same. 34 | 35 | struct boundary_tag *next; //< Linked list info. 36 | struct boundary_tag *prev; //< Linked list info. 37 | }; 38 | 39 | /** This function is supposed to lock the memory data structures. It 40 | * could be as simple as disabling interrupts or acquiring a spinlock. 41 | * It's up to you to decide. 42 | * 43 | * \return 0 if the lock was acquired successfully. Anything else is 44 | * failure. 45 | */ 46 | extern int liballoc_lock(); 47 | 48 | /** This function unlocks what was previously locked by the liballoc_lock 49 | * function. If it disabled interrupts, it enables interrupts. If it 50 | * had acquiried a spinlock, it releases the spinlock. etc. 51 | * 52 | * \return 0 if the lock was successfully released. 53 | */ 54 | extern int liballoc_unlock(); 55 | 56 | /** This is the hook into the local system which allocates pages. It 57 | * accepts an integer parameter which is the number of pages 58 | * required. The page size was set up in the liballoc_init function. 59 | * 60 | * \return NULL if the pages were not allocated. 61 | * \return A pointer to the allocated memory. 62 | */ 63 | extern void *liballoc_alloc(int); 64 | 65 | /** This frees previously allocated memory. The void* parameter passed 66 | * to the function is the exact same value returned from a previous 67 | * liballoc_alloc call. 68 | * 69 | * The integer value is the number of pages to free. 70 | * 71 | * \return 0 if the memory was successfully freed. 72 | */ 73 | extern int liballoc_free(void *, int); 74 | 75 | void *malloc(size_t); //< The standard function. 76 | void *realloc(void *, size_t); //< The standard function. 77 | void *calloc(size_t, size_t); //< The standard function. 78 | void free(void *); //< The standard function. 79 | 80 | #ifdef __cplusplus 81 | } 82 | #endif 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /src/lib/base.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | bool nerd_logs(); 9 | 10 | #define MAYBE_UNUSED __attribute__((unused)) 11 | #define PACKED __attribute__((packed)) 12 | #define UNUSED(x) (void)x 13 | #define ARRLEN(x) sizeof(x) / sizeof(*x) 14 | 15 | #define foreach(NAME, RANGE) for (size_t NAME = 0; NAME < RANGE; NAME += 1) 16 | 17 | #define foreachr(NAME, RANGE, ADD) for (size_t NAME = 0; NAME < RANGE; NAME += ADD) 18 | 19 | #define ALIGN_UP(NUM, WHAT) (((NUM) + WHAT - 1) & ~(WHAT - 1)) 20 | #define ALIGN_DOWN(NUM, WHAT) ((NUM) & ~(WHAT - 1)) 21 | 22 | #define DIV_ROUNDUP(A, B) ({ \ 23 | (A + (B - 1)) / B; \ 24 | }) 25 | -------------------------------------------------------------------------------- /src/lib/errno.h: -------------------------------------------------------------------------------- 1 | #define EDOM 1 2 | #define EILSEQ 2 3 | #define ERANGE 3 4 | 5 | #define E2BIG 1001 6 | #define EACCES 1002 7 | #define EADDRINUSE 1003 8 | #define EADDRNOTAVAIL 1004 9 | #define EAFNOSUPPORT 1005 10 | #define EAGAIN 1006 11 | #define EALREADY 1007 12 | #define EBADF 1008 13 | #define EBADMSG 1009 14 | #define EBUSY 1010 15 | #define ECANCELED 1011 16 | #define ECHILD 1012 17 | #define ECONNABORTED 1013 18 | #define ECONNREFUSED 1014 19 | #define ECONNRESET 1015 20 | #define EDEADLK 1016 21 | #define EDESTADDRREQ 1017 22 | #define EDQUOT 1018 23 | #define EEXIST 1019 24 | #define EFAULT 1020 25 | #define EFBIG 1021 26 | #define EHOSTUNREACH 1022 27 | #define EIDRM 1023 28 | #define EINPROGRESS 1024 29 | #define EINTR 1025 30 | #define EINVAL 1026 31 | #define EIO 1027 32 | #define EISCONN 1028 33 | #define EISDIR 1029 34 | #define ELOOP 1030 35 | #define EMFILE 1031 36 | #define EMLINK 1032 37 | #define EMSGSIZE 1034 38 | #define EMULTIHOP 1035 39 | #define ENAMETOOLONG 1036 40 | #define ENETDOWN 1037 41 | #define ENETRESET 1038 42 | #define ENETUNREACH 1039 43 | #define ENFILE 1040 44 | #define ENOBUFS 1041 45 | #define ENODEV 1042 46 | #define ENOENT 1043 47 | #define ENOEXEC 1044 48 | #define ENOLCK 1045 49 | #define ENOLINK 1046 50 | #define ENOMEM 1047 51 | #define ENOMSG 1048 52 | #define ENOPROTOOPT 1049 53 | #define ENOSPC 1050 54 | #define ENOSYS 1051 55 | #define ENOTCONN 1052 56 | #define ENOTDIR 1053 57 | #define ENOTEMPTY 1054 58 | #define ENOTRECOVERABLE 1055 59 | #define ENOTSOCK 1056 60 | #define ENOTSUP 1057 61 | #define ENOTTY 1058 62 | #define ENXIO 1059 63 | #define EOPNOTSUPP 1060 64 | #define EOVERFLOW 1061 65 | #define EOWNERDEAD 1062 66 | #define EPERM 1063 67 | #define EPIPE 1064 68 | #define EPROTO 1065 69 | #define EPROTONOSUPPORT 1066 70 | #define EPROTOTYPE 1067 71 | #define EROFS 1068 72 | #define ESPIPE 1069 73 | #define ESRCH 1070 74 | #define ESTALE 1071 75 | #define ETIMEDOUT 1072 76 | #define ETXTBSY 1073 77 | #define EWOULDBLOCK EAGAIN 78 | #define EXDEV 1075 79 | #define ENODATA 1076 80 | #define ETIME 1077 81 | #define ENOKEY 1078 82 | #define ESHUTDOWN 1079 83 | #define EHOSTDOWN 1080 84 | #define EBADFD 1081 85 | #define ENOMEDIUM 1082 86 | #define ENOTBLK 1083 87 | 88 | void set_errno(int val); 89 | int get_errno(); 90 | -------------------------------------------------------------------------------- /src/lib/lock.h: -------------------------------------------------------------------------------- 1 | #ifndef LIB_LOCK_H 2 | #define LIB_LOCK_H 3 | #include 4 | 5 | static inline void spin_lock(void *lock) 6 | { 7 | while (__atomic_test_and_set(lock, __ATOMIC_ACQUIRE)) 8 | ; 9 | } 10 | 11 | static inline void spin_release(void *lock) 12 | { 13 | __atomic_clear(lock, __ATOMIC_RELEASE); 14 | } 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/lib/mem.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void *memset(void *s, uint8_t c, size_t n) 4 | { 5 | uint8_t *dest = (uint8_t *)s; 6 | 7 | for (size_t i = 0; i < n; i++) 8 | { 9 | dest[i] = c; 10 | } 11 | 12 | return s; 13 | } 14 | 15 | void *memcpy(void *to, void *from, size_t n) 16 | { 17 | uint8_t *dest = (uint8_t *)to; 18 | uint8_t const *src = (uint8_t const *)from; 19 | 20 | for (size_t i = 0; i < n; i++) 21 | { 22 | dest[i] = src[i]; 23 | } 24 | 25 | return to; 26 | } -------------------------------------------------------------------------------- /src/lib/mem.h: -------------------------------------------------------------------------------- 1 | #ifndef LIB_MEM_H 2 | #define LIB_MEM_H 3 | #include 4 | 5 | void *memset(void *s, uint8_t c, size_t n); 6 | void *memcpy(void *to, void *from, size_t n); 7 | #endif -------------------------------------------------------------------------------- /src/lib/print.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | MAYBE_UNUSED static char *string_convert(unsigned int num, int base) 6 | { 7 | static char representation[] = "0123456789ABCDEF"; 8 | static char buffer[50]; 9 | char *ptr; 10 | 11 | ptr = &buffer[49]; 12 | *ptr = '\0'; 13 | 14 | do 15 | { 16 | *--ptr = representation[num % base]; 17 | num /= base; 18 | } while (num != 0); 19 | return (ptr); 20 | } 21 | 22 | void fmt_str(void (*callback)(char *), char *fmt, va_list lst) 23 | { 24 | while (*fmt) 25 | { 26 | if (*fmt == '%') 27 | { 28 | fmt++; 29 | 30 | switch (*fmt) 31 | { 32 | case 'c': 33 | { 34 | char c = va_arg(lst, int); 35 | 36 | callback((char[]){c, 0}); 37 | break; 38 | } 39 | 40 | case 's': 41 | { 42 | callback(va_arg(lst, char *)); 43 | break; 44 | } 45 | 46 | case 'd': 47 | { 48 | callback(string_convert(va_arg(lst, int), 10)); 49 | break; 50 | } 51 | 52 | case 'x': 53 | { 54 | callback(string_convert(va_arg(lst, int), 16)); 55 | break; 56 | } 57 | } 58 | } 59 | 60 | else 61 | { 62 | callback((char[]){*fmt, 0}); 63 | } 64 | 65 | fmt++; 66 | } 67 | } 68 | 69 | void printf(char *fmt, ...) 70 | { 71 | va_list arg; 72 | va_start(arg, fmt); 73 | 74 | fmt_str(print, fmt, arg); 75 | 76 | va_end(arg); 77 | } 78 | 79 | void _log(int line, char *file, char *function, char *fmt, ...) 80 | { 81 | va_list arg; 82 | va_start(arg, fmt); 83 | 84 | printf("\033[1m%s:%d \033[1;35m%s \033[0m", file, line, function); 85 | fmt_str(print, fmt, arg); 86 | 87 | print("\n"); 88 | 89 | va_end(arg); 90 | } 91 | void print(char *str) 92 | { 93 | host_print(str, strlen(str)); 94 | } -------------------------------------------------------------------------------- /src/lib/print.h: -------------------------------------------------------------------------------- 1 | #ifndef LIB_PRINT_H 2 | #define LIB_PRINT_H 3 | #include 4 | 5 | void host_print(char *str, size_t s); 6 | char host_getc(); 7 | 8 | void print(char *str); 9 | 10 | #define putc(c) print((char[]){c, 0}) 11 | 12 | void fmt_str(void (*callback)(char *), char *fmt, va_list lst); 13 | 14 | void _log(int line, char *file, char *function, char *fmt, ...); 15 | #define __FILENAME__ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__) 16 | 17 | #define log(FMT, ...) _log(__LINE__, __FILENAME__, (char *)__FUNCTION__, FMT, ##__VA_ARGS__) 18 | 19 | #endif -------------------------------------------------------------------------------- /src/lib/str.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | size_t strlen(const char *str) 5 | { 6 | size_t length = 0; 7 | 8 | for (length = 0; str[length] != '\0'; ++length) 9 | ; 10 | 11 | return length; 12 | } 13 | 14 | bool str_eq(const char *s1, const char *s2) 15 | { 16 | if (strlen(s1) != strlen(s2)) 17 | return false; 18 | for (size_t i = 0; i < strlen(s1); i++) 19 | { 20 | if (s1[i] != s2[i]) 21 | return false; 22 | } 23 | return true; 24 | } 25 | 26 | char *strstr(char *str, char *substr) 27 | { 28 | char *a = str, *b = substr; 29 | while (true) 30 | { 31 | if (!*b) 32 | return (char *)str; 33 | if (!*a) 34 | return NULL; 35 | 36 | if (*a++ != *b++) 37 | { 38 | a = ++str; 39 | b = substr; 40 | } 41 | } 42 | } 43 | 44 | char *basename(char *path) 45 | { 46 | if (path[0] != '/') 47 | return path; 48 | 49 | if (strlen(path) == 1) 50 | return path; 51 | 52 | char *ssc = strstr(path, "/"); 53 | int l = 0; 54 | 55 | do 56 | { 57 | l = strlen(ssc) + 1; 58 | 59 | path = &path[strlen(path) - l + 2]; 60 | 61 | ssc = strstr(path, "/"); 62 | } while (ssc); 63 | 64 | return path; 65 | } 66 | 67 | char *strchr(char *s, char c) 68 | { 69 | while (*s != c) 70 | { 71 | if (!*s++) 72 | { 73 | return NULL; 74 | } 75 | } 76 | return s; 77 | } 78 | 79 | // strtok 80 | char *strtok(char *str, char *delim) 81 | { 82 | static char *s = NULL; 83 | char *token; 84 | 85 | if (str != NULL) 86 | s = str; 87 | 88 | if (s == NULL) 89 | return NULL; 90 | 91 | token = s; 92 | 93 | while (*s != '\0') 94 | { 95 | if (strchr(delim, *s) != NULL) 96 | { 97 | *s++ = '\0'; 98 | return token; 99 | } 100 | s++; 101 | } 102 | 103 | s = NULL; 104 | return token; 105 | } 106 | 107 | char *strdup(char *s) 108 | { 109 | 110 | char *str; 111 | char *p; 112 | int len = 0; 113 | 114 | while (s[len]) 115 | len++; 116 | str = malloc(len + 1); 117 | p = str; 118 | while (*s) 119 | *p++ = *s++; 120 | *p = '\0'; 121 | return str; 122 | } 123 | char *dirname(char *path) 124 | { 125 | char *dir = malloc(strlen(path) + 1); 126 | 127 | int i = 0; 128 | int j = 0; 129 | 130 | while (path[i] != '\0') 131 | { 132 | if (path[i] == '/') 133 | { 134 | j = i; 135 | } 136 | i++; 137 | } 138 | 139 | if (j == 0) 140 | { 141 | dir[0] = '/'; 142 | dir[1] = '\0'; 143 | return dir; 144 | } 145 | else 146 | { 147 | for (int k = 0; k < j; k++) 148 | { 149 | dir[k] = path[k]; 150 | } 151 | dir[j] = '\0'; 152 | return dir; 153 | } 154 | } 155 | 156 | char *strcat(char *s, char *s2) 157 | { 158 | char *p = s; 159 | while (*s) 160 | s++; 161 | while (*s2) 162 | *s++ = *s2++; 163 | *s = '\0'; 164 | return p; 165 | } 166 | 167 | char *strcpy(char *dest, const char *src) 168 | { 169 | size_t i; 170 | 171 | for (i = 0; src[i]; i++) 172 | dest[i] = src[i]; 173 | 174 | dest[i] = 0; 175 | 176 | return dest; 177 | } -------------------------------------------------------------------------------- /src/lib/str.h: -------------------------------------------------------------------------------- 1 | #ifndef LIB_STR_H 2 | #define LIB_STR_H 3 | #include 4 | 5 | size_t strlen(const char *str); 6 | 7 | bool str_eq(const char *s1, const char *s2); 8 | 9 | char *strstr(char *str, char *substr); 10 | char *strchr(char *str, char c); 11 | char *strrchr(char *str, char c); 12 | char *basename(char *s); 13 | char *dirname(char *path); 14 | 15 | char *strtok(char *str, char *delim); 16 | char *strdup(char *s); 17 | char *strcat(char *s, char *s2); 18 | char *strcpy(char *dest, const char *src); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/lib/vec.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 rxi 3 | * 4 | * This library is free software; you can redistribute it and/or modify it 5 | * under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #include "vec.h" 9 | 10 | void memmove(void *dest, const void *src, size_t n) 11 | { 12 | uint8_t *pdest = (uint8_t *)dest; 13 | const uint8_t *psrc = (const uint8_t *)src; 14 | 15 | size_t i; 16 | if (src > dest) 17 | { 18 | for (i = 0; i < n; i++) 19 | { 20 | pdest[i] = psrc[i]; 21 | } 22 | } 23 | else if (src < dest) 24 | { 25 | for (i = n; i > 0; i--) 26 | { 27 | pdest[i - 1] = psrc[i - 1]; 28 | } 29 | } 30 | } 31 | 32 | int vec_expand_(char **data, int *length, int *capacity, int memsz) 33 | { 34 | if (*length + 1 > *capacity) 35 | { 36 | void *ptr; 37 | int n = (*capacity == 0) ? 1 : *capacity << 1; 38 | ptr = realloc(*data, n * memsz); 39 | if (ptr == NULL) 40 | return -1; 41 | *data = ptr; 42 | *capacity = n; 43 | } 44 | return 0; 45 | } 46 | 47 | int vec_reserve_(char **data, int *length, int *capacity, int memsz, int n) 48 | { 49 | (void)length; 50 | if (n > *capacity) 51 | { 52 | void *ptr = realloc(*data, n * memsz); 53 | if (ptr == NULL) 54 | return -1; 55 | *data = ptr; 56 | *capacity = n; 57 | } 58 | return 0; 59 | } 60 | 61 | int vec_reserve_po2_( 62 | char **data, int *length, int *capacity, int memsz, int n) 63 | { 64 | int n2 = 1; 65 | if (n == 0) 66 | return 0; 67 | while (n2 < n) 68 | n2 <<= 1; 69 | return vec_reserve_(data, length, capacity, memsz, n2); 70 | } 71 | 72 | int vec_compact_(char **data, int *length, int *capacity, int memsz) 73 | { 74 | if (*length == 0) 75 | { 76 | free(*data); 77 | *data = NULL; 78 | *capacity = 0; 79 | return 0; 80 | } 81 | else 82 | { 83 | void *ptr; 84 | int n = *length; 85 | ptr = realloc(*data, n * memsz); 86 | if (ptr == NULL) 87 | return -1; 88 | *capacity = n; 89 | *data = ptr; 90 | } 91 | return 0; 92 | } 93 | 94 | int vec_insert_(char **data, int *length, int *capacity, int memsz, 95 | int idx) 96 | { 97 | int err = vec_expand_(data, length, capacity, memsz); 98 | if (err) 99 | return err; 100 | memmove(*data + (idx + 1) * memsz, 101 | *data + idx * memsz, 102 | (*length - idx) * memsz); 103 | return 0; 104 | } 105 | 106 | void vec_splice_(char **data, int *length, int *capacity, int memsz, 107 | int start, int count) 108 | { 109 | (void)capacity; 110 | memmove(*data + start * memsz, 111 | *data + (start + count) * memsz, 112 | (*length - start - count) * memsz); 113 | } 114 | 115 | void vec_swapsplice_(char **data, int *length, int *capacity, int memsz, 116 | int start, int count) 117 | { 118 | (void)capacity; 119 | memmove(*data + start * memsz, 120 | *data + (*length - count) * memsz, 121 | count * memsz); 122 | } 123 | 124 | void vec_swap_(char **data, int *length, int *capacity, int memsz, 125 | int idx1, int idx2) 126 | { 127 | unsigned char *a, *b, tmp; 128 | int count; 129 | (void)length; 130 | (void)capacity; 131 | if (idx1 == idx2) 132 | return; 133 | a = (unsigned char *)*data + idx1 * memsz; 134 | b = (unsigned char *)*data + idx2 * memsz; 135 | count = memsz; 136 | while (count--) 137 | { 138 | tmp = *a; 139 | *a = *b; 140 | *b = tmp; 141 | a++, b++; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/lib/vec.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 rxi 3 | * 4 | * This library is free software; you can redistribute it and/or modify it 5 | * under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #ifndef VEC_H 9 | #define VEC_H 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #define VEC_VERSION "0.2.1" 16 | 17 | #define vec_unpack_(v) \ 18 | (char **)&(v)->data, &(v)->length, &(v)->capacity, sizeof(*(v)->data) 19 | 20 | #define vec_t(T) \ 21 | struct \ 22 | { \ 23 | T *data; \ 24 | int length, capacity; \ 25 | } 26 | 27 | #define vec_init(v) \ 28 | memset((v), 0, sizeof(*(v))) 29 | 30 | #define vec_deinit(v) \ 31 | (free((v)->data), \ 32 | vec_init(v)) 33 | 34 | #define vec_push(v, val) \ 35 | (vec_expand_(vec_unpack_(v)) ? -1 : ((v)->data[(v)->length++] = (val), 0)) 36 | 37 | #define vec_pop(v) \ 38 | (v)->data[--(v)->length] 39 | 40 | #define vec_splice(v, start, count) \ 41 | (vec_splice_(vec_unpack_(v), start, count), \ 42 | (v)->length -= (count)) 43 | 44 | #define vec_swapsplice(v, start, count) \ 45 | (vec_swapsplice_(vec_unpack_(v), start, count), \ 46 | (v)->length -= (count)) 47 | 48 | #define vec_insert(v, idx, val) \ 49 | (vec_insert_(vec_unpack_(v), idx) ? -1 : ((v)->data[idx] = (val), 0), (v)->length++, 0) 50 | 51 | #define vec_sort(v, fn) \ 52 | qsort((v)->data, (v)->length, sizeof(*(v)->data), fn) 53 | 54 | #define vec_swap(v, idx1, idx2) \ 55 | vec_swap_(vec_unpack_(v), idx1, idx2) 56 | 57 | #define vec_truncate(v, len) \ 58 | ((v)->length = (len) < (v)->length ? (len) : (v)->length) 59 | 60 | #define vec_clear(v) \ 61 | ((v)->length = 0) 62 | 63 | #define vec_first(v) \ 64 | (v)->data[0] 65 | 66 | #define vec_last(v) \ 67 | (v)->data[(v)->length - 1] 68 | 69 | #define vec_reserve(v, n) \ 70 | vec_reserve_(vec_unpack_(v), n) 71 | 72 | #define vec_compact(v) \ 73 | vec_compact_(vec_unpack_(v)) 74 | 75 | #define vec_pusharr(v, arr, count) \ 76 | do \ 77 | { \ 78 | int i__, n__ = (count); \ 79 | if (vec_reserve_po2_(vec_unpack_(v), (v)->length + n__) != 0) \ 80 | break; \ 81 | for (i__ = 0; i__ < n__; i__++) \ 82 | { \ 83 | (v)->data[(v)->length++] = (arr)[i__]; \ 84 | } \ 85 | } while (0) 86 | 87 | #define vec_extend(v, v2) \ 88 | vec_pusharr((v), (v2)->data, (v2)->length) 89 | 90 | #define vec_find(v, val, idx) \ 91 | do \ 92 | { \ 93 | for ((idx) = 0; (idx) < (v)->length; (idx)++) \ 94 | { \ 95 | if ((v)->data[(idx)] == (val)) \ 96 | break; \ 97 | } \ 98 | if ((idx) == (v)->length) \ 99 | (idx) = -1; \ 100 | } while (0) 101 | 102 | #define vec_remove(v, val) \ 103 | do \ 104 | { \ 105 | int idx__; \ 106 | vec_find(v, val, idx__); \ 107 | if (idx__ != -1) \ 108 | vec_splice(v, idx__, 1); \ 109 | } while (0) 110 | 111 | #define vec_reverse(v) \ 112 | do \ 113 | { \ 114 | int i__ = (v)->length / 2; \ 115 | while (i__--) \ 116 | { \ 117 | vec_swap((v), i__, (v)->length - (i__ + 1)); \ 118 | } \ 119 | } while (0) 120 | 121 | #define vec_foreach(v, var, iter) \ 122 | if ((v)->length > 0) \ 123 | for ((iter) = 0; \ 124 | (iter) < (v)->length && (((var) = (v)->data[(iter)]), 1); \ 125 | ++(iter)) 126 | 127 | #define vec_foreach_rev(v, var, iter) \ 128 | if ((v)->length > 0) \ 129 | for ((iter) = (v)->length - 1; \ 130 | (iter) >= 0 && (((var) = (v)->data[(iter)]), 1); \ 131 | --(iter)) 132 | 133 | #define vec_foreach_ptr(v, var, iter) \ 134 | if ((v)->length > 0) \ 135 | for ((iter) = 0; \ 136 | (iter) < (v)->length && (((var) = &(v)->data[(iter)]), 1); \ 137 | ++(iter)) 138 | 139 | #define vec_foreach_ptr_rev(v, var, iter) \ 140 | if ((v)->length > 0) \ 141 | for ((iter) = (v)->length - 1; \ 142 | (iter) >= 0 && (((var) = &(v)->data[(iter)]), 1); \ 143 | --(iter)) 144 | 145 | int vec_expand_(char **data, int *length, int *capacity, int memsz); 146 | int vec_reserve_(char **data, int *length, int *capacity, int memsz, int n); 147 | int vec_reserve_po2_(char **data, int *length, int *capacity, int memsz, 148 | int n); 149 | int vec_compact_(char **data, int *length, int *capacity, int memsz); 150 | int vec_insert_(char **data, int *length, int *capacity, int memsz, 151 | int idx); 152 | void vec_splice_(char **data, int *length, int *capacity, int memsz, 153 | int start, int count); 154 | void vec_swapsplice_(char **data, int *length, int *capacity, int memsz, 155 | int start, int count); 156 | void vec_swap_(char **data, int *length, int *capacity, int memsz, 157 | int idx1, int idx2); 158 | 159 | typedef vec_t(void *) vec_void_t; 160 | typedef vec_t(char *) vec_str_t; 161 | typedef vec_t(int) vec_int_t; 162 | typedef vec_t(char) vec_char_t; 163 | typedef vec_t(float) vec_float_t; 164 | typedef vec_t(double) vec_double_t; 165 | 166 | #endif -------------------------------------------------------------------------------- /src/link.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | . = 0xffffffff80200000; /* 2 MB in the higher half */ 6 | .stivale2hdr : 7 | { 8 | KEEP(*(.stivale2hdr)) 9 | } 10 | 11 | .text : 12 | { 13 | KEEP(*(.text*)) 14 | } 15 | 16 | .rodata : 17 | { 18 | KEEP(*(.rodata*)) 19 | } 20 | 21 | .data : 22 | { 23 | KEEP(*(.data*)) 24 | } 25 | 26 | .bss : 27 | { 28 | KEEP(*(COMMON)) 29 | KEEP(*(.bss*)) 30 | } 31 | .text : { *(.text) } 32 | .data : { *(.data) } 33 | .bss : { *(.bss) } 34 | end = .; 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/root/boot/limine.cfg: -------------------------------------------------------------------------------- 1 | TIMEOUT=5 2 | GRAPHICS=yes 3 | :bestOS 4 | PROTOCOL=stivale2 5 | KERNEL_PATH=boot:///kernel.elf 6 | KERNEL_CMDLINE=nolog 7 | 8 | MODULE_STRING=root 9 | MODULE_PATH=boot:///root.tar 10 | --------------------------------------------------------------------------------