├── .gitignore ├── LICENSE ├── README.md ├── boot └── limine.cfg ├── build-support └── cross_file.txt ├── host-recipes ├── autoconf ├── automake ├── binutils ├── gcc ├── gnulib ├── libgcc-binaries ├── libtool └── pkg-config ├── init ├── init.c └── makefile ├── jinx-config ├── makefile ├── patches ├── automake │ └── jinx-working-patch.patch ├── binutils │ └── jinx-working-patch.patch ├── gcc-host │ └── jinx-working-patch.patch ├── libtool │ └── jinx-working-patch.patch └── mlibc │ └── jinx-working-patch.patch ├── recipes ├── core-libs ├── cxxshim ├── frigg ├── init ├── libgcc ├── libiconv ├── libintl ├── libstdc++ ├── libxcrypt ├── linux-headers ├── mlibc └── mlibc-headers ├── source-recipes ├── autoconf ├── automake ├── binutils ├── cxxshim ├── frigg ├── gcc ├── gcc-host ├── gnulib ├── init ├── libgcc-binaries ├── libiconv ├── libintl ├── libtool ├── libxcrypt ├── linux ├── mlibc └── pkg-config └── src ├── acpi ├── acpi.c ├── acpi.h └── tables │ ├── madt.c │ └── madt.h ├── dev ├── apic │ ├── ioapic.c │ ├── ioapic.h │ ├── lapic.c │ └── lapic.h ├── console.c ├── console.h ├── fb.c ├── fb.h ├── pit.c ├── pit.h ├── ps2 │ ├── ps2.c │ ├── ps2.h │ ├── ps2kb.c │ └── ps2kb.h ├── serial.c └── serial.h ├── fs ├── ext2fs.c ├── ext2fs.h ├── initramfs.c ├── initramfs.h ├── tmpfs.c ├── tmpfs.h ├── vfs.c └── vfs.h ├── get-deps.sh ├── kernel.c ├── lib ├── assert.h ├── elf.c ├── elf.h ├── errno.h ├── hashmap.c ├── hashmap.h ├── io.h ├── lock.c ├── lock.h ├── stat.h ├── stddef.h ├── stdio.c ├── stdio.h ├── str.c ├── str.h ├── vector.c └── vector.h ├── linker.ld ├── makefile ├── memory ├── gdt │ ├── gdt.c │ ├── gdt.h │ └── loadgdt.asm ├── kheap.c ├── kheap.h ├── pmm.c ├── pmm.h ├── vmm.c └── vmm.h ├── proc ├── sched.c └── sched.h └── sys ├── cpu.h ├── idt ├── idt.c ├── idt.h └── isr.asm ├── smp.c ├── smp.h └── syscalls ├── syscall_handler.asm └── syscalls.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.iso 2 | *.elf 3 | *.o 4 | *.d 5 | /.git 6 | .gdbinit 7 | gdb.txt 8 | /.jinx-cache 9 | jinx 10 | /limine 11 | /src/flanterm 12 | /src/limine.h 13 | /src/mlibc-headers 14 | initramfs.tar 15 | /init/build 16 | /iso_root 17 | /builds 18 | /host-builds 19 | /host-pkgs 20 | /pkgs 21 | /sources 22 | /sysroot 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 catmaster 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # **flan-os** 2 | This is a hobby os on pause due to school. 3 | 4 | This supports the limine boot protocal and uses limine v5.x 5 | 6 | This can be compiled using a cross compiler x86_64-elf-gcc and nasm. Any VM of your choice should work. 7 | 8 | --- 9 | # **TODO** 10 | - [X] GDT 11 | - [x] PMM 12 | - [x] VMM 13 | - [x] KHEAP 14 | - [x] IDT 15 | - [x] Parse ACPI tables 16 | - [x] MADT 17 | - [x] Start up other CPUs 18 | - [x] Set up APIC 19 | - [x] Configure the PIT 20 | - [x] Calibrate the APIC timer 21 | - [x] Implement scheduler 22 | - [x] Implement VFS 23 | - [x] Elf loader 24 | - [ ] Syscalls 25 | - [ ] EXT2 26 | --- 27 | # Dependencies 28 | - `x86_64-elf-gcc` 29 | - `nasm` 30 | - `git` 31 | - `xorriso` 32 | - `make` 33 | 34 | To build the iso, just run `make`. 35 | -------------------------------------------------------------------------------- /boot/limine.cfg: -------------------------------------------------------------------------------- 1 | TIMEOUT=0 2 | TERM_WALLPAPER=boot:///background.bmp 3 | :flan-os 4 | PROTOCOL=limine 5 | KERNEL_PATH=boot:///kernel.elf 6 | MODULE_PATH=boot:///initramfs.tar 7 | -------------------------------------------------------------------------------- /build-support/cross_file.txt: -------------------------------------------------------------------------------- 1 | [binaries] 2 | c = 'x86_64-flan-gcc' 3 | cpp = 'x86_64-flan-g++' 4 | ar = 'x86_64-flan-ar' 5 | strip = 'x86_64-flan-strip' 6 | pkgconfig = 'x86_64-flan-pkg-config' 7 | # sed adds binaries here. 8 | 9 | [host_machine] 10 | system = 'flan' 11 | cpu_family = 'x86_64' 12 | cpu = 'x86_64' 13 | endian = 'little' 14 | -------------------------------------------------------------------------------- /host-recipes/autoconf: -------------------------------------------------------------------------------- 1 | name=autoconf 2 | from_source=autoconf 3 | revision=1 4 | 5 | configure() { 6 | "${source_dir}"/configure --prefix="${prefix}" 7 | } 8 | 9 | build() { 10 | make -j${parallelism} 11 | } 12 | 13 | install() { 14 | DESTDIR="${dest_dir}" make install 15 | } 16 | -------------------------------------------------------------------------------- /host-recipes/automake: -------------------------------------------------------------------------------- 1 | name=automake 2 | from_source=automake 3 | revision=1 4 | imagedeps="gcc" 5 | hostrundeps="autoconf" 6 | 7 | configure() { 8 | "${source_dir}"/configure --prefix="${prefix}" 9 | } 10 | 11 | build() { 12 | make -j${parallelism} 13 | } 14 | 15 | install() { 16 | DESTDIR="${dest_dir}" make install-strip 17 | } 18 | -------------------------------------------------------------------------------- /host-recipes/binutils: -------------------------------------------------------------------------------- 1 | name=binutils 2 | from_source=binutils 3 | revision=1 4 | imagedeps="gcc" 5 | hostdeps="autoconf automake libtool pkg-config" 6 | 7 | configure() { 8 | "${source_dir}"/configure \ 9 | --prefix="${prefix}" \ 10 | --target=x86_64-flan \ 11 | --with-sysroot="${sysroot_dir}" \ 12 | --disable-nls \ 13 | --disable-werror \ 14 | --disable-dependency-tracking 15 | } 16 | 17 | build() { 18 | make -j${parallelism} all 19 | } 20 | 21 | install() { 22 | DESTDIR="${dest_dir}" make install-strip 23 | } 24 | -------------------------------------------------------------------------------- /host-recipes/gcc: -------------------------------------------------------------------------------- 1 | name=gcc 2 | from_source=gcc-host 3 | revision=1 4 | imagedeps="gcc" 5 | hostdeps="autoconf automake libtool pkg-config" 6 | hostrundeps="binutils" 7 | deps="mlibc-headers" 8 | 9 | configure() { 10 | cp -rp "${source_dir}"/. ./ 11 | 12 | mkdir build && cd build 13 | 14 | CXXFLAGS_FOR_TARGET="$CFLAGS" \ 15 | CFLAGS_FOR_TARGET="$CFLAGS" \ 16 | ../configure \ 17 | --prefix="${prefix}" \ 18 | --target=x86_64-flan \ 19 | --with-sysroot="${sysroot_dir}" \ 20 | --disable-nls \ 21 | --enable-languages=c,c++,lto \ 22 | --disable-multilib \ 23 | --enable-initfini-array \ 24 | --enable-shared \ 25 | --enable-host-shared 26 | } 27 | 28 | build() { 29 | cd build 30 | make -j${parallelism} all-gcc 31 | } 32 | 33 | install() { 34 | cd build 35 | DESTDIR="${dest_dir}" make install-gcc 36 | } 37 | -------------------------------------------------------------------------------- /host-recipes/gnulib: -------------------------------------------------------------------------------- 1 | name=gnulib 2 | from_source=gnulib 3 | revision=1 4 | 5 | configure() { 6 | true 7 | } 8 | 9 | build() { 10 | true 11 | } 12 | 13 | install() { 14 | true 15 | } 16 | -------------------------------------------------------------------------------- /host-recipes/libgcc-binaries: -------------------------------------------------------------------------------- 1 | name=libgcc-binaries 2 | from_source=libgcc-binaries 3 | revision=1 4 | 5 | configure() { 6 | true 7 | } 8 | 9 | build() { 10 | true 11 | } 12 | 13 | install() { 14 | mkdir -p ${dest_dir}${prefix}/libgcc-binaries 15 | cp -rv ${source_dir}/. ${dest_dir}${prefix}/libgcc-binaries/ 16 | } 17 | -------------------------------------------------------------------------------- /host-recipes/libtool: -------------------------------------------------------------------------------- 1 | name=libtool 2 | from_source=libtool 3 | revision=1 4 | hostdeps="autoconf automake" 5 | imagedeps="help2man gcc" 6 | 7 | configure() { 8 | cp -rp "${source_dir}"/. ./ 9 | ./configure \ 10 | --prefix="${prefix}" 11 | } 12 | 13 | build() { 14 | make -j${parallelism} 15 | } 16 | 17 | install() { 18 | DESTDIR="${dest_dir}" make install-strip 19 | } 20 | -------------------------------------------------------------------------------- /host-recipes/pkg-config: -------------------------------------------------------------------------------- 1 | name=pkg-config 2 | from_source=pkg-config 3 | revision=1 4 | imagedeps="gcc" 5 | hostdeps="automake autoconf libtool" 6 | 7 | configure() { 8 | "${source_dir}"/configure \ 9 | --prefix="${prefix}" 10 | } 11 | 12 | build() { 13 | make -j${parallelism} 14 | } 15 | 16 | install() { 17 | DESTDIR="${dest_dir}" make install-strip 18 | mkdir -p "${dest_dir}${prefix}/share/pkgconfig/personality.d" 19 | cat <"${dest_dir}${prefix}/share/pkgconfig/personality.d/x86_64-flan.personality" 20 | Triplet: x86_64-flan 21 | SysrootDir: ${sysroot_dir} 22 | DefaultSearchPaths: ${sysroot_dir}/usr/lib/pkgconfig:${sysroot_dir}/usr/share/pkgconfig 23 | SystemIncludePaths: ${sysroot_dir}/usr/include 24 | SystemLibraryPaths: ${sysroot_dir}/usr/lib 25 | EOF 26 | ln -s pkgconf "${dest_dir}${prefix}/bin/x86_64-flan-pkg-config" 27 | } 28 | -------------------------------------------------------------------------------- /init/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(){ 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /init/makefile: -------------------------------------------------------------------------------- 1 | CFLAGS ?= -g -O2 -pipe -Wall -Wextra 2 | 3 | override CFLAGS += -std=gnu11 4 | 5 | all: init 6 | 7 | init: init.c 8 | $(CC) $(CFLAGS) $< -o $@ 9 | 10 | .PHONY: install 11 | install: all 12 | install -d $(DESTDIR)$(PREFIX)/bin 13 | install init $(DESTDIR)$(PREFIX)/bin/init 14 | -------------------------------------------------------------------------------- /jinx-config: -------------------------------------------------------------------------------- 1 | export CFLAGS="-O2 -pipe -march=x86-64 -mtune=generic" 2 | export CXXFLAGS="${CFLAGS}" 3 | 4 | autotools_recursive_regen() { 5 | for f in $(find . -name configure.ac); do 6 | echo "* autotools regen in '$(dirname $f)'..." 7 | ( cd "$(dirname "$f")" && libtoolize -cfvi && autoreconf -fvi "$@" ) 8 | done 9 | } 10 | 11 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | override IMAGENAME := flan 2 | 3 | QEMUFLAGS ?= -no-reboot -no-shutdown -m 4G -smp cores=4 -serial stdio -M q35 4 | BUILDDIR :=$(PWD)/kernel-build/ 5 | 6 | 7 | .PHONY: all 8 | all: $(IMAGENAME).iso 9 | 10 | limine: 11 | git clone https://github.com/limine-bootloader/limine.git --branch=v5.x-branch-binary --depth=1 12 | make -C limine 13 | 14 | jinx: 15 | curl -o jinx https://raw.githubusercontent.com/mintsuki/jinx/trunk/jinx 16 | chmod +x jinx 17 | 18 | export BUILDDIR 19 | .PHONY: kernel 20 | kernel: 21 | cd src && ./get-deps.sh 22 | $(MAKE) -C src 23 | 24 | initramfs.tar: jinx 25 | ./jinx build-all 26 | ./jinx sysroot 27 | cd sysroot && tar cvf ../initramfs.tar * 28 | 29 | 30 | $(IMAGENAME).iso: limine kernel initramfs.tar jinx 31 | mkdir -p iso_root/ 32 | cp $(BUILDDIR)/kernel.elf \ 33 | boot/limine.cfg limine/limine-bios.sys limine/limine-bios-cd.bin limine/limine-uefi-cd.bin initramfs.tar iso_root/ 34 | xorriso -as mkisofs -b limine-bios-cd.bin \ 35 | -no-emul-boot -boot-load-size 4 -boot-info-table \ 36 | --efi-boot limine-uefi-cd.bin \ 37 | -efi-boot-part --efi-boot-image --protective-msdos-label \ 38 | iso_root -o $(IMAGENAME).iso 39 | limine/limine bios-install $(IMAGENAME).iso 40 | 41 | 42 | .PHONY: clean 43 | clean: 44 | rm -rf iso_root $(IMAGENAME).iso initramfs.tar sysroot 45 | $(MAKE) -C src clean 46 | 47 | .PHONY: run 48 | run: $(IMAGENAME).iso 49 | qemu-system-x86_64 $(QEMUFLAGS) $(IMAGENAME).iso 50 | 51 | .PHONY: kvm 52 | kvm: $(IMAGENAME).iso 53 | qemu-system-x86_64 $(QEMUFLAGS) -cpu host --enable-kvm $(IMAGENAME).iso 54 | 55 | .PHONY: gdb 56 | gdb: $(IMAGENAME).iso 57 | qemu-system-x86_64 $(QEMUFLAGS) -s -S $(IMAGENAME).iso 58 | 59 | 60 | -------------------------------------------------------------------------------- /patches/automake/jinx-working-patch.patch: -------------------------------------------------------------------------------- 1 | diff --git automake-clean/lib/config.guess automake-workdir/lib/config.guess 2 | index e81d3ae..08139ca 100755 3 | --- automake-clean/lib/config.guess 4 | +++ automake-workdir/lib/config.guess 5 | @@ -929,6 +929,9 @@ EOF 6 | i*:PW*:*) 7 | GUESS=$UNAME_MACHINE-pc-pw32 8 | ;; 9 | + *:flan:*:*) 10 | + GUESS=$UNAME_MACHINE-pc-flan 11 | + ;; 12 | *:Interix*:*) 13 | case $UNAME_MACHINE in 14 | x86) 15 | diff --git automake-clean/lib/config.sub automake-workdir/lib/config.sub 16 | index d74fb6d..64292fe 100755 17 | --- automake-clean/lib/config.sub 18 | +++ automake-workdir/lib/config.sub 19 | @@ -1723,7 +1723,7 @@ case $os in 20 | | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ 21 | | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \ 22 | | hiux* | abug | nacl* | netware* | windows* \ 23 | - | os9* | macos* | osx* | ios* \ 24 | + | os9* | macos* | osx* | ios* | flan* \ 25 | | mpw* | magic* | mmixware* | mon960* | lnews* \ 26 | | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ 27 | | aos* | aros* | cloudabi* | sortix* | twizzler* \ 28 | -------------------------------------------------------------------------------- /patches/binutils/jinx-working-patch.patch: -------------------------------------------------------------------------------- 1 | diff --git binutils-clean/bfd/Makefile.am binutils-workdir/bfd/Makefile.am 2 | index e1692e7..aa8540f 100644 3 | --- binutils-clean/bfd/Makefile.am 4 | +++ binutils-workdir/bfd/Makefile.am 5 | @@ -782,7 +782,7 @@ ofiles: stamp-ofiles ; @true 6 | libbfd_la_SOURCES = $(BFD32_LIBS_CFILES) 7 | EXTRA_libbfd_la_SOURCES = $(CFILES) 8 | libbfd_la_DEPENDENCIES = $(OFILES) ofiles ../libsframe/libsframe.la 9 | -libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS) ../libsframe/libsframe.la 10 | +libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS) $(SFRAME_LIB_PATH) ../libsframe/libsframe.la 11 | libbfd_la_LDFLAGS += -release `cat libtool-soversion` @SHARED_LDFLAGS@ 12 | 13 | # libtool will build .libs/libbfd.a. We create libbfd.a in the build 14 | diff --git binutils-clean/bfd/config.bfd binutils-workdir/bfd/config.bfd 15 | index 1b0111f..bf2d882 100644 16 | --- binutils-clean/bfd/config.bfd 17 | +++ binutils-workdir/bfd/config.bfd 18 | @@ -666,6 +666,11 @@ case "${targ}" in 19 | targ_selvecs= 20 | targ64_selvecs=x86_64_elf64_vec 21 | ;; 22 | + i[3-7]86-*-flan*) 23 | + targ_defvec=i386_elf32_vec 24 | + targ_selvecs= 25 | + targ64_selvecs=x86_64_elf64_vec 26 | + ;; 27 | #ifdef BFD64 28 | x86_64-*-cloudabi*) 29 | targ_defvec=x86_64_elf64_cloudabi_vec 30 | @@ -736,6 +741,11 @@ case "${targ}" in 31 | targ_selvecs="i386_elf32_vec iamcu_elf32_vec x86_64_elf32_vec" 32 | want64=true 33 | ;; 34 | + x86_64-*-flan*) 35 | + targ_defvec=x86_64_elf64_vec 36 | + targ_selvecs=i386_elf32_vec 37 | + want64=true 38 | + ;; 39 | #endif 40 | i[3-7]86-*-lynxos*) 41 | targ_defvec=i386_elf32_vec 42 | diff --git binutils-clean/gas/configure.tgt binutils-workdir/gas/configure.tgt 43 | index 765ba73..f3f0515 100644 44 | --- binutils-clean/gas/configure.tgt 45 | +++ binutils-workdir/gas/configure.tgt 46 | @@ -226,6 +226,7 @@ case ${generic_target} in 47 | i386-*-beos*) fmt=elf ;; 48 | i386-*-elfiamcu) fmt=elf arch=iamcu ;; 49 | i386-*-elf*) fmt=elf ;; 50 | + i386-*-flan*) fmt=elf em=gnu ;; 51 | i386-*-fuchsia*) fmt=elf ;; 52 | i386-*-haiku*) fmt=elf em=haiku ;; 53 | i386-*-genode*) fmt=elf ;; 54 | diff --git binutils-clean/gprofng/libcollector/configure.ac binutils-workdir/gprofng/libcollector/configure.ac 55 | index 495963c..7bc2682 100644 56 | --- binutils-clean/gprofng/libcollector/configure.ac 57 | +++ binutils-workdir/gprofng/libcollector/configure.ac 58 | @@ -18,7 +18,7 @@ dnl . 59 | 60 | m4_include([../../bfd/version.m4]) 61 | AC_INIT([gprofng], BFD_VERSION) 62 | -AC_CONFIG_MACRO_DIRS([../../config ../..]) 63 | +#AC_CONFIG_MACRO_DIRS([../../config ../..]) 64 | AC_CONFIG_AUX_DIR(../..) 65 | AC_CANONICAL_TARGET 66 | AM_INIT_AUTOMAKE 67 | diff --git binutils-clean/ld/configure.tgt binutils-workdir/ld/configure.tgt 68 | index de04a44..5b410a2 100644 69 | --- binutils-clean/ld/configure.tgt 70 | +++ binutils-workdir/ld/configure.tgt 71 | @@ -374,6 +374,9 @@ i[3-7]86-*-linux-*) targ_emul=elf_i386 72 | i[3-7]86-*-redox*) targ_emul=elf_i386 73 | targ_extra_emuls=elf_x86_64 74 | ;; 75 | +i[3-7]86-*-flan*) targ_emul=elf_i386 76 | + targ_extra_emuls=elf_x86_64 77 | + ;; 78 | i[3-7]86-*-sysv[45]*) targ_emul=elf_i386 79 | targ_extra_emuls=elf_iamcu 80 | ;; 81 | @@ -1012,6 +1015,9 @@ x86_64-*-linux-*) targ_emul=elf_x86_64 82 | x86_64-*-redox*) targ_emul=elf_x86_64 83 | targ_extra_emuls=elf_i386 84 | ;; 85 | +x86_64-*-flan*) targ_emul=elf_x86_64 86 | + targ_extra_emuls=elf_i386 87 | + ;; 88 | x86_64-*-solaris2*) targ_emul=elf_x86_64_sol2 89 | targ_extra_emuls="elf_x86_64 elf_i386_sol2 elf_i386_ldso elf_i386 elf_iamcu" 90 | targ_extra_libpath=$targ_extra_emuls 91 | diff --git binutils-clean/libiberty/configure.ac binutils-workdir/libiberty/configure.ac 92 | index 6c1ff9c..78cdadc 100644 93 | --- binutils-clean/libiberty/configure.ac 94 | +++ binutils-workdir/libiberty/configure.ac 95 | @@ -37,7 +37,7 @@ else 96 | libiberty_topdir="${srcdir}/.." 97 | fi 98 | AC_SUBST(libiberty_topdir) 99 | -AC_CONFIG_AUX_DIR($libiberty_topdir) 100 | +AC_CONFIG_AUX_DIR([.]) 101 | 102 | dnl Very limited version of automake's enable-maintainer-mode 103 | 104 | diff --git binutils-workdir/multilib.am binutils-workdir/multilib.am 105 | new file mode 100644 106 | index 0000000..5c98b69 107 | --- /dev/null 108 | +++ binutils-workdir/multilib.am 109 | @@ -0,0 +1,45 @@ 110 | +## automake - create Makefile.in from Makefile.am 111 | + 112 | +## Copyright (C) 1994-2017 Free Software Foundation, Inc. 113 | +## This Makefile.in is free software; the Free Software Foundation 114 | +## gives unlimited permission to copy and/or distribute it, 115 | +## with or without modifications, as long as this notice is preserved. 116 | + 117 | +## This program is distributed in the hope that it will be useful, 118 | +## but WITHOUT ANY WARRANTY; without even the implied warranty of 119 | +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 120 | +## GNU General Public License for more details. 121 | + 122 | +MULTISRCTOP = 123 | +MULTIBUILDTOP = 124 | +MULTIDIRS = 125 | +MULTISUBDIR = 126 | +MULTIDO = true 127 | +MULTICLEAN = true 128 | + 129 | +# GNU Make needs to see an explicit $(MAKE) variable in the command it 130 | +# runs to enable its job server during parallel builds. Hence the 131 | +# comments below. 132 | +all-multi: 133 | + $(MULTIDO) $(AM_MAKEFLAGS) DO=all multi-do # $(MAKE) 134 | +install-multi: 135 | + $(MULTIDO) $(AM_MAKEFLAGS) DO=install multi-do # $(MAKE) 136 | +mostlyclean-multi: 137 | + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=mostlyclean multi-clean # $(MAKE) 138 | +clean-multi: 139 | + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=clean multi-clean # $(MAKE) 140 | +distclean-multi: 141 | + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=distclean multi-clean # $(MAKE) 142 | +maintainer-clean-multi: 143 | + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=maintainer-clean multi-clean # $(MAKE) 144 | + 145 | +.MAKE .PHONY: all-multi clean-multi distclean-multi install-am \ 146 | + install-multi maintainer-clean-multi mostlyclean-multi 147 | + 148 | +install-exec-local: install-multi 149 | + 150 | +all-local: all-multi 151 | +mostlyclean-local: mostlyclean-multi 152 | +clean-local: clean-multi 153 | +distclean-local: distclean-multi 154 | +maintainer-clean-local: maintainer-clean-multi 155 | -------------------------------------------------------------------------------- /patches/gcc-host/jinx-working-patch.patch: -------------------------------------------------------------------------------- 1 | diff --git gcc-host-clean/fixincludes/mkfixinc.sh gcc-host-workdir/fixincludes/mkfixinc.sh 2 | index df90720..484f8bc 100755 3 | --- gcc-host-clean/fixincludes/mkfixinc.sh 4 | +++ gcc-host-workdir/fixincludes/mkfixinc.sh 5 | @@ -12,6 +12,7 @@ target=fixinc.sh 6 | # Check for special fix rules for particular targets 7 | case $machine in 8 | i?86-*-cygwin* | \ 9 | + x86_64-*-flan* | \ 10 | i?86-*-mingw32* | \ 11 | x86_64-*-mingw32* | \ 12 | powerpc-*-eabisim* | \ 13 | diff --git gcc-host-workdir/gcc/config/flan.h gcc-host-workdir/gcc/config/flan.h 14 | new file mode 100644 15 | index 0000000..ca776e9 16 | --- /dev/null 17 | +++ gcc-host-workdir/gcc/config/flan.h 18 | @@ -0,0 +1,29 @@ 19 | +#undef TARGET_FLAN 20 | +#define TARGET_FLAN 1 21 | + 22 | +#undef LIB_SPEC 23 | +#define LIB_SPEC "-lc" 24 | + 25 | +#undef STARTFILE_SPEC 26 | +#define STARTFILE_SPEC "%{!shared:crt0.o%s} crti.o%s %{shared:crtbeginS.o%s;:crtbegin.o%s}" 27 | + 28 | +#undef ENDFILE_SPEC 29 | +#define ENDFILE_SPEC "%{shared:crtendS.o%s;:crtend.o%s} crtn.o%s" 30 | + 31 | +#define GNU_USER_LINK_EMULATION32 "elf_i386" 32 | +#define GNU_USER_LINK_EMULATION64 "elf_x86_64" 33 | +#define GNU_USER_LINK_EMULATIONX32 "elf32_x86_64" 34 | + 35 | +#define GNU_USER_DYNAMIC_LINKER32 "/usr/lib/ld_i386.so" 36 | +#define GNU_USER_DYNAMIC_LINKER64 "/usr/lib/ld.so" 37 | +#define GNU_USER_DYNAMIC_LINKERX32 "/usr/lib/ld32.so" 38 | + 39 | +#undef TARGET_OS_CPP_BUILTINS 40 | +#define TARGET_OS_CPP_BUILTINS() \ 41 | + do { \ 42 | + builtin_define ("__flan__"); \ 43 | + builtin_define ("__unix__"); \ 44 | + builtin_assert ("system=flan"); \ 45 | + builtin_assert ("system=unix"); \ 46 | + builtin_assert ("system=posix"); \ 47 | + } while (0); 48 | diff --git gcc-host-clean/gcc/config.gcc gcc-host-workdir/gcc/config.gcc 49 | index 6fd1594..0e447e3 100644 50 | --- gcc-host-clean/gcc/config.gcc 51 | +++ gcc-host-workdir/gcc/config.gcc 52 | @@ -840,6 +840,15 @@ case ${target} in 53 | tmake_file="${tmake_file} t-freebsd" 54 | target_has_targetdm=yes 55 | ;; 56 | +*-*-flan*) 57 | + extra_options="$extra_options gnu-user.opt" 58 | + gas=yes 59 | + gnu_ld=yes 60 | + default_use_cxa_atexit=yes 61 | + use_gcc_stdint=wrap 62 | + tmake_file="${tmake_file} t-slibgcc" 63 | + thread_file='posix' 64 | + ;; 65 | *-*-fuchsia*) 66 | native_system_header_dir=/include 67 | ;; 68 | @@ -2214,6 +2223,9 @@ i[34567]86-*-mingw* | x86_64-*-mingw*) 69 | ;; 70 | esac 71 | ;; 72 | +x86_64-*-flan*) 73 | + tm_file="${tm_file} i386/unix.h i386/att.h elfos.h gnu-user.h glibc-stdint.h i386/x86-64.h i386/gnu-user-common.h i386/gnu-user64.h flan.h" 74 | + ;; 75 | x86_64-*-fuchsia*) 76 | tmake_file="${tmake_file} i386/t-x86_64-elf" 77 | tm_file="${tm_file} i386/unix.h i386/att.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h fuchsia.h" 78 | diff --git gcc-host-clean/libgcc/config.host gcc-host-workdir/libgcc/config.host 79 | index b9975de..1fe0834 100644 80 | --- gcc-host-clean/libgcc/config.host 81 | +++ gcc-host-workdir/libgcc/config.host 82 | @@ -263,6 +263,11 @@ case ${host} in 83 | tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip t-slibgcc t-slibgcc-fuchsia" 84 | extra_parts="crtbegin.o crtend.o" 85 | ;; 86 | +*-*-flan*) 87 | + extra_parts="$extra_parts crti.o crtbegin.o crtbeginS.o crtend.o crtendS.o crtn.o" 88 | + tmake_file="$tmake_file t-crtstuff-pic" 89 | + tmake_file="$tmake_file t-slibgcc t-slibgcc-gld t-slibgcc-elf-ver t-libgcc-pic" 90 | + ;; 91 | *-*-linux* | frv-*-*linux* | *-*-kfreebsd*-gnu | *-*-gnu* | *-*-kopensolaris*-gnu | *-*-uclinuxfdpiceabi) 92 | 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" 93 | extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o" 94 | @@ -697,6 +702,10 @@ x86_64-*-elf* | x86_64-*-rtems*) 95 | x86_64-*-fuchsia*) 96 | tmake_file="$tmake_file t-libgcc-pic" 97 | ;; 98 | +x86_64-*-flan*) 99 | + extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o" 100 | + tmake_file="$tmake_file i386/t-crtpc t-crtfm i386/t-crtstuff t-dfprules" 101 | + ;; 102 | i[34567]86-*-dragonfly*) 103 | tmake_file="${tmake_file} i386/t-dragonfly i386/t-crtstuff" 104 | md_unwind_header=i386/dragonfly-unwind.h 105 | diff --git gcc-host-clean/libgcc/configure.ac gcc-host-workdir/libgcc/configure.ac 106 | index 2fc9d5d..83d246e 100644 107 | --- gcc-host-clean/libgcc/configure.ac 108 | +++ gcc-host-workdir/libgcc/configure.ac 109 | @@ -46,7 +46,7 @@ else 110 | libgcc_topdir="${srcdir}/.." 111 | fi 112 | AC_SUBST(libgcc_topdir) 113 | -AC_CONFIG_AUX_DIR($libgcc_topdir) 114 | +AC_CONFIG_AUX_DIR([.]) 115 | AC_CONFIG_HEADER(auto-target.h:config.in) 116 | 117 | AC_ARG_ENABLE(shared, 118 | diff --git gcc-host-clean/libiberty/configure.ac gcc-host-workdir/libiberty/configure.ac 119 | index 28d996f..61ff752 100644 120 | --- gcc-host-clean/libiberty/configure.ac 121 | +++ gcc-host-workdir/libiberty/configure.ac 122 | @@ -37,7 +37,7 @@ else 123 | libiberty_topdir="${srcdir}/.." 124 | fi 125 | AC_SUBST(libiberty_topdir) 126 | -AC_CONFIG_AUX_DIR($libiberty_topdir) 127 | +AC_CONFIG_AUX_DIR([.]) 128 | 129 | dnl Very limited version of automake's enable-maintainer-mode 130 | 131 | diff --git gcc-host-clean/libstdc++-v3/crossconfig.m4 gcc-host-workdir/libstdc++-v3/crossconfig.m4 132 | index b3269cb..3303aaa 100644 133 | --- gcc-host-clean/libstdc++-v3/crossconfig.m4 134 | +++ gcc-host-workdir/libstdc++-v3/crossconfig.m4 135 | @@ -136,6 +136,18 @@ case "${host}" in 136 | AC_CHECK_FUNCS(uselocale) 137 | ;; 138 | 139 | + *-flan*) 140 | + GLIBCXX_CHECK_COMPILER_FEATURES 141 | + GLIBCXX_CHECK_LINKER_FEATURES 142 | + GLIBCXX_CHECK_MATH_SUPPORT 143 | + GLIBCXX_CHECK_STDLIB_SUPPORT 144 | + AC_DEFINE(_GLIBCXX_USE_DEV_RANDOM) 145 | + AC_DEFINE(_GLIBCXX_USE_RANDOM_TR1) 146 | + GCC_CHECK_TLS 147 | + AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc) 148 | + AC_CHECK_FUNCS(timespec_get) 149 | + ;; 150 | + 151 | *-fuchsia*) 152 | SECTION_FLAGS='-ffunction-sections -fdata-sections' 153 | AC_SUBST(SECTION_FLAGS) 154 | -------------------------------------------------------------------------------- /patches/libtool/jinx-working-patch.patch: -------------------------------------------------------------------------------- 1 | diff --git libtool-clean/build-aux/ltmain.in libtool-workdir/build-aux/ltmain.in 2 | index a5f21a1..c06d55c 100644 3 | --- libtool-clean/build-aux/ltmain.in 4 | +++ libtool-workdir/build-aux/ltmain.in 5 | @@ -6497,7 +6497,7 @@ func_mode_link () 6 | fi 7 | else 8 | # We cannot seem to hardcode it, guess we'll fake it. 9 | - add_dir=-L$libdir 10 | + add_dir=-L$lt_sysroot$libdir 11 | # Try looking first in the location we're being installed to. 12 | if test -n "$inst_prefix_dir"; then 13 | case $libdir in 14 | diff --git libtool-clean/libtoolize.in libtool-workdir/libtoolize.in 15 | index 0c40fed..763619b 100644 16 | --- libtool-clean/libtoolize.in 17 | +++ libtool-workdir/libtoolize.in 18 | @@ -1891,7 +1891,7 @@ func_require_seen_libtool () 19 | # Do not remove config.guess, config.sub or install-sh, we don't 20 | # install them without --install, and the project may not be using 21 | # Automake. Similarly, do not remove Gnulib files. 22 | - all_pkgaux_files="compile depcomp missing ltmain.sh" 23 | + all_pkgaux_files="" 24 | all_pkgmacro_files="libtool.m4 ltargz.m4 ltdl.m4 ltoptions.m4 ltsugar.m4 ltversion.in ltversion.m4 lt~obsolete.m4" 25 | all_pkgltdl_files="COPYING.LIB Makefile Makefile.in Makefile.inc Makefile.am README acinclude.m4 aclocal.m4 argz_.h argz.c config.h.in config-h.in configure configure.ac configure.in libltdl/lt__alloc.h libltdl/lt__argz.h libltdl/lt__dirent.h libltdl/lt__glibc.h libltdl/lt__private.h libltdl/lt__strl.h libltdl/lt_dlloader.h libltdl/lt_error.h libltdl/lt_system.h libltdl/slist.h loaders/dld_link.c loaders/dlopen.c loaders/dyld.c loaders/load_add_on.c loaders/loadlibrary.c loaders/preopen.c loaders/shl_load.c lt__alloc.c lt__argz.c lt__dirent.c lt__strl.c lt_dlloader.c lt_error.c ltdl.c ltdl.h ltdl.mk slist.c" 26 | 27 | diff --git libtool-clean/m4/libtool.m4 libtool-workdir/m4/libtool.m4 28 | index 79a2451..6101192 100644 29 | --- libtool-clean/m4/libtool.m4 30 | +++ libtool-workdir/m4/libtool.m4 31 | @@ -1696,7 +1696,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl 32 | lt_cv_sys_max_cmd_len=12288; # 12K is about right 33 | ;; 34 | 35 | - gnu*) 36 | + gnu* | flan*) 37 | # Under GNU Hurd, this test is not required because there is 38 | # no limit to the length of command line arguments. 39 | # Libtool will interpret -1 as no limit whatsoever 40 | @@ -2925,6 +2925,18 @@ netbsd*) 41 | hardcode_into_libs=yes 42 | ;; 43 | 44 | +flan*) 45 | + version_type=linux # correct to gnu/linux during the next big refactor 46 | + need_lib_prefix=no 47 | + need_version=no 48 | + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' 49 | + soname_spec='$libname$release$shared_ext$major' 50 | + dynamic_linker='mlibc ld.so' 51 | + shlibpath_var=LD_LIBRARY_PATH 52 | + shlibpath_overrides_runpath=no 53 | + hardcode_into_libs=yes 54 | + ;; 55 | + 56 | newsos6) 57 | version_type=linux # correct to gnu/linux during the next big refactor 58 | library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' 59 | @@ -3566,6 +3578,10 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) 60 | lt_cv_deplibs_check_method=pass_all 61 | ;; 62 | 63 | +flan*) 64 | + lt_cv_deplibs_check_method=pass_all 65 | + ;; 66 | + 67 | netbsd*) 68 | if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then 69 | lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' 70 | @@ -4446,6 +4462,8 @@ m4_if([$1], [CXX], [ 71 | ;; 72 | netbsd*) 73 | ;; 74 | + flan*) 75 | + ;; 76 | *qnx* | *nto*) 77 | # QNX uses GNU C++, but need to define -shared option too, otherwise 78 | # it will coredump. 79 | @@ -4794,6 +4812,12 @@ m4_if([$1], [CXX], [ 80 | _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' 81 | ;; 82 | 83 | + flan*) 84 | + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' 85 | + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' 86 | + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' 87 | + ;; 88 | + 89 | *nto* | *qnx*) 90 | # QNX uses GNU C++, but need to define -shared option too, otherwise 91 | # it will coredump. 92 | @@ -5273,6 +5297,11 @@ _LT_EOF 93 | fi 94 | ;; 95 | 96 | + flan*) 97 | + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' 98 | + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' 99 | + ;; 100 | + 101 | netbsd*) 102 | if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then 103 | _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' 104 | @@ -5815,6 +5844,9 @@ _LT_EOF 105 | esac 106 | ;; 107 | 108 | + flan*) 109 | + ;; 110 | + 111 | netbsd*) 112 | if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then 113 | _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out 114 | @@ -7115,6 +7147,10 @@ if test yes != "$_lt_caught_CXX_error"; then 115 | esac 116 | ;; 117 | 118 | + flan*) 119 | + _LT_TAGVAR(ld_shlibs, $1)=yes 120 | + ;; 121 | + 122 | netbsd*) 123 | if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then 124 | _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' 125 | diff --git libtool-clean/m4/ltdl.m4 libtool-workdir/m4/ltdl.m4 126 | index 772c150..106bebc 100644 127 | --- libtool-clean/m4/ltdl.m4 128 | +++ libtool-workdir/m4/ltdl.m4 129 | @@ -497,6 +497,9 @@ AC_CACHE_CHECK([whether deplibs are loaded by dlopen], 130 | # at 6.2 and later dlopen does load deplibs. 131 | lt_cv_sys_dlopen_deplibs=yes 132 | ;; 133 | + flan*) 134 | + lt_cv_sys_dlopen_deplibs=yes 135 | + ;; 136 | netbsd*) 137 | lt_cv_sys_dlopen_deplibs=yes 138 | ;; 139 | -------------------------------------------------------------------------------- /patches/mlibc/jinx-working-patch.patch: -------------------------------------------------------------------------------- 1 | diff --git mlibc-clean/meson.build mlibc-workdir/meson.build 2 | index 12a74ae..91af059 100644 3 | --- mlibc-clean/meson.build 4 | +++ mlibc-workdir/meson.build 5 | @@ -154,6 +154,11 @@ elif host_machine.system() == 'dripos' 6 | rtdl_include_dirs += include_directories('sysdeps/dripos/include') 7 | libc_include_dirs += include_directories('sysdeps/dripos/include') 8 | subdir('sysdeps/dripos') 9 | +elif host_machine.system() == 'flan' 10 | + disable_linux_option = true 11 | + rtdl_include_dirs += include_directories('sysdeps/flan/include') 12 | + libc_include_dirs += include_directories('sysdeps/flan/include') 13 | + subdir('sysdeps/flan') 14 | else 15 | error('No sysdeps defined for OS: ' + host_machine.system()) 16 | endif 17 | diff --git mlibc-workdir/sysdeps/flan/crt-src/crt0.S mlibc-workdir/sysdeps/flan/crt-src/crt0.S 18 | new file mode 100644 19 | index 0000000..9e81022 20 | --- /dev/null 21 | +++ mlibc-workdir/sysdeps/flan/crt-src/crt0.S 22 | @@ -0,0 +1,6 @@ 23 | +.section .text 24 | +.global _start 25 | +_start: 26 | + mov $main, %rdi 27 | + call __mlibc_entry 28 | +.section .note.GNU-stack,"",%progbits 29 | diff --git mlibc-workdir/sysdeps/flan/crt-src/crti.S mlibc-workdir/sysdeps/flan/crt-src/crti.S 30 | new file mode 100644 31 | index 0000000..f04679c 32 | --- /dev/null 33 | +++ mlibc-workdir/sysdeps/flan/crt-src/crti.S 34 | @@ -0,0 +1,10 @@ 35 | +.section .init 36 | +.global _init 37 | +_init: 38 | + push %rax 39 | + 40 | +.section .fini 41 | +.global _fini 42 | +_fini: 43 | + push %rax 44 | +.section .note.GNU-stack,"",%progbits 45 | diff --git mlibc-workdir/sysdeps/flan/crt-src/crtn.S mlibc-workdir/sysdeps/flan/crt-src/crtn.S 46 | new file mode 100644 47 | index 0000000..1b61d5a 48 | --- /dev/null 49 | +++ mlibc-workdir/sysdeps/flan/crt-src/crtn.S 50 | @@ -0,0 +1,8 @@ 51 | +.section .init 52 | + pop %rax 53 | + ret 54 | + 55 | +.section .fini 56 | + pop %rax 57 | + ret 58 | +.section .note.GNU-stack,"",%progbits 59 | diff --git mlibc-workdir/sysdeps/flan/generic/entry.cpp mlibc-workdir/sysdeps/flan/generic/entry.cpp 60 | new file mode 100644 61 | index 0000000..265ab56 62 | --- /dev/null 63 | +++ mlibc-workdir/sysdeps/flan/generic/entry.cpp 64 | @@ -0,0 +1,32 @@ 65 | +#include 66 | +#include 67 | +#include 68 | +#include 69 | + 70 | +// defined by the POSIX library 71 | +void __mlibc_initLocale(); 72 | + 73 | +extern "C" uintptr_t *__dlapi_entrystack(); 74 | + 75 | +extern char **environ; 76 | +static mlibc::exec_stack_data __mlibc_stack_data; 77 | + 78 | +struct LibraryGuard { 79 | + LibraryGuard(); 80 | +}; 81 | + 82 | +static LibraryGuard guard; 83 | + 84 | +LibraryGuard::LibraryGuard() { 85 | + __mlibc_initLocale(); 86 | + 87 | + // Parse the exec() stack. 88 | + mlibc::parse_exec_stack(__dlapi_entrystack(), &__mlibc_stack_data); 89 | + mlibc::set_startup_data(__mlibc_stack_data.argc, __mlibc_stack_data.argv, 90 | + __mlibc_stack_data.envp); 91 | +} 92 | + 93 | +extern "C" void __mlibc_entry(int (*main_fn)(int argc, char *argv[], char *env[])) { 94 | + auto result = main_fn(__mlibc_stack_data.argc, __mlibc_stack_data.argv, environ); 95 | + exit(result); 96 | +} 97 | diff --git mlibc-workdir/sysdeps/flan/generic/generic.cpp mlibc-workdir/sysdeps/flan/generic/generic.cpp 98 | new file mode 100644 99 | index 0000000..6c37a34 100 | --- /dev/null 101 | +++ mlibc-workdir/sysdeps/flan/generic/generic.cpp 102 | @@ -0,0 +1,176 @@ 103 | +#include 104 | +#include 105 | + 106 | +#include 107 | +#include 108 | +#include 109 | +#include 110 | +#include 111 | +#include 112 | +#include 113 | +#include 114 | +#include 115 | + 116 | +typedef struct { 117 | + uint64_t ret; 118 | + uint64_t errno; 119 | +} syscall_ret_t; 120 | + 121 | +#define NOT_IMPLEMENTED { __ensure(!"NOT IMPLEMENTED"); __builtin_unreachable(); } 122 | + 123 | +#define SYSCALL0(NUM) ({ \ 124 | + asm volatile ("syscall" \ 125 | + : "=a"(ret.ret), "=d"(ret.errno) \ 126 | + : "a"(NUM) \ 127 | + : "rcx", "r11", "memory"); \ 128 | +}) 129 | + 130 | +#define SYSCALL1(NUM, ARG0) ({ \ 131 | + asm volatile ("syscall" \ 132 | + : "=a"(ret.ret), "=d"(ret.errno) \ 133 | + : "a"(NUM), "D"(ARG0) \ 134 | + : "rcx", "r11", "memory"); \ 135 | +}) 136 | + 137 | +#define SYSCALL2(NUM, ARG0, ARG1) ({ \ 138 | + asm volatile ("syscall" \ 139 | + : "=a"(ret.ret), "=d"(ret.errno) \ 140 | + : "a"(NUM), "D"(ARG0), "S"(ARG1) \ 141 | + : "rcx", "r11", "memory"); \ 142 | +}) 143 | + 144 | +#define SYSCALL3(NUM, ARG0, ARG1, ARG2) ({ \ 145 | + asm volatile ("syscall" \ 146 | + : "=a"(ret.ret), "=d"(ret.errno) \ 147 | + : "a"(NUM), "D"(ARG0), "S"(ARG1), "d"(ARG2) \ 148 | + : "rcx", "r11", "memory"); \ 149 | +}) 150 | + 151 | +#define SYSCALL4(NUM, ARG0, ARG1, ARG2, ARG3) ({ \ 152 | + register uintptr_t arg3 asm("r10") = ARG3; \ 153 | + asm volatile ("syscall" \ 154 | + : "=a"(ret.ret), "=d"(ret.errno) \ 155 | + : "a"(NUM), "D"(ARG0), "S"(ARG1), "d"(ARG2), \ 156 | + "r"(arg3) \ 157 | + : "rcx", "r11", "memory"); \ 158 | +}) 159 | + 160 | +#define SYSCALL5(NUM, ARG0, ARG1, ARG2, ARG3, ARG4) ({ \ 161 | + register uintptr_t arg3 asm("r10") = ARG3; \ 162 | + register uintptr_t arg4 asm("r8") = ARG4; \ 163 | + asm volatile ("syscall" \ 164 | + : "=a"(ret.ret), "=d"(ret.errno) \ 165 | + : "a"(NUM), "D"(ARG0), "S"(ARG1), "d"(ARG2), \ 166 | + "r"(arg3), "r"(arg4) \ 167 | + : "rcx", "r11", "memory"); \ 168 | +}) 169 | + 170 | +#define SYSCALL6(NUM, ARG0, ARG1, ARG2, ARG3, ARG4, ARG5) ({ \ 171 | + register uintptr_t arg3 asm("r10") = ARG3; \ 172 | + register uintptr_t arg4 asm("r8") = ARG4; \ 173 | + register uintptr_t arg5 asm("r9") = ARG5; \ 174 | + asm volatile ("syscall" \ 175 | + : "=a"(ret.ret), "=d"(ret.errno) \ 176 | + : "a"(NUM), "D"(ARG0), "S"(ARG1), "d"(ARG2), \ 177 | + "r"(arg3), "r"(arg4), "r"(arg5) \ 178 | + : "rcx", "r11", "memory"); \ 179 | +}) 180 | + 181 | +#define SYSCALL_LOG 0 182 | +#define SYSCALL_MMAP 1 183 | +#define SYSCALL_OPENAT 2 184 | +#define SYSCALL_READ 3 185 | +#define SYSCALL_SEEK 4 186 | +#define SYSCALL_SET_FS_BASE 5 187 | +#define SYSCALL_EXIT_THREAD 6 188 | + 189 | +namespace mlibc { 190 | + 191 | +void sys_libc_log(const char *message) { 192 | + syscall_ret_t ret; 193 | + SYSCALL1(SYSCALL_LOG, message); 194 | +} 195 | + 196 | +//XXX 197 | +void sys_exit(int status) { 198 | + syscall_ret_t ret; 199 | + SYSCALL0(SYSCALL_EXIT_THREAD); 200 | +} 201 | +void sys_libc_panic() { 202 | + sys_libc_log("\nMLIBC PANIC\n"); 203 | + for(;;); 204 | +} 205 | + 206 | +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, 207 | + off_t offset, void **window) { 208 | + syscall_ret_t ret; 209 | + SYSCALL6(SYSCALL_MMAP, hint, size, prot, flags, fd, offset); 210 | + void* ret_val = (void *)ret.ret; 211 | + if (ret_val == MAP_FAILED) { 212 | + return ret.errno; 213 | + } 214 | + *window = ret_val; 215 | + return 0; 216 | +} 217 | + 218 | +int sys_anon_allocate(size_t size, void **pointer) { 219 | + int errno = sys_vm_map(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON, -1, 0, pointer); 220 | + return errno; 221 | +} 222 | + 223 | +int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd) { 224 | + syscall_ret_t ret; 225 | + SYSCALL4(SYSCALL_OPENAT, dirfd, path, flags, mode); 226 | + if (ret.ret == -1) 227 | + return ret.errno; 228 | + *fd = ret.ret; 229 | + return 0; 230 | +} 231 | + 232 | + 233 | +int sys_open(const char *path, int flags, mode_t mode, int *fd) { 234 | + return sys_openat(AT_FDCWD, path, flags, mode, fd); 235 | +} 236 | + 237 | +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { 238 | + syscall_ret_t ret; 239 | + SYSCALL3(SYSCALL_READ, fd, buf, count); 240 | + int ret_val = (int)ret.ret; 241 | + if (ret_val == -1) { 242 | + return ret.errno; 243 | + } 244 | + *bytes_read = ret_val; 245 | + return 0; 246 | +} 247 | + 248 | +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset){ 249 | + syscall_ret_t ret; 250 | + SYSCALL3(SYSCALL_SEEK, fd, offset, whence); 251 | + off_t ret_val = (off_t)ret.ret; 252 | + if (ret_val == -1) { 253 | + return ret.errno; 254 | + } 255 | + *new_offset = ret_val; 256 | + return 0; 257 | +} 258 | + 259 | +int sys_close(int fd) { 260 | + return 0; 261 | +} 262 | +int sys_tcb_set(void *pointer) { 263 | + syscall_ret_t ret; 264 | + SYSCALL1(SYSCALL_SET_FS_BASE, pointer); 265 | + return 0; 266 | +} 267 | +int sys_vm_unmap(void *pointer, size_t size) NOT_IMPLEMENTED 268 | + 269 | +int sys_isatty(int fd) NOT_IMPLEMENTED 270 | + 271 | + 272 | +int sys_anon_free(void *pointer, size_t size) NOT_IMPLEMENTED 273 | +int sys_write(int fd, void const *buf, size_t count, ssize_t *bytes_written)NOT_IMPLEMENTED 274 | +int sys_futex_wait(int *pointer, int expected, timespec const *time)NOT_IMPLEMENTED 275 | +int sys_futex_wake(int *pointer) NOT_IMPLEMENTED 276 | +int sys_clock_get(int clock, time_t *secs, long *nanos) NOT_IMPLEMENTED 277 | + 278 | +} // namespace mlibc 279 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/access.h mlibc-workdir/sysdeps/flan/include/abi-bits/access.h 280 | new file mode 120000 281 | index 0000000..cb83931 282 | --- /dev/null 283 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/access.h 284 | @@ -0,0 +1 @@ 285 | +../../../../abis/linux/access.h 286 | \ No newline at end of file 287 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/auxv.h mlibc-workdir/sysdeps/flan/include/abi-bits/auxv.h 288 | new file mode 120000 289 | index 0000000..c43f878 290 | --- /dev/null 291 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/auxv.h 292 | @@ -0,0 +1 @@ 293 | +../../../../abis/linux/auxv.h 294 | \ No newline at end of file 295 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/blkcnt_t.h mlibc-workdir/sysdeps/flan/include/abi-bits/blkcnt_t.h 296 | new file mode 120000 297 | index 0000000..0b0ec27 298 | --- /dev/null 299 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/blkcnt_t.h 300 | @@ -0,0 +1 @@ 301 | +../../../../abis/linux/blkcnt_t.h 302 | \ No newline at end of file 303 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/blksize_t.h mlibc-workdir/sysdeps/flan/include/abi-bits/blksize_t.h 304 | new file mode 120000 305 | index 0000000..7dc8d7c 306 | --- /dev/null 307 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/blksize_t.h 308 | @@ -0,0 +1 @@ 309 | +../../../../abis/linux/blksize_t.h 310 | \ No newline at end of file 311 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/clockid_t.h mlibc-workdir/sysdeps/flan/include/abi-bits/clockid_t.h 312 | new file mode 120000 313 | index 0000000..6a42da5 314 | --- /dev/null 315 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/clockid_t.h 316 | @@ -0,0 +1 @@ 317 | +../../../../abis/linux/clockid_t.h 318 | \ No newline at end of file 319 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/dev_t.h mlibc-workdir/sysdeps/flan/include/abi-bits/dev_t.h 320 | new file mode 120000 321 | index 0000000..bca881e 322 | --- /dev/null 323 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/dev_t.h 324 | @@ -0,0 +1 @@ 325 | +../../../../abis/linux/dev_t.h 326 | \ No newline at end of file 327 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/epoll.h mlibc-workdir/sysdeps/flan/include/abi-bits/epoll.h 328 | new file mode 120000 329 | index 0000000..eb4b76d 330 | --- /dev/null 331 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/epoll.h 332 | @@ -0,0 +1 @@ 333 | +../../../../abis/linux/epoll.h 334 | \ No newline at end of file 335 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/errno.h mlibc-workdir/sysdeps/flan/include/abi-bits/errno.h 336 | new file mode 120000 337 | index 0000000..6e507de 338 | --- /dev/null 339 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/errno.h 340 | @@ -0,0 +1 @@ 341 | +../../../../abis/linux/errno.h 342 | \ No newline at end of file 343 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/fcntl.h mlibc-workdir/sysdeps/flan/include/abi-bits/fcntl.h 344 | new file mode 120000 345 | index 0000000..463e2c9 346 | --- /dev/null 347 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/fcntl.h 348 | @@ -0,0 +1 @@ 349 | +../../../../abis/linux/fcntl.h 350 | \ No newline at end of file 351 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/fsblkcnt_t.h mlibc-workdir/sysdeps/flan/include/abi-bits/fsblkcnt_t.h 352 | new file mode 120000 353 | index 0000000..898dfb2 354 | --- /dev/null 355 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/fsblkcnt_t.h 356 | @@ -0,0 +1 @@ 357 | +../../../../abis/linux/fsblkcnt_t.h 358 | \ No newline at end of file 359 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/fsfilcnt_t.h mlibc-workdir/sysdeps/flan/include/abi-bits/fsfilcnt_t.h 360 | new file mode 120000 361 | index 0000000..791755c 362 | --- /dev/null 363 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/fsfilcnt_t.h 364 | @@ -0,0 +1 @@ 365 | +../../../../abis/linux/fsfilcnt_t.h 366 | \ No newline at end of file 367 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/gid_t.h mlibc-workdir/sysdeps/flan/include/abi-bits/gid_t.h 368 | new file mode 120000 369 | index 0000000..abce6d6 370 | --- /dev/null 371 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/gid_t.h 372 | @@ -0,0 +1 @@ 373 | +../../../../abis/linux/gid_t.h 374 | \ No newline at end of file 375 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/in.h mlibc-workdir/sysdeps/flan/include/abi-bits/in.h 376 | new file mode 120000 377 | index 0000000..418d1d5 378 | --- /dev/null 379 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/in.h 380 | @@ -0,0 +1 @@ 381 | +../../../../abis/linux/in.h 382 | \ No newline at end of file 383 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/ino_t.h mlibc-workdir/sysdeps/flan/include/abi-bits/ino_t.h 384 | new file mode 120000 385 | index 0000000..4c20aca 386 | --- /dev/null 387 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/ino_t.h 388 | @@ -0,0 +1 @@ 389 | +../../../../abis/linux/ino_t.h 390 | \ No newline at end of file 391 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/inotify.h mlibc-workdir/sysdeps/flan/include/abi-bits/inotify.h 392 | new file mode 120000 393 | index 0000000..b5cb282 394 | --- /dev/null 395 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/inotify.h 396 | @@ -0,0 +1 @@ 397 | +../../../../abis/linux/inotify.h 398 | \ No newline at end of file 399 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/ioctls.h mlibc-workdir/sysdeps/flan/include/abi-bits/ioctls.h 400 | new file mode 120000 401 | index 0000000..595106b 402 | --- /dev/null 403 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/ioctls.h 404 | @@ -0,0 +1 @@ 405 | +../../../../abis/linux/ioctls.h 406 | \ No newline at end of file 407 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/limits.h mlibc-workdir/sysdeps/flan/include/abi-bits/limits.h 408 | new file mode 120000 409 | index 0000000..6c88db2 410 | --- /dev/null 411 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/limits.h 412 | @@ -0,0 +1 @@ 413 | +../../../../abis/linux/limits.h 414 | \ No newline at end of file 415 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/mode_t.h mlibc-workdir/sysdeps/flan/include/abi-bits/mode_t.h 416 | new file mode 120000 417 | index 0000000..5d78fdf 418 | --- /dev/null 419 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/mode_t.h 420 | @@ -0,0 +1 @@ 421 | +../../../../abis/linux/mode_t.h 422 | \ No newline at end of file 423 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/mqueue.h mlibc-workdir/sysdeps/flan/include/abi-bits/mqueue.h 424 | new file mode 120000 425 | index 0000000..fa87b07 426 | --- /dev/null 427 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/mqueue.h 428 | @@ -0,0 +1 @@ 429 | +../../../../abis/linux/mqueue.h 430 | \ No newline at end of file 431 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/nlink_t.h mlibc-workdir/sysdeps/flan/include/abi-bits/nlink_t.h 432 | new file mode 120000 433 | index 0000000..bb3b625 434 | --- /dev/null 435 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/nlink_t.h 436 | @@ -0,0 +1 @@ 437 | +../../../../abis/linux/nlink_t.h 438 | \ No newline at end of file 439 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/packet.h mlibc-workdir/sysdeps/flan/include/abi-bits/packet.h 440 | new file mode 120000 441 | index 0000000..998ef1a 442 | --- /dev/null 443 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/packet.h 444 | @@ -0,0 +1 @@ 445 | +../../../../abis/linux/packet.h 446 | \ No newline at end of file 447 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/pid_t.h mlibc-workdir/sysdeps/flan/include/abi-bits/pid_t.h 448 | new file mode 120000 449 | index 0000000..baa90f6 450 | --- /dev/null 451 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/pid_t.h 452 | @@ -0,0 +1 @@ 453 | +../../../../abis/linux/pid_t.h 454 | \ No newline at end of file 455 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/poll.h mlibc-workdir/sysdeps/flan/include/abi-bits/poll.h 456 | new file mode 120000 457 | index 0000000..8ea6a0a 458 | --- /dev/null 459 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/poll.h 460 | @@ -0,0 +1 @@ 461 | +../../../../abis/linux/poll.h 462 | \ No newline at end of file 463 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/ptrace.h mlibc-workdir/sysdeps/flan/include/abi-bits/ptrace.h 464 | new file mode 120000 465 | index 0000000..b2517b2 466 | --- /dev/null 467 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/ptrace.h 468 | @@ -0,0 +1 @@ 469 | +../../../../abis/linux/ptrace.h 470 | \ No newline at end of file 471 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/reboot.h mlibc-workdir/sysdeps/flan/include/abi-bits/reboot.h 472 | new file mode 120000 473 | index 0000000..77013a4 474 | --- /dev/null 475 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/reboot.h 476 | @@ -0,0 +1 @@ 477 | +../../../../abis/linux/reboot.h 478 | \ No newline at end of file 479 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/resource.h mlibc-workdir/sysdeps/flan/include/abi-bits/resource.h 480 | new file mode 120000 481 | index 0000000..88d7402 482 | --- /dev/null 483 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/resource.h 484 | @@ -0,0 +1 @@ 485 | +../../../../abis/linux/resource.h 486 | \ No newline at end of file 487 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/seek-whence.h mlibc-workdir/sysdeps/flan/include/abi-bits/seek-whence.h 488 | new file mode 120000 489 | index 0000000..df7bccf 490 | --- /dev/null 491 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/seek-whence.h 492 | @@ -0,0 +1 @@ 493 | +../../../../abis/linux/seek-whence.h 494 | \ No newline at end of file 495 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/shm.h mlibc-workdir/sysdeps/flan/include/abi-bits/shm.h 496 | new file mode 120000 497 | index 0000000..067d8c4 498 | --- /dev/null 499 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/shm.h 500 | @@ -0,0 +1 @@ 501 | +../../../../abis/linux/shm.h 502 | \ No newline at end of file 503 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/signal.h mlibc-workdir/sysdeps/flan/include/abi-bits/signal.h 504 | new file mode 120000 505 | index 0000000..4dcb0b7 506 | --- /dev/null 507 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/signal.h 508 | @@ -0,0 +1 @@ 509 | +../../../../abis/linux/signal.h 510 | \ No newline at end of file 511 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/socket.h mlibc-workdir/sysdeps/flan/include/abi-bits/socket.h 512 | new file mode 120000 513 | index 0000000..f1dc016 514 | --- /dev/null 515 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/socket.h 516 | @@ -0,0 +1 @@ 517 | +../../../../abis/linux/socket.h 518 | \ No newline at end of file 519 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/socklen_t.h mlibc-workdir/sysdeps/flan/include/abi-bits/socklen_t.h 520 | new file mode 120000 521 | index 0000000..41f3b11 522 | --- /dev/null 523 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/socklen_t.h 524 | @@ -0,0 +1 @@ 525 | +../../../../abis/linux/socklen_t.h 526 | \ No newline at end of file 527 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/stat.h mlibc-workdir/sysdeps/flan/include/abi-bits/stat.h 528 | new file mode 120000 529 | index 0000000..1f63b41 530 | --- /dev/null 531 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/stat.h 532 | @@ -0,0 +1 @@ 533 | +../../../../abis/linux/stat.h 534 | \ No newline at end of file 535 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/statfs.h mlibc-workdir/sysdeps/flan/include/abi-bits/statfs.h 536 | new file mode 120000 537 | index 0000000..e3d202f 538 | --- /dev/null 539 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/statfs.h 540 | @@ -0,0 +1 @@ 541 | +../../../../abis/linux/statfs.h 542 | \ No newline at end of file 543 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/statvfs.h mlibc-workdir/sysdeps/flan/include/abi-bits/statvfs.h 544 | new file mode 120000 545 | index 0000000..1fc80c2 546 | --- /dev/null 547 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/statvfs.h 548 | @@ -0,0 +1 @@ 549 | +../../../../abis/linux/statvfs.h 550 | \ No newline at end of file 551 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/suseconds_t.h mlibc-workdir/sysdeps/flan/include/abi-bits/suseconds_t.h 552 | new file mode 120000 553 | index 0000000..9ed6597 554 | --- /dev/null 555 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/suseconds_t.h 556 | @@ -0,0 +1 @@ 557 | +../../../../abis/linux/suseconds_t.h 558 | \ No newline at end of file 559 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/termios.h mlibc-workdir/sysdeps/flan/include/abi-bits/termios.h 560 | new file mode 120000 561 | index 0000000..ee8f0b0 562 | --- /dev/null 563 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/termios.h 564 | @@ -0,0 +1 @@ 565 | +../../../../abis/linux/termios.h 566 | \ No newline at end of file 567 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/time.h mlibc-workdir/sysdeps/flan/include/abi-bits/time.h 568 | new file mode 120000 569 | index 0000000..2a02625 570 | --- /dev/null 571 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/time.h 572 | @@ -0,0 +1 @@ 573 | +../../../../abis/linux/time.h 574 | \ No newline at end of file 575 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/uid_t.h mlibc-workdir/sysdeps/flan/include/abi-bits/uid_t.h 576 | new file mode 120000 577 | index 0000000..b306777 578 | --- /dev/null 579 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/uid_t.h 580 | @@ -0,0 +1 @@ 581 | +../../../../abis/linux/uid_t.h 582 | \ No newline at end of file 583 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/utsname.h mlibc-workdir/sysdeps/flan/include/abi-bits/utsname.h 584 | new file mode 120000 585 | index 0000000..b285754 586 | --- /dev/null 587 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/utsname.h 588 | @@ -0,0 +1 @@ 589 | +../../../../abis/linux/utsname.h 590 | \ No newline at end of file 591 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/vm-flags.h mlibc-workdir/sysdeps/flan/include/abi-bits/vm-flags.h 592 | new file mode 120000 593 | index 0000000..bbe258c 594 | --- /dev/null 595 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/vm-flags.h 596 | @@ -0,0 +1 @@ 597 | +../../../../abis/linux/vm-flags.h 598 | \ No newline at end of file 599 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/vt.h mlibc-workdir/sysdeps/flan/include/abi-bits/vt.h 600 | new file mode 120000 601 | index 0000000..5798a4a 602 | --- /dev/null 603 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/vt.h 604 | @@ -0,0 +1 @@ 605 | +../../../../abis/linux/vt.h 606 | \ No newline at end of file 607 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/wait.h mlibc-workdir/sysdeps/flan/include/abi-bits/wait.h 608 | new file mode 120000 609 | index 0000000..feb2840 610 | --- /dev/null 611 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/wait.h 612 | @@ -0,0 +1 @@ 613 | +../../../../abis/linux/wait.h 614 | \ No newline at end of file 615 | diff --git mlibc-workdir/sysdeps/flan/include/abi-bits/xattr.h mlibc-workdir/sysdeps/flan/include/abi-bits/xattr.h 616 | new file mode 120000 617 | index 0000000..66412d7 618 | --- /dev/null 619 | +++ mlibc-workdir/sysdeps/flan/include/abi-bits/xattr.h 620 | @@ -0,0 +1 @@ 621 | +../../../../abis/linux/xattr.h 622 | \ No newline at end of file 623 | diff --git mlibc-workdir/sysdeps/flan/meson.build mlibc-workdir/sysdeps/flan/meson.build 624 | new file mode 100644 625 | index 0000000..49bb989 626 | --- /dev/null 627 | +++ mlibc-workdir/sysdeps/flan/meson.build 628 | @@ -0,0 +1,86 @@ 629 | +rtdl_sources += files( 630 | + 'generic/generic.cpp' 631 | +) 632 | + 633 | +libc_sources += files( 634 | + 'generic/entry.cpp', 635 | + 'generic/generic.cpp' 636 | +) 637 | + 638 | +if not no_headers 639 | + install_headers( 640 | + 'include/abi-bits/auxv.h', 641 | + 'include/abi-bits/seek-whence.h', 642 | + 'include/abi-bits/vm-flags.h', 643 | + 'include/abi-bits/errno.h', 644 | + 'include/abi-bits/fcntl.h', 645 | + 'include/abi-bits/in.h', 646 | + 'include/abi-bits/reboot.h', 647 | + 'include/abi-bits/resource.h', 648 | + 'include/abi-bits/stat.h', 649 | + 'include/abi-bits/signal.h', 650 | + 'include/abi-bits/socket.h', 651 | + 'include/abi-bits/termios.h', 652 | + 'include/abi-bits/time.h', 653 | + 'include/abi-bits/blkcnt_t.h', 654 | + 'include/abi-bits/blksize_t.h', 655 | + 'include/abi-bits/dev_t.h', 656 | + 'include/abi-bits/gid_t.h', 657 | + 'include/abi-bits/ino_t.h', 658 | + 'include/abi-bits/mode_t.h', 659 | + 'include/abi-bits/nlink_t.h', 660 | + 'include/abi-bits/pid_t.h', 661 | + 'include/abi-bits/uid_t.h', 662 | + 'include/abi-bits/access.h', 663 | + 'include/abi-bits/wait.h', 664 | + 'include/abi-bits/limits.h', 665 | + 'include/abi-bits/utsname.h', 666 | + 'include/abi-bits/ptrace.h', 667 | + 'include/abi-bits/poll.h', 668 | + 'include/abi-bits/epoll.h', 669 | + 'include/abi-bits/packet.h', 670 | + 'include/abi-bits/inotify.h', 671 | + 'include/abi-bits/clockid_t.h', 672 | + 'include/abi-bits/shm.h', 673 | + 'include/abi-bits/mqueue.h', 674 | + 'include/abi-bits/suseconds_t.h', 675 | + 'include/abi-bits/fsfilcnt_t.h', 676 | + 'include/abi-bits/fsblkcnt_t.h', 677 | + 'include/abi-bits/socklen_t.h', 678 | + 'include/abi-bits/statfs.h', 679 | + 'include/abi-bits/statvfs.h', 680 | + 'include/abi-bits/ioctls.h', 681 | + 'include/abi-bits/xattr.h', 682 | + subdir: 'abi-bits' 683 | + ) 684 | +endif 685 | + 686 | +if not headers_only 687 | + crt = custom_target('crt0', 688 | + build_by_default: true, 689 | + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], 690 | + input: 'crt-src/crt0.S', 691 | + output: 'crt0.o', 692 | + install: true, 693 | + install_dir: get_option('libdir') 694 | + ) 695 | + 696 | + custom_target('crti', 697 | + build_by_default: true, 698 | + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], 699 | + input: 'crt-src/crti.S', 700 | + output: 'crti.o', 701 | + install: true, 702 | + install_dir: get_option('libdir') 703 | + ) 704 | + 705 | + custom_target('crtn', 706 | + build_by_default: true, 707 | + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], 708 | + input: 'crt-src/crtn.S', 709 | + output: 'crtn.o', 710 | + install: true, 711 | + install_dir: get_option('libdir') 712 | + ) 713 | +endif 714 | + 715 | -------------------------------------------------------------------------------- /recipes/core-libs: -------------------------------------------------------------------------------- 1 | name=core-libs 2 | from_source=mlibc 3 | revision=1 4 | deps="mlibc libgcc libstdc++ libintl libiconv libxcrypt" 5 | 6 | configure() { 7 | true 8 | } 9 | 10 | build() { 11 | true 12 | } 13 | 14 | install() { 15 | true 16 | } 17 | -------------------------------------------------------------------------------- /recipes/cxxshim: -------------------------------------------------------------------------------- 1 | name=cxxshim 2 | from_source=cxxshim 3 | revision=1 4 | imagedeps="meson ninja git base-devel" 5 | 6 | configure() { 7 | meson setup \ 8 | --prefix=${prefix} \ 9 | --libdir=lib \ 10 | --includedir=share/cxxshim/include \ 11 | -Dinstall_headers=true \ 12 | ${source_dir} 13 | } 14 | 15 | build() { 16 | ninja 17 | } 18 | 19 | install() { 20 | DESTDIR="${dest_dir}" ninja install 21 | } 22 | -------------------------------------------------------------------------------- /recipes/frigg: -------------------------------------------------------------------------------- 1 | name=frigg 2 | from_source=frigg 3 | revision=1 4 | imagedeps="meson ninja git base-devel" 5 | 6 | configure() { 7 | meson setup \ 8 | --prefix=${prefix} \ 9 | --libdir=lib \ 10 | --includedir=share/frigg/include \ 11 | --buildtype=debugoptimized \ 12 | -Dbuild_tests=disabled \ 13 | ${source_dir} 14 | } 15 | 16 | build() { 17 | ninja 18 | } 19 | 20 | install() { 21 | DESTDIR="${dest_dir}" ninja install 22 | } 23 | -------------------------------------------------------------------------------- /recipes/init: -------------------------------------------------------------------------------- 1 | name=init 2 | from_source=init 3 | revision=1 4 | deps="core-libs" 5 | hostdeps="gcc" 6 | 7 | configure() { 8 | cp -r ${source_dir}/. ./ 9 | } 10 | 11 | build() { 12 | make -j${parallelism} CC=x86_64-flan-gcc 13 | } 14 | 15 | install() { 16 | make install DESTDIR="${dest_dir}" PREFIX="${prefix}" STRIP=x86_64-flan-strip 17 | } 18 | -------------------------------------------------------------------------------- /recipes/libgcc: -------------------------------------------------------------------------------- 1 | name=libgcc 2 | from_source=gcc-host 3 | revision=1 4 | hostdeps="gcc autoconf automake libtool pkg-config" 5 | imagedeps="gcc" 6 | deps="mlibc" 7 | 8 | configure() { 9 | true 10 | } 11 | 12 | build() { 13 | cd "${base_dir}"/host-builds/gcc/build 14 | 15 | make -j${parallelism} all-target-libgcc 16 | } 17 | 18 | install() { 19 | cd "${base_dir}"/host-builds/gcc/build 20 | 21 | rm -rf tmp_libgcc_dir 22 | mkdir tmp_libgcc_dir 23 | 24 | DESTDIR="$(realpath tmp_libgcc_dir)" make install-strip-target-libgcc 25 | 26 | mkdir -p "${dest_dir}${prefix}" 27 | 28 | cp -r tmp_libgcc_dir/usr/local/lib "${dest_dir}${prefix}"/ 29 | cp -r tmp_libgcc_dir/usr/local/x86_64-flan/* "${dest_dir}${prefix}"/ 30 | 31 | rm "${dest_dir}${prefix}"/lib/gcc/x86_64-flan/13.1.0/crti.o 32 | rm "${dest_dir}${prefix}"/lib/gcc/x86_64-flan/13.1.0/crtn.o 33 | 34 | # Copy libgcc into GCC's tree else it will complain. 35 | mkdir -p "${base_dir}"/host-pkgs/gcc/usr/local/lib 36 | cp -r tmp_libgcc_dir/usr/local/lib/* "${base_dir}"/host-pkgs/gcc/usr/local/lib/ 37 | 38 | rm "${base_dir}"/host-pkgs/gcc/usr/local/lib/gcc/x86_64-flan/13.1.0/crti.o 39 | rm "${base_dir}"/host-pkgs/gcc/usr/local/lib/gcc/x86_64-flan/13.1.0/crtn.o 40 | } 41 | -------------------------------------------------------------------------------- /recipes/libiconv: -------------------------------------------------------------------------------- 1 | name=libiconv 2 | from_source=libiconv 3 | revision=1 4 | hostdeps="gcc autoconf automake libtool pkg-config" 5 | deps="mlibc libgcc libstdc++" 6 | imagedeps="binutils" 7 | 8 | configure() { 9 | ${source_dir}/configure \ 10 | --host=x86_64-flan \ 11 | --prefix=${prefix} \ 12 | --sysconfdir=/etc \ 13 | --localstatedir=/var \ 14 | --disable-static \ 15 | --enable-shared \ 16 | --disable-nls 17 | } 18 | 19 | build() { 20 | make -j${parallelism} 21 | } 22 | 23 | install() { 24 | DESTDIR="${dest_dir}" make install-strip 25 | 26 | x86_64-flan-strip "${dest_dir}${prefix}"/lib/{libcharset.so.1.0.0,libiconv.so.2.6.1} 27 | } 28 | -------------------------------------------------------------------------------- /recipes/libintl: -------------------------------------------------------------------------------- 1 | name=libintl 2 | from_source=libintl 3 | revision=1 4 | hostdeps="gcc automake autoconf libtool pkg-config" 5 | deps="mlibc libgcc libiconv" 6 | 7 | configure() { 8 | ${source_dir}/configure \ 9 | --host=x86_64-flan \ 10 | --prefix=${prefix} \ 11 | --without-emacs \ 12 | --without-lispdir \ 13 | `# Normally this controls nls behavior in general, but the libintl` \ 14 | `# subdir is skipped unless this is explicitly set.` \ 15 | --enable-nls \ 16 | `# This magic flag enables libintl.` \ 17 | --with-included-gettext \ 18 | --disable-c++ \ 19 | --disable-libasprintf \ 20 | --disable-java \ 21 | --enable-shared \ 22 | --disable-static \ 23 | --enable-threads=posix \ 24 | --disable-curses \ 25 | --without-git \ 26 | --without-cvs \ 27 | --without-bzip2 \ 28 | --without-xz 29 | } 30 | 31 | build() { 32 | make -C gettext-runtime/intl -j${parallelism} 33 | } 34 | 35 | install() { 36 | DESTDIR="${dest_dir}" make -C gettext-runtime/intl install-strip 37 | } 38 | -------------------------------------------------------------------------------- /recipes/libstdc++: -------------------------------------------------------------------------------- 1 | name=libstdc++ 2 | from_source=gcc-host 3 | revision=1 4 | hostdeps="gcc autoconf automake libtool pkg-config" 5 | imagedeps="gcc" 6 | deps="mlibc libgcc" 7 | 8 | configure() { 9 | true 10 | } 11 | 12 | build() { 13 | cd "${base_dir}"/host-builds/gcc/build 14 | 15 | make -j${parallelism} all-target-libstdc++-v3 16 | } 17 | 18 | install() { 19 | cd "${base_dir}"/host-builds/gcc/build 20 | 21 | rm -rf tmp_libstdc++_dir 22 | mkdir tmp_libstdc++_dir 23 | 24 | DESTDIR="$(realpath tmp_libstdc++_dir)" make install-strip-target-libstdc++-v3 25 | 26 | mkdir -p "${dest_dir}${prefix}" 27 | 28 | cp -r tmp_libstdc++_dir/usr/local/share "${dest_dir}${prefix}"/ 29 | cp -r tmp_libstdc++_dir/usr/local/x86_64-flan/* "${dest_dir}${prefix}"/ 30 | # Remove static libraries 31 | rm -rf "${dest_dir}${prefix}"/lib/*.a 32 | 33 | # Copy libstdc++ and headers into GCC's tree else it will complain. 34 | mkdir -p "${base_dir}"/host-pkgs/gcc/usr/local/x86_64-flan 35 | cp -r tmp_libstdc++_dir/usr/local/x86_64-flan/* "${base_dir}"/host-pkgs/gcc/usr/local/x86_64-flan/ 36 | } 37 | -------------------------------------------------------------------------------- /recipes/libxcrypt: -------------------------------------------------------------------------------- 1 | name=libxcrypt 2 | from_source=libxcrypt 3 | revision=1 4 | hostdeps="gcc automake autoconf libtool pkg-config" 5 | deps="mlibc libgcc libstdc++" 6 | 7 | configure() { 8 | ${source_dir}/configure \ 9 | --host=x86_64-flan \ 10 | --prefix=${prefix} \ 11 | --sysconfdir=/etc \ 12 | --localstatedir=/var \ 13 | --enable-obsolete-api=yes \ 14 | --disable-xcrypt-compat-files \ 15 | --disable-static 16 | } 17 | 18 | build() { 19 | make -j${parallelism} 20 | } 21 | 22 | install() { 23 | DESTDIR="${dest_dir}" make install-strip 24 | } 25 | -------------------------------------------------------------------------------- /recipes/linux-headers: -------------------------------------------------------------------------------- 1 | name=linux-headers 2 | from_source=linux 3 | revision=1 4 | imagedeps="gcc rsync" 5 | 6 | configure() { 7 | cp -rp "${source_dir}"/. ./ 8 | } 9 | 10 | build() { 11 | make ARCH=x86_64 headers_install 12 | find usr/include -type f ! -name *.h -delete 13 | # remove this file, as mlibc will override this file with one suited to mlibc 14 | rm usr/include/linux/libc-compat.h 15 | } 16 | 17 | install() { 18 | mkdir -p "${dest_dir}${prefix}" 19 | cp -r usr/include "${dest_dir}${prefix}"/ 20 | } 21 | -------------------------------------------------------------------------------- /recipes/mlibc: -------------------------------------------------------------------------------- 1 | name=mlibc 2 | from_source=mlibc 3 | revision=1 4 | imagedeps="meson ninja" 5 | hostdeps="gcc pkg-config libgcc-binaries" 6 | deps="linux-headers mlibc-headers cxxshim frigg" 7 | 8 | configure() { 9 | LDFLAGS="-Wl,/usr/local/libgcc-binaries/libgcc-x86_64.a" \ 10 | meson setup \ 11 | --cross-file ${base_dir}/build-support/cross_file.txt \ 12 | --prefix=${prefix} \ 13 | --libdir=lib \ 14 | --buildtype=debugoptimized \ 15 | -Dmlibc_no_headers=true \ 16 | -Ddisable_crypt_option=true \ 17 | -Ddisable_iconv_option=true \ 18 | -Ddisable_intl_option=true \ 19 | -Ddisable_libgcc_dependency=true \ 20 | ${source_dir} 21 | } 22 | 23 | build() { 24 | ninja 25 | } 26 | 27 | install() { 28 | DESTDIR="${dest_dir}" ninja install 29 | } 30 | -------------------------------------------------------------------------------- /recipes/mlibc-headers: -------------------------------------------------------------------------------- 1 | name=mlibc-headers 2 | from_source=mlibc 3 | revision=1 4 | hostdeps="pkg-config" 5 | imagedeps="meson ninja git" 6 | deps="linux-headers cxxshim frigg" 7 | 8 | configure() { 9 | meson setup \ 10 | --cross-file ${base_dir}/build-support/cross_file.txt \ 11 | --prefix=${prefix} \ 12 | -Dheaders_only=true \ 13 | -Ddisable_crypt_option=true \ 14 | -Ddisable_iconv_option=true \ 15 | -Ddisable_intl_option=true \ 16 | ${source_dir} 17 | } 18 | 19 | build() { 20 | ninja 21 | } 22 | 23 | install() { 24 | DESTDIR="${dest_dir}" ninja install 25 | } 26 | -------------------------------------------------------------------------------- /source-recipes/autoconf: -------------------------------------------------------------------------------- 1 | name=autoconf 2 | version=2.69 3 | tarball_url="https://ftp.gnu.org/gnu/autoconf/autoconf-${version}.tar.gz" 4 | tarball_blake2b="7e8a513bbfcabadad1577919c048cc05ca0a084788850b42570f88afc2fa9c25fb32277412f135b81ba1c0d8079465a6b581d2d78662c991d2183b739fac407c" 5 | 6 | regenerate() { 7 | true 8 | } 9 | -------------------------------------------------------------------------------- /source-recipes/automake: -------------------------------------------------------------------------------- 1 | name=automake 2 | version=1.16.5 3 | tarball_url="https://ftp.gnu.org/gnu/automake/automake-${version}.tar.gz" 4 | tarball_blake2b="5ccdcbe2d3deb2b0baed4a8590b07714cd7098fbda251afebe83232ed03f4db84abbe023cf0544622dbc5137254347273247428eb5420564a167b86de95d113e" 5 | 6 | regenerate() { 7 | true 8 | } 9 | -------------------------------------------------------------------------------- /source-recipes/binutils: -------------------------------------------------------------------------------- 1 | name=binutils 2 | version=2.40 3 | tarball_url="https://ftp.gnu.org/gnu/binutils/binutils-${version}.tar.xz" 4 | tarball_blake2b="8d799f7c595f878b9af5b17a490021dd8b8300ac2fe0ed8574c012929d22d2d0493e003a3e631a9436e8e712da801779b777c566167fe42b0bde119ffa5ad1c2" 5 | hostdeps="autoconf automake libtool pkg-config" 6 | 7 | regenerate() { 8 | ( cd libiberty && libtoolize -cfvi && autoreconf -fvi -I$(realpath ./config) -I$(realpath ../config) ) 9 | ( cd intl && libtoolize -cfvi && autoreconf -fvi -I$(realpath ../config) ) 10 | ( cd zlib/contrib/minizip && libtoolize -cfvi && autoreconf -fvi -I$(realpath ../../../config) ) 11 | ( cd zlib && libtoolize -cfvi && autoreconf -fvi -I$(realpath ../config) ) 12 | ( cd bfd && libtoolize -cfvi && autoreconf -fvi -I$(realpath ../config) ) 13 | ( cd opcodes && libtoolize -cfvi && autoreconf -fvi -I$(realpath ../config) ) 14 | ( cd gas && libtoolize -cfvi && autoreconf -fvi -I$(realpath ../config) ) 15 | ( cd gold && libtoolize -cfvi && autoreconf -fvi -I$(realpath ../config) ) 16 | ( cd libctf && libtoolize -cfvi && autoreconf -fvi -I$(realpath ../config) ) 17 | ( cd binutils && libtoolize -cfvi && autoreconf -fvi -I$(realpath ../config) ) 18 | ( cd libsframe && libtoolize -cfvi && autoreconf -fvi -I$(realpath ../config) ) 19 | ( cd gprof && libtoolize -cfvi && autoreconf -fvi -I$(realpath ../config) ) 20 | ( cd gprofng/libcollector && libtoolize -cfvi && autoreconf -fvi -I$(realpath ../../config) ) 21 | ( cd gprofng && libtoolize -cfvi && autoreconf -fvi -I$(realpath ../config) ) 22 | ( cd ld && libtoolize -cfvi && autoreconf -fvi -I$(realpath ../config) ) 23 | libtoolize -cfvi && autoreconf -fvi -I$(realpath ./config) 24 | } 25 | -------------------------------------------------------------------------------- /source-recipes/cxxshim: -------------------------------------------------------------------------------- 1 | name=cxxshim 2 | version=1abc678c17a8b54bf9497065443c1d4b292accb9 3 | tarball_url="https://github.com/managarm/cxxshim/archive/${version}.tar.gz" 4 | tarball_blake2b="4bf7a835e5df38c8ceb2f12aa9329c1aab1daed09bdeb4ae6981d379456988ef13a2ac662ffe5b4b0c1dde89fc32e17a4219bd752d2dbef4608f95bf20a884d8" 5 | 6 | regenerate() { 7 | true 8 | } 9 | -------------------------------------------------------------------------------- /source-recipes/frigg: -------------------------------------------------------------------------------- 1 | name=frigg 2 | version=22126f9f33c76e3b1dc342081cc7497c1327e02d 3 | tarball_url="https://github.com/managarm/frigg/archive/${version}.tar.gz" 4 | tarball_blake2b="ac8ff2da4bbc846baf8d50070cc4f53876415e5897752c2385b06804b257e9f5dfaa02dd1ecd97a1ed2feac7f13a11c9186222a5cf13cb8a66126828bf04711f" 5 | 6 | regenerate() { 7 | true 8 | } 9 | -------------------------------------------------------------------------------- /source-recipes/gcc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catmaster1010/flan/5abbfd5c61bee82edbaabc14f3512d45ac88b1cb/source-recipes/gcc -------------------------------------------------------------------------------- /source-recipes/gcc-host: -------------------------------------------------------------------------------- 1 | name=gcc-host 2 | version=13.1.0 3 | tarball_url="https://ftp.gnu.org/gnu/gcc/gcc-${version}/gcc-${version}.tar.xz" 4 | tarball_blake2b="b956a773cffe8b43bd6c9a99fe614f53f665438925a6b320975d301f547923e45d4d6fa577a143467fb03e0a9c1bab2b6719a1011d672367f3e644433a2d7606" 5 | hostdeps="automake autoconf libtool pkg-config" 6 | imagedeps="git" 7 | allow_network="yes" 8 | 9 | regenerate() { 10 | ./contrib/download_prerequisites 11 | 12 | autotools_recursive_regen -I"$(realpath ./config)" 13 | } 14 | -------------------------------------------------------------------------------- /source-recipes/gnulib: -------------------------------------------------------------------------------- 1 | name=gnulib 2 | version=8c4d0fbf4c45df8e86acbb338b154930c5498dc3 3 | tarball_url="https://git.savannah.gnu.org/cgit/gnulib.git/snapshot/gnulib-${version}.tar.gz" 4 | tarball_blake2b="b808f83f296dc31c147cbff3e9fa1d2345d49ee8fda606b4efd702d4c15fd83e61371550712a10bc15397b1424e135ffd1ffd118e7e5bc72e4a4b866ccce5720" 5 | 6 | regenerate() { 7 | true 8 | } 9 | -------------------------------------------------------------------------------- /source-recipes/init: -------------------------------------------------------------------------------- 1 | name=init 2 | version=0.0 3 | source_dir="init" 4 | 5 | regenerate() { 6 | true 7 | } 8 | -------------------------------------------------------------------------------- /source-recipes/libgcc-binaries: -------------------------------------------------------------------------------- 1 | name=libgcc-binaries 2 | version=e1f1e4d9727f42e9a82a8f384a126853b7b03818 3 | tarball_url="https://github.com/mintsuki/libgcc-binaries/archive/${version}.tar.gz" 4 | tarball_blake2b="3e5f3131da754259f58c2c6427fc8534d47c25adfc79d18ff5ea96037b8031caa3e2484ea5e78ddde4547023523a49951e33706384faa3132e296707e244a6d1" 5 | 6 | regenerate() { 7 | true 8 | } 9 | -------------------------------------------------------------------------------- /source-recipes/libiconv: -------------------------------------------------------------------------------- 1 | name=libiconv 2 | version=1.17 3 | tarball_url="https://ftp.gnu.org/gnu/libiconv/libiconv-${version}.tar.gz" 4 | tarball_blake2b="1d317dd0655c680a2082c38561cdff51ac1a9181d4734a8bb1e86861dfd66f1a6c0846a90b5b88f3b38b1fa9983d9e563551f27e95a8e329896b71becceae52b" 5 | hostdeps="automake autoconf libtool pkg-config" 6 | 7 | regenerate() { 8 | cp /usr/local/share/aclocal/libtool.m4 ./m4/ 9 | cp /usr/local/share/aclocal/libtool.m4 ./libcharset/m4/ 10 | cp /usr/local/share/libtool/build-aux/ltmain.sh ./build-aux/ 11 | cp /usr/local/share/libtool/build-aux/ltmain.sh ./libcharset/build-aux/ 12 | cp /usr/local/share/aclocal/ltversion.m4 ./m4/ 13 | cp /usr/local/share/aclocal/ltversion.m4 ./libcharset/m4/ 14 | 15 | autotools_recursive_regen -I"${source_dir}"/m4 -I"${source_dir}"/srcm4 16 | } 17 | -------------------------------------------------------------------------------- /source-recipes/libintl: -------------------------------------------------------------------------------- 1 | name=libintl 2 | version=0.21.1 3 | tarball_url="https://ftp.gnu.org/gnu/gettext/gettext-${version}.tar.gz" 4 | tarball_blake2b="339fb844c7ee57f70b69837e07feba8cc98789ccd4c7cffa9015d3f95fc505f315823ac0ab9581c7cb6b698e122d914cac24c2604d8054f501b0b977f15c31ef" 5 | hostdeps="autoconf automake libtool pkg-config" 6 | 7 | regenerate() { 8 | ( cd gettext-runtime/libasprintf && libtoolize -cfvi && autoreconf -fvi ) 9 | ( cd gettext-runtime && libtoolize -cfvi && autoreconf -fvi ) 10 | ( cd gettext-tools && libtoolize -cfvi && autoreconf -fvi ) 11 | ( cd libtextstyle && libtoolize -cfvi && autoreconf -fvi ) 12 | libtoolize -cfvi && autoreconf -fvi 13 | } 14 | -------------------------------------------------------------------------------- /source-recipes/libtool: -------------------------------------------------------------------------------- 1 | name=libtool 2 | version=2.4.7 3 | tarball_url="https://ftp.gnu.org/gnu/libtool/libtool-${version}.tar.gz" 4 | tarball_blake2b="3b7c66050237931443008d6be9c0c30f4938402bf68576cdf02f2248b216bb68c6b797bbfdb8a92caa5e12cb10208cd19771cdcb6b0d83572ad60bfc03e67e98" 5 | hostdeps="autoconf automake gnulib" 6 | imagedeps="help2man" 7 | 8 | regenerate() { 9 | cp -r ${base_dir}/sources/gnulib ./ 10 | ./bootstrap --force --skip-git --skip-po --gnulib-srcdir=`pwd`/gnulib 11 | } 12 | -------------------------------------------------------------------------------- /source-recipes/libxcrypt: -------------------------------------------------------------------------------- 1 | name=libxcrypt 2 | version=4.4.33 3 | tarball_url="https://github.com/besser82/libxcrypt/releases/download/v${version}/libxcrypt-${version}.tar.xz" 4 | tarball_blake2b="9cd2a2df4e2399d9084a5e03cb9be45e70c0213e1f143d423b5043f8f331320c79e6b8efa7ff33d401bce41a32574c6d6866096b70bf14ed715416c638f43a21" 5 | hostdeps="autoconf automake libtool pkg-config" 6 | 7 | regenerate() { 8 | libtoolize -cfvi && autoreconf -fvi 9 | } 10 | -------------------------------------------------------------------------------- /source-recipes/linux: -------------------------------------------------------------------------------- 1 | name=linux 2 | version=6.2.9 3 | tarball_url="https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${version}.tar.xz" 4 | tarball_blake2b="0e7ad5502767cb74fa0fea79884ce753be0421a56bbbe0a6cb66add5839b3329298671725595c0624886d9d2836c4e9d4bd152acefb2b3df1cf7a1013e0178ba" 5 | 6 | regenerate() { 7 | true 8 | } 9 | -------------------------------------------------------------------------------- /source-recipes/mlibc: -------------------------------------------------------------------------------- 1 | name=mlibc 2 | source_method=tarball 3 | tarball_url="https://github.com/managarm/mlibc/archive/refs/tags/4.0.0-rc1.tar.gz" 4 | tarball_blake2b="bd04605fb3e52da1bfdc4d28c60ea2d26cc516a6c961d6cfca8f86222a0309143889a53cf757cccb4904016eb3db97be82661024dc4e558f6b2fa9eba0b1c252" 5 | regenerate() { 6 | true 7 | } 8 | -------------------------------------------------------------------------------- /source-recipes/pkg-config: -------------------------------------------------------------------------------- 1 | name=pkg-config 2 | version=1.8.0 3 | tarball_url="https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-${version}.tar.gz" 4 | tarball_blake2b="41c3496b53ba97f74afd306af872c3c5e5728f9bbf78582f17cf814fd5f92ee502b315f086c8699801b267b09dec4bb9c74adb82dd5674683fb2bafee29d852f" 5 | hostdeps="autoconf automake libtool" 6 | 7 | regenerate() { 8 | libtoolize -cfvi && autoreconf -fvi 9 | } 10 | -------------------------------------------------------------------------------- /src/acpi/acpi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static volatile struct limine_rsdp_request rsdp_request = { 11 | .id = LIMINE_RSDP_REQUEST, .revision = 0}; 12 | 13 | static rsdp_descriptor_t *rsdp = NULL; 14 | static rsdt_t *rsdt = NULL; 15 | 16 | int use_xsdt() { return rsdp->revision >= 2 && rsdp->xsdt_address != 0; } 17 | 18 | void acpi_init() { 19 | 20 | assert(rsdp_request.response); 21 | assert(rsdp_request.response->address); 22 | rsdp = rsdp_request.response->address; 23 | 24 | if (use_xsdt()) { 25 | rsdt = (rsdt_t *)(rsdp->xsdt_address + HHDM_OFFSET); 26 | } else { 27 | rsdt = (rsdt_t *)((uint64_t)rsdp->rsdt_address + HHDM_OFFSET); 28 | } 29 | 30 | printf("ACPI version: %d \n", rsdp->revision); 31 | printf("OEM ID: %s \n", rsdp->oem_id); 32 | printf("RSDT at %x\n", rsdt); 33 | if (use_xsdt()) { 34 | printf("Using XSDT.\n"); 35 | }; 36 | madt_init(); 37 | } 38 | void *acpi_find_sdt(char signature[4], uint64_t index) { 39 | uint64_t entry_count = 40 | (rsdt->header.length - sizeof(rsdt_t)) / (use_xsdt() ? 8 : 4); 41 | 42 | for (uint64_t i = 0; i < entry_count; i++) { 43 | sdt_header_t *sdt = NULL; 44 | if (use_xsdt()) { 45 | sdt = (sdt_header_t *)(*((uint64_t *)rsdt->data + i) + HHDM_OFFSET); 46 | } else { 47 | sdt = (sdt_header_t *)(*((uint32_t *)rsdt->data + i) + HHDM_OFFSET); 48 | } 49 | 50 | if (memcmp(sdt->signature, signature, 4) != 0) { 51 | continue; 52 | } 53 | 54 | if (index > 0) { 55 | index--; 56 | continue; 57 | } 58 | 59 | printf("Found %s at %x\n", signature, sdt); 60 | return sdt; 61 | } 62 | printf("Cannot find %s", signature); 63 | return NULL; 64 | } 65 | -------------------------------------------------------------------------------- /src/acpi/acpi.h: -------------------------------------------------------------------------------- 1 | #ifndef acpi_h 2 | #define acpi_h 3 | #include 4 | 5 | typedef struct { 6 | char signature[8]; // This 8-byte string (not null terminated!) must contain 7 | // "RSD PTR " 8 | uint8_t checksum; // The value to add to calculate the Checksum of this 9 | // table. If this value added isn't equal to 0, the table 10 | // must be ignored. 11 | char oem_id[6]; // The specification says: "An OEM-supplied string that 12 | // identifies the OEM". 13 | uint8_t revision; // Version of ACPI. 14 | uint32_t rsdt_address; // 32-bit *physical* address of the RSDT table. 15 | // v2 16 | uint32_t length; // The size of the entire table since offset 0 to the end. 17 | uint64_t xsdt_address; // 64-bit *physical* address of XSDT. If ACPI Version 18 | // 2 use this table instead of RSDT. 19 | uint8_t 20 | extended_checksum; // This field is used to calculate the checksum of 21 | // the entire table, including both checksum fields. 22 | uint8_t reserved[3]; // 3 bytes to be ignored in reading and that must not 23 | // be written. 24 | } rsdp_descriptor_t; 25 | 26 | // https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf 27 | struct acpi_sdt_header { 28 | char signature[4]; // Used to determine what table are you working with. 29 | uint32_t length; // Length of table including header. 30 | uint8_t revision; // Revision of the structure corresponding to the 31 | // signature field for this table. 32 | uint8_t checksum; 33 | char oem_id[6]; 34 | char oem_table_id[6]; 35 | uint32_t oem_revision; 36 | uint32_t creator_id; // Vendor ID of utility that created the table. For 37 | // tables containing Definition Blocks, this is the ID 38 | // for the ASL Compiler. 39 | uint32_t creator_revision; 40 | }; 41 | typedef struct acpi_sdt_header sdt_header_t; 42 | 43 | typedef struct { 44 | sdt_header_t header; 45 | char data[]; 46 | } rsdt_t; 47 | 48 | void acpi_init(); 49 | void *acpi_find_sdt(char signature[4], uint64_t index); 50 | int use_xsdt(); 51 | #endif 52 | -------------------------------------------------------------------------------- /src/acpi/tables/madt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | vector_t madt_lapics; 9 | vector_t madt_ioapics; 10 | vector_t madt_isos; 11 | 12 | void madt_init() { 13 | madt_t *madt = acpi_find_sdt("APIC", 0); 14 | assert(madt); 15 | 16 | vector_create(&madt_lapics, sizeof(madt_lapic_t)); 17 | vector_create(&madt_ioapics, sizeof(madt_ioapic_t)); 18 | vector_create(&madt_isos, sizeof(madt_iso_t)); 19 | 20 | uint64_t offset = 0; 21 | 22 | while (1) { 23 | if (madt->header.length - sizeof(madt_t) - offset < 2) 24 | break; 25 | 26 | madt_header_t *header = (madt_header_t *)(madt->data + offset); 27 | 28 | switch (header->id) { 29 | case 0: 30 | madt_lapic_t *lapic = (madt_lapic_t *)header; 31 | printf("Found local LAPIC id: %d (%d)\n", lapic->apic_id, 32 | lapic->processor_id); 33 | vector_push(&madt_lapics, header); 34 | break; 35 | case 1: 36 | madt_ioapic_t *ioapic = (madt_ioapic_t *)header; 37 | printf("Found IO APIC id: %d\n", ioapic->header.id); 38 | vector_push(&madt_ioapics, header); 39 | break; 40 | case 2: 41 | madt_iso_t *isos = (madt_iso_t *)header; 42 | printf("Found ISO IRQ %d redirected to GSI %d\n", isos->irq_source, 43 | isos->gsi); 44 | vector_push(&madt_isos, header); 45 | break; 46 | default: 47 | break; 48 | } 49 | 50 | offset += MAX(header->length, 2); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/acpi/tables/madt.h: -------------------------------------------------------------------------------- 1 | #ifndef madt_h 2 | #define madt_h 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | typedef struct __attribute__((packed)) { 9 | sdt_header_t header; 10 | uint32_t local_controller_address; 11 | uint32_t flags; 12 | char data[]; 13 | } madt_t; 14 | 15 | typedef struct __attribute__((packed)) { 16 | uint8_t id; 17 | uint8_t length; 18 | } madt_header_t; 19 | 20 | typedef struct __attribute__((packed)) { 21 | madt_header_t header; 22 | uint8_t processor_id; 23 | uint8_t apic_id; 24 | uint32_t flags; 25 | } madt_lapic_t; 26 | 27 | typedef struct __attribute__((packed)) { 28 | madt_header_t header; 29 | uint8_t apic_id; 30 | uint8_t reserved; 31 | uint32_t address; 32 | uint32_t gsib; 33 | } madt_ioapic_t; 34 | 35 | typedef struct __attribute__((packed)) { 36 | madt_header_t header; 37 | uint8_t bus_source; 38 | uint8_t irq_source; 39 | uint32_t gsi; 40 | uint16_t flags; 41 | } madt_iso_t; 42 | 43 | typedef struct __attribute__((packed)) { 44 | madt_header_t header; 45 | uint8_t processor; 46 | uint16_t flags; 47 | uint8_t lint; 48 | } madt_nmi_t; 49 | 50 | void madt_init(); 51 | extern vector_t madt_ioapics; 52 | extern vector_t madt_isos; 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/dev/apic/ioapic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | uint32_t ioapic_read(uint64_t ioapic_address, uint64_t reg) { 11 | *((volatile uint32_t *)(ioapic_address + HHDM_OFFSET)) = reg; 12 | return *((volatile uint32_t *)(ioapic_address + HHDM_OFFSET + 0x10)); 13 | } 14 | 15 | void ioapic_write(uint64_t ioapic_address, uint64_t reg, uint32_t data) { 16 | *((volatile uint32_t *)(ioapic_address + HHDM_OFFSET)) = reg; 17 | *((volatile uint32_t *)(ioapic_address + HHDM_OFFSET + 0x10)) = data; 18 | } 19 | 20 | static uint64_t ioapic_gsi_count(madt_ioapic_t *ioapic) { 21 | return (ioapic_read((uint64_t)ioapic->address, 1) & 0xff0000) >> 16; 22 | } 23 | 24 | static madt_ioapic_t *ioapic_from_gsi(uint32_t gsi) { 25 | for (uint64_t i = 0; i < madt_ioapics.items; i++) { 26 | madt_ioapic_t *io_apic = vector_get(&madt_ioapics, i); 27 | if (gsi >= io_apic->gsib && 28 | gsi < io_apic->gsib + ioapic_gsi_count(io_apic)) { 29 | return io_apic; 30 | } 31 | } 32 | printf("Cannot find an IOAPIC from the given GSI\n"); 33 | assert(0); 34 | } 35 | 36 | void ioapic_redirect_gsi(uint32_t lapic_id, uint32_t gsi, uint8_t vector, 37 | uint64_t flags) { 38 | uint64_t ioredtbl_data = 39 | ((uint64_t)lapic_id << 56) | ((uint64_t)vector) | flags; 40 | madt_ioapic_t *ioapic = ioapic_from_gsi(gsi); 41 | uint64_t ioredtbl = (gsi - ioapic->gsib) * 2 + 0x10; 42 | ioapic_write(ioapic->address, ioredtbl, (uint32_t)ioredtbl_data); 43 | ioapic_write(ioapic->address, ioredtbl + 1, 44 | (uint32_t)(ioredtbl_data >> 32)); 45 | } 46 | 47 | void ioapic_redirect_irq(uint32_t lapic_id, uint8_t irq, uint8_t vector, 48 | uint64_t flags) { 49 | for (uint64_t i = 0; i < madt_isos.items; i++) { 50 | madt_iso_t *iso = vector_get(&madt_isos, i); 51 | if (iso->irq_source == irq) { 52 | ioapic_redirect_gsi(lapic_id, iso->gsi, vector, 53 | (uint64_t)iso->flags | flags); 54 | return; 55 | } 56 | } 57 | ioapic_redirect_gsi(lapic_id, (uint32_t)irq, vector, flags); 58 | } 59 | -------------------------------------------------------------------------------- /src/dev/apic/ioapic.h: -------------------------------------------------------------------------------- 1 | #ifndef ioapic_h 2 | #define ioapic_h 3 | 4 | #include 5 | 6 | #define IOAPIC_IOREGSEL 0x00 7 | #define IOAPIC_IOWIN 0x10 8 | 9 | uint32_t ioapic_read(uint64_t ioapic_address, uint64_t reg); 10 | void ioapic_write(uint64_t ioapic_address, uint64_t reg, uint32_t data); 11 | void ioapic_redirect_gsi(uint32_t lapic_id, uint32_t gsi, uint8_t vector, 12 | uint64_t flags); 13 | void ioapic_redirect_irq(uint32_t lapic_id, uint8_t irq, uint8_t vector, 14 | uint64_t flags); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/dev/apic/lapic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | spinlock_t lapic_lock; 12 | 13 | static inline uint64_t lapic_base() { 14 | return (rdmsr(0x1b) & 0xfffff000) + HHDM_OFFSET; 15 | } 16 | 17 | uint32_t lapic_read(uint32_t reg) { 18 | return *((volatile uint32_t *)(lapic_base() + reg)); 19 | } 20 | 21 | void lapic_write(uint32_t reg, uint32_t data) { 22 | *((volatile uint32_t *)(lapic_base() + reg)) = data; 23 | } 24 | 25 | void lapic_init() { 26 | // printf("%x\n",lapic_base()); 27 | lapic_write(LAPIC_SPURIOUS_IVR, 28 | lapic_read(LAPIC_SPURIOUS_IVR) | (1 << 8) | 0xff); 29 | lapic_calibrate(); 30 | } 31 | 32 | void lapic_eoi() { lapic_write(LAPIC_EOI, 0x00); } 33 | 34 | void lapic_ipi(uint32_t lapic_id, uint8_t vector) { 35 | lapic_write(LAPIC_ICR1, lapic_id << 24); 36 | lapic_write(LAPIC_ICR0, vector); 37 | } 38 | 39 | uint32_t lapic_id() { return lapic_read(LAPIC_APIC_ID); } 40 | 41 | void lapic_stop() { 42 | lapic_write(LAPIC_TIMER_INIT_COUNT, 0); 43 | lapic_write(LAPIC_LVT_TIMER_REG, 1 << 16); 44 | } 45 | 46 | void lapic_timer_oneshot(uint64_t ms, uint8_t vector) { 47 | asm volatile("cli"); 48 | 49 | lapic_stop(); 50 | uint64_t ticks = ms * (this_cpu()->lapic_freq / 1000); 51 | 52 | lapic_write(LAPIC_LVT_TIMER_REG, vector); 53 | lapic_write(LAPIC_TIMER_DIVIDE_CFG_REG, 0); 54 | lapic_write(LAPIC_TIMER_INIT_COUNT, ticks); 55 | 56 | asm volatile("sti"); 57 | } 58 | 59 | void lapic_calibrate() { 60 | spinlock_acquire(&lapic_lock); 61 | lapic_stop(); 62 | pit_set_reload_value(0xffff); 63 | uint16_t tick_first = pit_get_current_count(); 64 | 65 | lapic_write(LAPIC_TIMER_INIT_COUNT, 0xfffff); 66 | while (lapic_read(LAPIC_TIMER_COUNTER)) { 67 | } 68 | 69 | uint16_t tick_last = pit_get_current_count(); 70 | 71 | uint64_t tick_total = tick_first - tick_last; 72 | 73 | uint64_t freq = 0xfffff / tick_total * OSCILATOR_FREQ; 74 | // printf("%d freq",freq); 75 | 76 | this_cpu()->lapic_freq = freq; 77 | 78 | lapic_stop(); 79 | 80 | spinlock_release(&lapic_lock); 81 | } 82 | -------------------------------------------------------------------------------- /src/dev/apic/lapic.h: -------------------------------------------------------------------------------- 1 | #ifndef lapic_h 2 | #define lapic_h 3 | #include 4 | 5 | #define LAPIC_MSR 0x1b 6 | 7 | #define LAPIC_APIC_ID 0x20 8 | #define LAPIC_APIC_VERSION 0x30 9 | #define LAPIC_TPR 0x80 10 | #define LAPIC_APR 0x90 11 | #define LAPIC_PPR 0xa0 12 | #define LAPIC_EOI 0xb0 13 | #define LAPIC_RRD 0xc0 14 | #define LAPIC_LOGICAL_DESTINATION_REG 0xd0 15 | #define LAPIC_DESTINATION_FORMAT_REG 0xe0 16 | #define LAPIC_SPURIOUS_IVR 0xf0 17 | 18 | #define LAPIC_ISR0 0x100 19 | #define LAPIC_ISR1 0x110 20 | #define LAPIC_ISR2 0x120 21 | #define LAPIC_ISR3 0x130 22 | #define LAPIC_ISR4 0x140 23 | #define LAPIC_ISR5 0x150 24 | #define LAPIC_ISR6 0x160 25 | #define LAPIC_ISR7 0x170 26 | 27 | #define LAPIC_TMR0 0x180 28 | #define LAPIC_TMR1 0x190 29 | #define LAPIC_TMR2 0x1a0 30 | #define LAPIC_TMR3 0x1b0 31 | #define LAPIC_TMR4 0x1c0 32 | #define LAPIC_TMR5 0x1d0 33 | #define LAPIC_TMR6 0x1e0 34 | #define LAPIC_TMR7 0x1f0 35 | 36 | #define LAPIC_IRR0 0x200 37 | #define LAPIC_IRR1 0x210 38 | #define LAPIC_IRR2 0x220 39 | #define LAPIC_IRR3 0x230 40 | #define LAPIC_IRR4 0x240 41 | #define LAPIC_IRR5 0x250 42 | #define LAPIC_IRR6 0x260 43 | #define LAPIC_IRR7 0x270 44 | 45 | #define LAPIC_ERROR_REG 0x280 46 | #define LAPIC_LVT_CMCI_REGS 0x2f0 47 | #define LAPIC_ICR0 0x300 48 | #define LAPIC_ICR1 0x310 49 | 50 | #define LAPIC_LVT_TIMER_REG 0x320 51 | #define LAPIC_LVT_THERMAL_SENSOR_REG 0x330 52 | #define LAPIC_LVT_PERF_MON_CNT_REG 0x340 53 | #define LAPIC_LVT_LINT0 0x350 54 | #define LAPIC_LVT_LINT1 0x360 55 | #define LAPIC_LVT_ERROR_REG 0x370 56 | 57 | #define LAPIC_TIMER_INIT_COUNT 0x380 58 | #define LAPIC_TIMER_COUNTER 0x390 59 | #define LAPIC_TIMER_DIVIDE_CFG_REG 0x3e0 60 | 61 | uint32_t lapic_read(uint32_t reg); 62 | void lapic_write(uint32_t reg, uint32_t data); 63 | void lapic_init(); 64 | void lapic_ipi(uint32_t lapic_id, uint8_t vector); 65 | uint32_t lapic_id(); 66 | void lapic_calibrate(); 67 | void lapic_stop(); 68 | void lapic_timer_oneshot(uint64_t ms, uint8_t vector); 69 | void lapic_eoi(); 70 | #endif 71 | -------------------------------------------------------------------------------- /src/dev/console.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | spinlock_t console_lock = LOCK_INIT; 9 | static struct flanterm_context *term_context = NULL; 10 | 11 | void console_init() { 12 | struct limine_framebuffer_response *fb_response = fb_request.response; 13 | struct limine_framebuffer *fb = fb_response->framebuffers[0]; 14 | term_context = 15 | flanterm_fb_init(kheap_alloc, (void *)kheap_free, fb->address, 16 | fb->width, fb->height, fb->pitch, NULL, NULL, NULL, 17 | NULL, NULL, NULL, NULL, NULL, 0, 0, 1, 1, 1, 0); 18 | } 19 | 20 | void console_write(char *str) { 21 | if (term_context != NULL) { 22 | spinlock_acquire(&console_lock); 23 | flanterm_write(term_context, str, strlen(str)); 24 | spinlock_release(&console_lock); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/dev/console.h: -------------------------------------------------------------------------------- 1 | #ifndef console_h 2 | #define console_h 3 | void console_init(); 4 | void console_write(char *str); 5 | #endif 6 | -------------------------------------------------------------------------------- /src/dev/fb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | volatile struct limine_framebuffer_request fb_request = { 6 | .id = LIMINE_FRAMEBUFFER_REQUEST, .revision = 0}; 7 | 8 | struct limine_framebuffer *fb_address() { 9 | return fb_request.response->framebuffers[0]->address; 10 | } 11 | 12 | void fb_info() { 13 | struct limine_framebuffer *fb_addresss = fb_address(); 14 | printf("Our frame buffer is at virtual address: %x\n", fb_addresss); 15 | printf("Resolution: %dx%d\n", fb_request.response->framebuffers[0]->width, 16 | fb_request.response->framebuffers[0]->height); 17 | printf("Depth: %d\n", fb_request.response->framebuffers[0]->bpp); 18 | printf("\n"); 19 | } 20 | 21 | void plot_pixel(uint8_t *screen, uint64_t x, uint64_t y, uint32_t colour) { 22 | uint64_t pitch = fb_request.response->framebuffers[0]->pitch; 23 | uint64_t pix_wid = (fb_request.response->framebuffers[0]->bpp) / 8; 24 | unsigned where = x * pix_wid + y * pitch; 25 | screen[where] = colour & 255; // BLUE 26 | screen[where + 1] = (colour >> 8) & 255; // GREEN 27 | screen[where + 2] = (colour >> 16) & 255; // RED 28 | } 29 | 30 | void fb_colour_background() { 31 | uint8_t *fb_place = (uint8_t *)fb_address(); 32 | for (uint64_t x = 0; x < fb_request.response->framebuffers[0]->width; x++) { 33 | for (uint64_t y = 0; y < fb_request.response->framebuffers[0]->height; 34 | y++) { 35 | plot_pixel(fb_place, x, y, 0x8c4c4c); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/dev/fb.h: -------------------------------------------------------------------------------- 1 | #ifndef fb_h 2 | #define fb_h 3 | #include 4 | 5 | extern volatile struct limine_framebuffer_request fb_request; 6 | void fb_info(); 7 | struct limine_framebuffer *fb_address(void); 8 | void plot_pixel(uint8_t *screen, uint64_t x, uint64_t y, uint32_t colour); 9 | void fb_colour_background(); 10 | #endif 11 | -------------------------------------------------------------------------------- /src/dev/pit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static volatile uint64_t ticks = 0; 9 | uint16_t pit_get_current_count() { 10 | outb(0x43, 0x00); 11 | uint8_t lo = inb(0x40); 12 | uint8_t hi = inb(0x40); 13 | return ((uint16_t)hi << 8) | lo; 14 | } 15 | 16 | void pit_set_reload_value(uint16_t count) { 17 | asm("cli"); 18 | outb(0x43, 0x34); 19 | outb(0x40, (uint8_t)count); 20 | outb(0x40, (uint8_t)(count >> 8)); 21 | asm("sti"); 22 | } 23 | 24 | static void pit() { 25 | // printf("."); 26 | ticks++; 27 | 28 | lapic_eoi(); 29 | } 30 | void sleep(uint64_t ms) { 31 | uint64_t etick = ticks + ms; 32 | while (ticks < etick) { 33 | } 34 | } 35 | 36 | void pit_init() { 37 | isr[32] = pit; 38 | ioapic_redirect_irq(0, 0, 32, 0); 39 | uint16_t divisor = OSCILATOR_FREQ / TIMER_FREQ; 40 | pit_set_reload_value(divisor); 41 | 42 | printf("PIT initialized.\n"); 43 | } 44 | -------------------------------------------------------------------------------- /src/dev/pit.h: -------------------------------------------------------------------------------- 1 | #ifndef pit_h 2 | #define pit_h 3 | #include 4 | 5 | #define OSCILATOR_FREQ ((uint64_t)1193182) 6 | #define TIMER_FREQ 1000 7 | 8 | void pit_set_reload_value(uint16_t count); 9 | void pit_set_frequency(); 10 | void pit_init(); 11 | void sleep(uint64_t ms); 12 | uint16_t pit_get_current_count(); 13 | #endif 14 | -------------------------------------------------------------------------------- /src/dev/ps2/ps2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | uint8_t ps2_read() { 8 | while ((inb(0x64) & 1) == 0) 9 | ; 10 | return inb(0x60); 11 | } 12 | 13 | void ps2_write(uint16_t port, uint8_t value) { 14 | while ((inb(0x64) & 2) != 0) 15 | ; 16 | outb(port, value); 17 | } 18 | 19 | void ps2_init() { 20 | ps2_write(0x64, 0xad); 21 | ps2_write(0x64, 0xa7); 22 | 23 | inb(0x60); 24 | 25 | ps2_write(0x64, 0x20); 26 | // ps2_write(0x64,0xaa); 27 | // assert(ps2_read()==0x55); 28 | 29 | ps2_write(0x64, 0xae); 30 | 31 | ps2kb_init(); 32 | } 33 | -------------------------------------------------------------------------------- /src/dev/ps2/ps2.h: -------------------------------------------------------------------------------- 1 | #ifndef ps2_h 2 | #define ps2_h 3 | #include 4 | 5 | void ps2_init(); 6 | 7 | uint8_t ps2_read(); 8 | void ps2_write(uint16_t port, uint8_t value); 9 | #endif 10 | -------------------------------------------------------------------------------- /src/dev/ps2/ps2kb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static const char keymap[] = { 14 | '\0', '\e', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 15 | '-', '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 16 | 'o', 'p', '[', ']', '\n', '\0', 'a', 's', 'd', 'f', 'g', 'h', 17 | 'j', 'k', 'l', ';', '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v', 18 | 'b', 'n', 'm', ',', '.', '/', '\0', '\0', '\0', ' '}; 19 | 20 | void ps2kb_handler() { 21 | uint8_t scancode = ps2_read(); 22 | if (scancode < 0x57) { 23 | char c = keymap[scancode]; 24 | char str[2] = {c, '\0'}; 25 | printf("%s", str); 26 | } 27 | lapic_eoi(); 28 | } 29 | 30 | void ps2kb_init() { 31 | isr[33] = ps2kb_handler; 32 | ioapic_redirect_irq(0, 1, 33, 0); 33 | inb(0x60); 34 | } 35 | -------------------------------------------------------------------------------- /src/dev/ps2/ps2kb.h: -------------------------------------------------------------------------------- 1 | #ifndef ps2kb_h 2 | #define ps2kb_h 3 | void ps2kb_init(); 4 | #endif 5 | -------------------------------------------------------------------------------- /src/dev/serial.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void serial_init() { 6 | outb(PORT + 1, 0x00); 7 | outb(PORT + 3, 0x80); // Enable DLAB 8 | 9 | outb(PORT + 0, 0x01); // 115200 baud 10 | outb(PORT + 1, 0x00); 11 | 12 | outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit 13 | 14 | outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold 15 | outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set 16 | } 17 | 18 | static inline bool is_transmitter_empty() { 19 | return (inb(PORT + 5) & 0b01000000) != 0; 20 | } 21 | static inline void transmit_data(uint8_t value) { 22 | while (!is_transmitter_empty()) 23 | asm volatile("pause"); 24 | outb(PORT, value); 25 | } 26 | 27 | void serial_out(char *str) { 28 | static spinlock_t serial_lock = LOCK_INIT; 29 | spinlock_acquire(&serial_lock); 30 | while (*str) { 31 | if (*str == '\n') 32 | transmit_data('\r'); 33 | 34 | transmit_data(*str++); 35 | } 36 | spinlock_release(&serial_lock); 37 | } 38 | -------------------------------------------------------------------------------- /src/dev/serial.h: -------------------------------------------------------------------------------- 1 | #ifndef serial_h 2 | #define serial_h 3 | #define PORT 0x3f8 // COM1 4 | void serial_init(); 5 | void serial_out(char *str); 6 | #endif 7 | -------------------------------------------------------------------------------- /src/fs/ext2fs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct ext2fs_superblock { 5 | uint32_t inode_num; 6 | uint32_t block_num; 7 | uint32_t rsvd_num; 8 | uint32_t unallocb; 9 | uint32_t unalloci; 10 | uint32_t sb; 11 | uint32_t log2_blksize; 12 | uint32_t log2_fragsize; 13 | uint32_t blocks_per_group; 14 | uint32_t frags_per_group; 15 | uint32_t inodes_per_group; 16 | uint32_t last_mnt; // unix epoch for last mount 17 | uint32_t last_written; // unix epoch for last write 18 | uint16_t last_check_mounts; 19 | uint16_t 20 | mounts_allowed_before_check; // are we allowed to mount this filesystem? 21 | uint16_t ext2_sig; // ext signature 22 | uint16_t fss_tate; 23 | uint16_t errorr_action; 24 | uint16_t minor_version; 25 | uint32_t last_fsck; // last time we cleaned the filesystem 26 | uint32_t forced_fsck_time; 27 | uint32_t osid; 28 | uint32_t major_version; 29 | uint16_t uid; 30 | uint16_t gid; 31 | 32 | // extend superblock fields 33 | uint32_t first; 34 | uint16_t inode_size; 35 | uint16_t bg_sb; 36 | uint32_t optional_features; 37 | uint32_t required_features; 38 | uint32_t readonly_features; 39 | char uuid[16]; // filesystem uuid 40 | char name[16]; 41 | char lastmountedpath[64]; // last path we had when mounted 42 | uint32_t comp_algo; 43 | uint8_t blocks_prealloc_files; 44 | uint8_t blocks_prealloc_dirs; 45 | uint16_t unused; 46 | char journal_id[16]; 47 | uint32_t journal_inode; 48 | uint32_t journal_dev; 49 | uint32_t head_orphan_inode_list; 50 | 51 | } __attribute__((packed)); 52 | typedef struct ext2fs_superblock ext2fs_superblock_t; 53 | 54 | struct ext2fs_block_group_desc { 55 | uint32_t usage_bitmap; 56 | uint32_t inode_bitmap; 57 | uint32_t inode_table; 58 | uint16_t unalloc_blocks; 59 | uint16_t unalloc_inodes; 60 | uint16_t dirs; 61 | uint8_t unused[14]; 62 | } __attribute__((packed)); 63 | typedef struct ext2fs_block_group_desc ext2fs_block_group_desc_t; 64 | 65 | struct ext2fs_inode { 66 | uint16_t perms; 67 | uint16_t uid; 68 | uint32_t size_low; 69 | uint32_t last_acc; 70 | uint32_t create_time; 71 | uint32_t last_mod; 72 | uint32_t del_time; 73 | uint16_t gid; 74 | uint16_t hardlinks; 75 | uint32_t sectors; 76 | uint32_t flags; 77 | uint32_t ossv1; 78 | uint32_t blocks[15]; 79 | uint32_t generation_num; 80 | uint32_t eab; 81 | uint32_t size_high; 82 | uint32_t frag_addr; 83 | uint32_t ossv2[3]; 84 | 85 | } __attribute__((packed)); 86 | typedef struct ext2fs_inode ext2fs_inode_t; 87 | 88 | struct ext2fs_dir_entry { 89 | uint32_t inode; 90 | uint16_t entry_size; 91 | uint8_t name_length; 92 | uint8_t type; 93 | char name[]; 94 | } __attribute__((packed)); 95 | typedef struct ext2fs_dir_entry ext2fs_dir_entry_t; 96 | 97 | typedef struct { 98 | ext2fs_inode_t root; 99 | ext2fs_superblock_t sb; 100 | 101 | uint32_t block_size; 102 | uint32_t frag_size; 103 | 104 | } ext2fs_t; 105 | 106 | static vfs_node_t *ext2fs_mount(vfs_node_t *, vfs_node_t *, char *) { 107 | return NULL; 108 | } 109 | 110 | static vfs_node_t *ext2fs_create(vfs_node_t *, char *, int) { return NULL; } 111 | static int ext2fs_read(struct vfs_node *, void *, uint64_t, uint64_t) { 112 | return NULL; 113 | } 114 | 115 | static int ext2fs_write(struct vfs_node *, void *, uint64_t, uint64_t) { 116 | return NULL; 117 | } 118 | 119 | static vfs_fs_t ext2fs_calls = {.mount = ext2fs_mount, 120 | .create = ext2fs_create, 121 | .read = ext2fs_read, 122 | .write = ext2fs_write}; 123 | 124 | vfs_fs_t *ext2fs_funcs() { return &ext2fs_calls; } 125 | 126 | void ext2fs_init() {} 127 | -------------------------------------------------------------------------------- /src/fs/ext2fs.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef ext2fs_h 3 | #define ext2fs_h 4 | #include 5 | vfs_fs_t *ext2fs_funcs(); 6 | void ext2fs_init(); 7 | #endif 8 | -------------------------------------------------------------------------------- /src/fs/initramfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define TAR_FILE_TYPE_NORMAL '0' 12 | #define TAR_FILE_TYPE_HARD_LINK '1' 13 | #define TAR_FILE_TYPE_SYMLINK '2' 14 | #define TAR_FILE_TYPE_CHAR_DEV '3' 15 | #define TAR_FILE_TYPE_BLOCK_DEV '4' 16 | #define TAR_FILE_TYPE_DIRECTORY '5' 17 | #define TAR_FILE_TYPE_FIFO '6' 18 | #define TAR_FILE_TYPE_GNU_LONG_PATH 'L' 19 | 20 | struct tar_header { 21 | char filename[100]; 22 | char mode[8]; 23 | char uid[8]; 24 | char gid[8]; 25 | char size[12]; 26 | char mtime[12]; 27 | char chksum[8]; 28 | char typeflag; 29 | char link_name[100]; 30 | char magic[6]; 31 | char version[2]; 32 | char uname[32]; 33 | char gname[32]; 34 | char dev_major[8]; 35 | char dev_minor[8]; 36 | char prefix[155]; 37 | }; 38 | typedef struct tar_header tar_header_t; 39 | 40 | static volatile struct limine_module_request module_request = { 41 | .id = LIMINE_MODULE_REQUEST, .revision = 0}; 42 | 43 | static inline uint64_t oct2int(const char *str, int len) { 44 | uint64_t value = 0; 45 | while (*str && len > 0) { 46 | value = value * 8 + (*str++ - '0'); 47 | len--; 48 | } 49 | return value; 50 | } 51 | 52 | void initramfs_init() { 53 | struct limine_module_response *modules = module_request.response; 54 | if (modules == 0 || modules->module_count == 0) { 55 | assert(false); 56 | } 57 | struct limine_file *module = modules->modules[0]; 58 | tar_header_t *current_file = (tar_header_t *)module->address; 59 | while (memcmp(current_file->magic, "ustar", 5) == 0) { 60 | uint64_t size = oct2int(current_file->size, sizeof(current_file->size)); 61 | uint64_t mode = oct2int(current_file->mode, sizeof(current_file->mode)); 62 | char *name = current_file->filename; 63 | 64 | switch (current_file->typeflag) { 65 | case TAR_FILE_TYPE_NORMAL: { 66 | vfs_node_t *node = vfs_create(root, name, S_IFREG); 67 | // printf("New file: %s Size: %x Mode: %x Node: %x\n", name, size, 68 | // mode, node); 69 | assert(node); 70 | assert(node->fs->write(node, (void *)current_file + 512, size, 0) == 71 | (int)size); 72 | break; 73 | } 74 | case TAR_FILE_TYPE_DIRECTORY: { 75 | vfs_node_t *node = vfs_create(root, name, S_IFDIR); 76 | assert(node); 77 | // printf("New dir: %s Node: %x\n", name, node); 78 | break; 79 | } 80 | } 81 | pmm_free((void *)current_file - HHDM_OFFSET, 82 | (512 + ALIGN_UP(size, 512)) / FRAME_SIZE); 83 | current_file = (void *)current_file + 512 + ALIGN_UP(size, 512); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/fs/initramfs.h: -------------------------------------------------------------------------------- 1 | #ifndef initramfs_h 2 | #define initramfs_h 3 | 4 | void initramfs_init(); 5 | #endif 6 | -------------------------------------------------------------------------------- /src/fs/tmpfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static vfs_node_t *tmpfs_create(vfs_node_t *parent, char *name, mode_t mode) { 8 | vfs_fs_t *fs = tmpfs_funcs(); 9 | vfs_node_t *node = vfs_create_node(parent, name, fs, S_ISDIR(mode)); 10 | if (S_ISREG(mode)) { 11 | void *new_data = kheap_calloc(FRAME_SIZE); 12 | assert(new_data); 13 | node->data = new_data; 14 | } 15 | 16 | struct stat *st = &node->st; 17 | st->st_blksize = FRAME_SIZE; 18 | st->st_size = st->st_blksize; 19 | st->st_blocks = 1; 20 | st->st_mode = mode; 21 | st->st_nlink = 1; 22 | st->st_ino = node->fs->inode_number++; 23 | return node; 24 | } 25 | 26 | static int tmpfs_read(vfs_node_t *node, void *buff, uint64_t count, 27 | uint64_t offset) { 28 | uint64_t max = node->st.st_size - offset; 29 | if (count > max) 30 | count = max; 31 | 32 | spinlock_acquire(&node->lock); 33 | memcpy(buff, node->data + offset, count); 34 | spinlock_release(&node->lock); 35 | node->offset += count; 36 | 37 | return count; 38 | } 39 | 40 | static int tmpfs_write(vfs_node_t *node, void *buff, uint64_t count, 41 | uint64_t offset) { 42 | 43 | uint64_t page = (offset + count) / FRAME_SIZE; 44 | 45 | spinlock_acquire(&node->lock); 46 | if (node->st.st_blocks <= (off_t)page) { 47 | void *new = kheap_realloc(node->data, (page + 1) * FRAME_SIZE); 48 | assert(new); 49 | node->data = new; 50 | node->st.st_blocks = page + 1; 51 | node->st.st_size = offset + count; 52 | } 53 | memcpy(node->data + offset, buff, count); 54 | spinlock_release(&node->lock); 55 | 56 | return count; 57 | } 58 | 59 | static vfs_node_t *tmpfs_mount(vfs_node_t *node, vfs_node_t *dev, char *name) { 60 | (void)dev; 61 | vfs_fs_t *fs = tmpfs_funcs(); 62 | vfs_node_t *ret = tmpfs_create(node, name, S_IFDIR); 63 | node->fs = fs; 64 | return ret; 65 | } 66 | 67 | static vfs_fs_t tmpfs = {.mount = tmpfs_mount, 68 | .create = tmpfs_create, 69 | .read = tmpfs_read, 70 | .write = tmpfs_write}; 71 | 72 | vfs_fs_t *tmpfs_funcs() { return &tmpfs; } 73 | -------------------------------------------------------------------------------- /src/fs/tmpfs.h: -------------------------------------------------------------------------------- 1 | #ifndef tmpfs_h 2 | #define tmpfs_h 3 | #include 4 | 5 | vfs_fs_t *tmpfs_funcs(); 6 | #endif 7 | -------------------------------------------------------------------------------- /src/fs/vfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | spinlock_t vfs_lock = LOCK_INIT; 14 | vfs_node_t *root; 15 | hashmap_t filesystems; 16 | 17 | static vfs_node_t *reduce_node(vfs_node_t *node) { 18 | if (node->mountpoint) { 19 | return reduce_node(node->mountpoint); 20 | } 21 | if (node->link) { 22 | return reduce_node(node->link); 23 | } 24 | return node; 25 | } 26 | 27 | static void create_dot(vfs_node_t *parent, vfs_node_t *node) { 28 | vfs_node_t *dot = vfs_create_node(node, ".", node->fs, false); 29 | vfs_node_t *dotdot = vfs_create_node(node, ".", node->fs, false); 30 | 31 | dot->link = node; 32 | dotdot->link = parent; 33 | 34 | hashmap_set(node->children, ".", dot); 35 | hashmap_set(node->children, "..", dotdot); 36 | } 37 | 38 | typedef struct { 39 | vfs_node_t *parent; 40 | vfs_node_t *result; 41 | } path_to_node_t; 42 | 43 | static path_to_node_t path_to_node(vfs_node_t *parent, const char *path) { 44 | if (path == NULL || strlen(path) == 0) 45 | return (path_to_node_t){NULL, NULL}; 46 | uint64_t path_len = strlen(path); 47 | 48 | vfs_node_t *current_node; 49 | vfs_node_t *parent_node; 50 | if (!parent) { 51 | parent_node = root; 52 | } else { 53 | parent_node = parent; 54 | } 55 | current_node = parent_node = reduce_node(parent_node); 56 | uint64_t index = 0; 57 | 58 | if (path[index] == '/') 59 | current_node = reduce_node(root); 60 | 61 | for (; path[index] == '/'; index++) { 62 | if (index == path_len - 1) { 63 | return (path_to_node_t){parent_node, current_node}; 64 | } 65 | } 66 | 67 | char *new_path; 68 | bool dir = path[path_len - 1] == '/'; 69 | uint64_t amount = index + dir; 70 | if (amount) { 71 | new_path = kheap_alloc(path_len - (amount) + 1); 72 | memcpy(new_path, path + index, path_len - (amount)); 73 | new_path[path_len - (amount)] = '\0'; 74 | } else { 75 | new_path = strdup(path); 76 | } 77 | 78 | char *segment = strtok(new_path, "/"); 79 | 80 | while (segment != NULL) { 81 | current_node = hashmap_get(current_node->children, segment); 82 | 83 | segment = strtok(NULL, "/"); 84 | 85 | if (current_node) { 86 | if (current_node->children) { 87 | parent_node = current_node; 88 | } 89 | continue; 90 | } 91 | 92 | kheap_free(new_path); 93 | if (segment != NULL) 94 | return (path_to_node_t){NULL, NULL}; 95 | return (path_to_node_t){parent_node, NULL}; 96 | } 97 | 98 | return (path_to_node_t){parent_node, current_node}; 99 | } 100 | vfs_node_t *get_node(vfs_node_t *parent, const char *path) { 101 | path_to_node_t p2n_result = path_to_node(parent, path); 102 | 103 | return p2n_result.result; 104 | } 105 | 106 | vfs_node_t *path_to_parent(vfs_node_t *parent, const char *path) { 107 | path_to_node_t p2n_result = path_to_node(parent, path); 108 | if (p2n_result.parent == NULL) { 109 | return NULL; 110 | } 111 | return p2n_result.parent; 112 | } 113 | 114 | vfs_node_t *fd_to_node(int fd) { 115 | process_t *process = get_current_thread()->process; 116 | vfs_node_t *result = NULL; 117 | 118 | if (fd == AT_FDCWD) { 119 | result = process->cwd; 120 | } else { 121 | result = vector_get(process->fildes, (uint64_t)fd); 122 | } 123 | 124 | if (result == NULL) { 125 | errno = EBADF; 126 | } 127 | 128 | return result; 129 | } 130 | 131 | int node_to_fd(vfs_node_t *node) { 132 | process_t *process = get_current_thread()->process; 133 | int result; 134 | result = vector_get_index(process->fildes, (void *)node); 135 | if (result == -1) { 136 | errno = ENOENT; 137 | } 138 | return result; 139 | } 140 | 141 | vfs_node_t *vfs_create_node(vfs_node_t *parent, char *name, vfs_fs_t *fs, 142 | bool dir) { 143 | vfs_node_t *node = kheap_calloc(sizeof(vfs_node_t)); 144 | assert(node); 145 | node->name = kheap_alloc(strlen(name) + 1); 146 | assert(node->name); 147 | memcpy(node->name, name, strlen(name) + 1); 148 | node->fs = fs; 149 | if (dir) { 150 | node->children = kheap_alloc(sizeof(hashmap_t)); 151 | hashmap_create(node->children, 256); 152 | } 153 | 154 | if (!parent) 155 | parent = root; 156 | 157 | if (parent) { 158 | node->parent = parent; 159 | assert(hashmap_set(parent->children, name, node)); 160 | } 161 | 162 | return node; 163 | } 164 | 165 | vfs_node_t *vfs_open(vfs_node_t *parent, const char *path) { 166 | spinlock_acquire(&vfs_lock); 167 | process_t *process = get_current_thread()->process; 168 | path_to_node_t ret = path_to_node(parent, path); 169 | vfs_node_t *node = ret.result; 170 | 171 | if (node == NULL) { 172 | spinlock_release(&vfs_lock); 173 | errno = ENOENT; 174 | return NULL; 175 | } 176 | node = vector_replace(process->fildes, node, process->current_filde); 177 | process->current_filde++; 178 | spinlock_release(&vfs_lock); 179 | return node; 180 | } 181 | 182 | bool vfs_mount(vfs_node_t *parent, char *source, char *target, char *fs_name) { 183 | spinlock_acquire(&vfs_lock); 184 | vfs_fs_t *fs = hashmap_get(&filesystems, fs_name); 185 | path_to_node_t p2n_result; 186 | 187 | vfs_node_t *dev = NULL; 188 | if (source != NULL) { 189 | p2n_result = path_to_node(parent, source); 190 | dev = p2n_result.result; 191 | } 192 | 193 | p2n_result = path_to_node(parent, target); 194 | vfs_node_t *target_node = p2n_result.result; 195 | 196 | vfs_node_t *mount_node = fs->mount(target_node, dev, basename(target)); 197 | target_node->mountpoint = mount_node; 198 | create_dot(p2n_result.parent, mount_node); 199 | spinlock_release(&vfs_lock); 200 | return true; 201 | } 202 | 203 | vfs_node_t *vfs_create(vfs_node_t *parent, char *path, mode_t mode) { 204 | path_to_node_t p2n_result = path_to_node(parent, path); 205 | if (!p2n_result.parent) 206 | return NULL; 207 | if (p2n_result.result) 208 | return NULL; 209 | 210 | vfs_fs_t *target_fs = p2n_result.parent->fs; 211 | vfs_node_t *node = 212 | target_fs->create(p2n_result.parent, basename(path), mode); 213 | if (node == NULL) 214 | return NULL; 215 | 216 | if (S_ISDIR(mode)) 217 | create_dot(p2n_result.parent, node); 218 | return node; 219 | } 220 | 221 | int vfs_write(vfs_node_t *node, void *buff, uint64_t count, uint64_t offset) { 222 | int write_count = node->fs->write(node, buff, count, offset); 223 | return write_count; 224 | } 225 | 226 | int vfs_read(vfs_node_t *node, void *buff, uint64_t count, uint64_t offset) { 227 | int read_count = node->fs->read(node, buff, count, offset); 228 | return read_count; 229 | } 230 | 231 | void add_filesystem(vfs_fs_t *fs, char *fs_name) { 232 | spinlock_acquire(&vfs_lock); 233 | assert(hashmap_set(&filesystems, fs_name, fs)); 234 | spinlock_release(&vfs_lock); 235 | } 236 | 237 | void vfs_init() { 238 | root = vfs_create_node(NULL, "", NULL, true); 239 | hashmap_create(&filesystems, 64); 240 | assert(hashmap_set(&filesystems, "tmpfs", tmpfs_funcs())); 241 | assert(hashmap_set(&filesystems, "ext2fs", ext2fs_funcs())); 242 | vfs_mount(root, NULL, "/", "tmpfs"); 243 | } 244 | -------------------------------------------------------------------------------- /src/fs/vfs.h: -------------------------------------------------------------------------------- 1 | #ifndef vfs_h 2 | #define vfs_h 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct vfs_node; 9 | typedef struct vfs_fs { 10 | struct vfs_node *(*mount)(struct vfs_node *mountpoint, struct vfs_node *dev, 11 | char *name); 12 | struct vfs_node *(*create)(struct vfs_node *parent, char *name, int mode); 13 | int (*read)(struct vfs_node *node, void *buff, uint64_t count, 14 | uint64_t offset); 15 | int (*write)(struct vfs_node *node, void *buff, uint64_t count, 16 | uint64_t offset); 17 | uint64_t inode_number; 18 | } vfs_fs_t; 19 | 20 | typedef struct vfs_node { 21 | char *name; 22 | struct vfs_node *parent; 23 | hashmap_t *children; 24 | vfs_fs_t *fs; 25 | int pid; 26 | uint64_t seek; 27 | uint64_t file_size; 28 | struct vfs_node *mountpoint; 29 | struct vfs_node *link; 30 | void *data; 31 | struct stat st; 32 | int offset; 33 | spinlock_t lock; 34 | } vfs_node_t; 35 | 36 | vfs_node_t *vfs_create_node(vfs_node_t *parent, char *name, vfs_fs_t *fs, 37 | bool dir); 38 | void vfs_init(); 39 | void add_filesystem(vfs_fs_t *fs, char *fs_name); 40 | bool vfs_mount(vfs_node_t *parent, char *source, char *target, char *fs_name); 41 | vfs_node_t *vfs_create(vfs_node_t *parent, char *path, mode_t mode); 42 | int vfs_read(vfs_node_t *node, void *buff, uint64_t count, uint64_t offset); 43 | int vfs_write(vfs_node_t *node, void *buff, uint64_t count, uint64_t offset); 44 | vfs_node_t *vfs_open(vfs_node_t *parent, const char *path); 45 | vfs_node_t *fd_to_node(int fd); 46 | int node_to_fd(vfs_node_t *node); 47 | vfs_node_t *path_to_parent(vfs_node_t *parent, const char *path); 48 | vfs_node_t *get_node(vfs_node_t *parent, const char *path); 49 | extern vfs_node_t *root; 50 | #endif 51 | -------------------------------------------------------------------------------- /src/get-deps.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | set -e 4 | 5 | [ -f limine.h ] || curl -Lo limine.h https://github.com/limine-bootloader/limine/raw/trunk/limine.h 6 | [ -d flanterm ] || git clone https://github.com/mintsuki/flanterm.git --depth=1 7 | 8 | MLIBC_VERSION=4.0.0-rc1 9 | 10 | if ! [ -d mlibc-headers ]; then 11 | git clone https://github.com/managarm/mlibc.git 12 | cd mlibc 13 | git checkout ${MLIBC_VERSION} 14 | for f in ../../patches/mlibc/*; do patch -p1 < $f; done 15 | mkdir ../mlibc-build 16 | cd ../mlibc-build 17 | meson setup --cross-file ../../build-support/cross_file.txt --prefix=/ -Dheaders_only=true ../mlibc 18 | ninja 19 | DESTDIR=$(realpath ../mlibc-headers-out) ninja install 20 | cd .. 21 | mv mlibc-headers-out/include mlibc-headers 22 | rm -rf mlibc mlibc-build mlibc-headers-out 23 | fi 24 | -------------------------------------------------------------------------------- /src/kernel.c: -------------------------------------------------------------------------------- 1 | #include 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 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | void kernel_thread(); 24 | 25 | void _start(void) { 26 | serial_init(); 27 | printf("%sHello world! %s\n", cRED, cNONE); 28 | fb_info(); 29 | gdt_init(); 30 | idt_init(); 31 | pmm_init(); 32 | vmm_init(); 33 | kheap_init(); 34 | console_init(); 35 | acpi_init(); 36 | smp_init(); 37 | pit_init(); 38 | ps2_init(); 39 | vfs_init(); 40 | 41 | sched_init(kernel_thread); 42 | } 43 | 44 | void kernel_thread() { 45 | printf("%sHello world from kernel thread!%s\n", cRED, cNONE); 46 | initramfs_init(); 47 | 48 | printf("\nNothing to be done now...\n"); 49 | 50 | vfs_node_t *init_node = vfs_open(root, "/usr/bin/init"); 51 | assert(init_node); 52 | 53 | pagemap_t *user_pagemap = vmm_new_pagemap(); 54 | struct auxval init_aux, ld_aux; 55 | const char *ld_path; 56 | 57 | assert(elf_load(user_pagemap, init_node, &init_aux, &ld_path)); 58 | 59 | vfs_node_t *ld_node = vfs_open(root, ld_path); 60 | assert(ld_node); 61 | 62 | assert(elf_load(user_pagemap, ld_node, &ld_aux, NULL)); 63 | process_t *user_proc = sched_process(user_pagemap); 64 | 65 | const char *argv[] = {"/usr/bin/init", NULL}; 66 | const char *envp[] = {NULL}; 67 | 68 | sched_user_thread((void *)ld_aux.at_entry, NULL, user_proc, argv, envp, 69 | &init_aux); 70 | dequeue_and_die(); 71 | } 72 | -------------------------------------------------------------------------------- /src/lib/assert.h: -------------------------------------------------------------------------------- 1 | #ifndef assert_h 2 | #define assert_h 3 | #include 4 | 5 | #define assert(check) \ 6 | ({ \ 7 | if (!(check)) { \ 8 | printf("\n%sassert() failed in %s() (%s:%d)\n", cRED, __func__, \ 9 | __FILE__, __LINE__); \ 10 | for (;;) \ 11 | asm("hlt"); \ 12 | } \ 13 | }) 14 | #endif 15 | -------------------------------------------------------------------------------- /src/lib/elf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static inline bool check_headers(Elf64_Ehdr *header) { 10 | if (memcmp(header->e_ident, ELFMAG, 4)) 11 | return false; 12 | if (header->e_ident[EI_CLASS] != ELFCLASS64) 13 | return false; 14 | if (header->e_ident[EI_DATA] != ELFDATA2LSB) 15 | return false; 16 | if (header->e_machine != EM_X86_64) 17 | return false; 18 | if (header->e_version != EV_CURRENT) 19 | return false; 20 | return true; 21 | } 22 | 23 | bool elf_load(pagemap_t *pagemap, vfs_node_t *node, struct auxval *aux, 24 | const char **ld_path) { 25 | Elf64_Ehdr elf_header; 26 | 27 | if (vfs_read(node, &elf_header, sizeof(Elf64_Ehdr), 0) <= 0) 28 | return false; 29 | 30 | if (!check_headers(&elf_header)) 31 | return false; 32 | 33 | for (uint64_t i = 0; i < elf_header.e_phnum; i++) { 34 | Elf64_Phdr program_header; 35 | if (vfs_read(node, &program_header, sizeof(Elf64_Phdr), 36 | elf_header.e_phoff + i * elf_header.e_phentsize) <= 0) 37 | return false; 38 | 39 | switch (program_header.p_type) { 40 | case PT_LOAD: { 41 | 42 | /* 43 | uint64_t prot = PROT_READ; 44 | if (program_header.p_flags & PF_W) 45 | prot |= PROT_WRITE; 46 | if (program_header.p_flags & PF_X) 47 | prot |= PROT_EXEC; 48 | */ 49 | 50 | uint64_t unaligned = program_header.p_vaddr & (FRAME_SIZE - 1); 51 | uint64_t pages = 52 | ALIGN_UP(program_header.p_memsz + unaligned, FRAME_SIZE) / 53 | FRAME_SIZE; 54 | void *phys = pmm_calloc(pages); 55 | if (!phys) 56 | return false; 57 | 58 | vmm_map_pages(pagemap, (uintptr_t)phys, program_header.p_vaddr, 59 | PTE_PRESENT | PTE_WRITABLE | PTE_USER, pages); 60 | 61 | assert(vfs_read(node, phys + unaligned + HHDM_OFFSET, 62 | program_header.p_filesz, program_header.p_offset)); 63 | break; 64 | } 65 | case PT_INTERP: { 66 | void *path = kheap_calloc(program_header.p_filesz + 1); 67 | assert(path); 68 | assert(vfs_read(node, path, program_header.p_filesz, 69 | program_header.p_offset)); 70 | if (ld_path) 71 | *ld_path = path; 72 | break; 73 | } 74 | case PT_PHDR: { 75 | aux->at_phdr = program_header.p_vaddr; 76 | break; 77 | } 78 | } 79 | } 80 | aux->at_entry = elf_header.e_entry; 81 | aux->at_phent = elf_header.e_phentsize; 82 | aux->at_phnum = elf_header.e_phnum; 83 | return true; 84 | } 85 | -------------------------------------------------------------------------------- /src/lib/elf.h: -------------------------------------------------------------------------------- 1 | #ifndef elf_h 2 | #define elf_h 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct auxval { 9 | uint64_t at_entry; 10 | uint64_t at_phdr; 11 | uint64_t at_phent; 12 | uint64_t at_phnum; 13 | }; 14 | bool elf_load(pagemap_t *pagemap, vfs_node_t *node, struct auxval *aux, 15 | const char **ld_path); 16 | #endif 17 | -------------------------------------------------------------------------------- /src/lib/errno.h: -------------------------------------------------------------------------------- 1 | #ifndef errno_h 2 | #define errno_h 3 | 4 | #include 5 | #include 6 | 7 | #define errno (get_current_thread()->errno) 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/lib/hashmap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static inline uint64_t hash(char *key, uint64_t size) { 8 | uint64_t hash = 5381; 9 | for (uint64_t i = 0; i < size; i++) { 10 | uint8_t c = key[i]; 11 | hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ 12 | } 13 | return hash; 14 | } 15 | 16 | #define INDEX(KEY, ENTRY_COUNT) \ 17 | { hash(KEY, strlen(KEY)) % ENTRY_COUNT } 18 | 19 | static inline hashmap_entry_t *hashmap_entry_get(hashmap_t *hashmap, 20 | char *key) { 21 | uint64_t index = INDEX(key, hashmap->entry_count); 22 | hashmap_entry_t *entry = &hashmap->entries[index]; 23 | uint64_t key_length = strlen(key); 24 | while (entry) { 25 | if (key_length == entry->key_length) { 26 | if (!memcmp(entry->key, key, key_length)) 27 | break; 28 | } 29 | entry = entry->next; 30 | } 31 | return entry; 32 | } 33 | 34 | bool hashmap_create(hashmap_t *hashmap, uint64_t entry_count) { 35 | void *data = kheap_calloc(entry_count * sizeof(hashmap_entry_t)); 36 | if (!data) 37 | return false; 38 | hashmap->entries = data; 39 | hashmap->entry_count = entry_count; 40 | hashmap->items = 0; 41 | return true; 42 | } 43 | 44 | bool hashmap_set(hashmap_t *hashmap, char *key, void *val) { 45 | hashmap_entry_t *entry = hashmap_entry_get(hashmap, key); 46 | if (entry) { 47 | entry->val = val; 48 | return true; 49 | } 50 | // key is not in hashmap 51 | uint64_t index = INDEX(key, hashmap->entry_count); 52 | entry = &hashmap->entries[index]; 53 | while (true) { 54 | if (entry->next == NULL) 55 | break; 56 | entry = entry->next; 57 | } 58 | 59 | hashmap_entry_t *new_entry = kheap_calloc(sizeof(hashmap_entry_t)); 60 | if (!new_entry) 61 | return false; 62 | 63 | new_entry->key = key; 64 | new_entry->key_length = strlen(key); 65 | new_entry->val = val; 66 | new_entry->next = NULL; 67 | entry->next = new_entry; 68 | hashmap->items++; 69 | return true; 70 | } 71 | 72 | void *hashmap_get(hashmap_t *hashmap, char *key) { 73 | hashmap_entry_t *entry = hashmap_entry_get(hashmap, key); 74 | if (entry == NULL) { 75 | return 0; 76 | } 77 | return entry->val; 78 | } 79 | 80 | bool hashmap_remove(hashmap_t *hashmap, char *key) { 81 | uint64_t index = INDEX(key, hashmap->entry_count); 82 | hashmap_entry_t *entry = &hashmap->entries[index]; 83 | hashmap_entry_t *prev = NULL; 84 | uint64_t key_length = strlen(key); 85 | while (entry) { 86 | if (key_length == entry->key_length) { 87 | if (memcmp(entry->key, key, key_length)) 88 | break; 89 | } 90 | prev = entry; 91 | entry = entry->next; 92 | } 93 | 94 | if (prev) { 95 | prev->next = entry->next; 96 | kheap_free(entry); 97 | kheap_free(entry->key); 98 | } else if (entry->next) { 99 | memcpy(entry, entry->next, sizeof(hashmap_entry_t)); 100 | kheap_free(entry->next); 101 | } 102 | hashmap->items--; 103 | return true; 104 | } 105 | -------------------------------------------------------------------------------- /src/lib/hashmap.h: -------------------------------------------------------------------------------- 1 | #ifndef hashmap_h 2 | #define hashmap_h 3 | #include 4 | #include 5 | 6 | typedef struct hashmap_entry { 7 | struct hashmap_entry *next; 8 | uint64_t key_length; 9 | char *key; 10 | void *val; 11 | } hashmap_entry_t; 12 | 13 | typedef struct { 14 | hashmap_entry_t *entries; 15 | uint64_t entry_count; 16 | uint64_t items; 17 | } hashmap_t; 18 | 19 | bool hashmap_create(hashmap_t *hashmap, uint64_t item_count); 20 | bool hashmap_set(hashmap_t *hashmap, char *key, void *val); 21 | void *hashmap_get(hashmap_t *hashmap, char *key); 22 | bool hashmap_remove(hashmap_t *hashmap, char *key); 23 | bool hashmap_delete(hashmap_t *hashmap); 24 | #endif 25 | -------------------------------------------------------------------------------- /src/lib/io.h: -------------------------------------------------------------------------------- 1 | #ifndef io_h 2 | #define io_h 3 | #include 4 | 5 | static inline void outb(uint16_t port, uint8_t data) { 6 | asm volatile("outb %1, %0\n" : : "a"(data), "Nd"(port) : "memory"); 7 | } 8 | 9 | static inline void outw(uint16_t port, uint16_t data) { 10 | asm volatile("outw %1, %0\n" : : "a"(data), "Nd"(port) : "memory"); 11 | } 12 | 13 | static inline void outd(uint16_t port, uint32_t data) { 14 | asm volatile("outd %1, %0\n" : : "a"(data), "Nd"(port) : "memory"); 15 | } 16 | 17 | static inline uint8_t inb(uint16_t port) { 18 | uint8_t data; 19 | asm volatile("inb %0, %1\n" : "=a"(data) : "Nd"(port) : "memory"); 20 | return data; 21 | } 22 | 23 | static inline uint16_t inw(uint16_t port) { 24 | uint16_t data; 25 | asm volatile("inw %0, %1\n" : "=a"(data) : "Nd"(port) : "memory"); 26 | return data; 27 | } 28 | 29 | static inline uint32_t ind(uint16_t port) { 30 | uint32_t data; 31 | asm volatile("ind %0, %1\n" : "=a"(data) : "Nd"(port) : "memory"); 32 | return data; 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/lib/lock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int spinlock_test_and_acq(spinlock_t *lock) { return CAS(&lock->lock, 0, 1); } 6 | 7 | void spinlock_acquire(spinlock_t *lock) { 8 | uint64_t spinlock_count = 0; 9 | 10 | for (;;) { 11 | if (spinlock_test_and_acq(lock)) { 12 | break; 13 | } 14 | spinlock_count++; 15 | if (spinlock_count > 10000000) { 16 | printf("%s deadlock", lock->file); 17 | assert(0); 18 | } 19 | 20 | asm volatile("pause"); 21 | } 22 | } 23 | 24 | void spinlock_release(spinlock_t *lock) { CAS(&lock->lock, 1, 0); } 25 | -------------------------------------------------------------------------------- /src/lib/lock.h: -------------------------------------------------------------------------------- 1 | #ifndef lock_h 2 | #define lock_h 3 | #include 4 | #define CAS __sync_bool_compare_and_swap 5 | 6 | typedef struct { 7 | int lock; 8 | const char *file; 9 | } spinlock_t; 10 | 11 | #define LOCK_INIT \ 12 | (spinlock_t) { 0, __FILE__ } 13 | 14 | int spinlock_test_and_acq(spinlock_t *lock); 15 | void spinlock_acquire(spinlock_t *lock); 16 | void spinlock_release(spinlock_t *lock); 17 | #endif 18 | -------------------------------------------------------------------------------- /src/lib/stat.h: -------------------------------------------------------------------------------- 1 | #ifndef stat_h 2 | #define stat_h 3 | #include 4 | 5 | typedef int64_t ssize_t; 6 | typedef int64_t off_t; 7 | 8 | typedef uint64_t dev_t; 9 | typedef uint64_t ino_t; 10 | typedef int32_t mode_t; 11 | typedef int32_t nlink_t; 12 | typedef int64_t blksize_t; 13 | typedef int64_t blkcnt_t; 14 | 15 | typedef int32_t pid_t; 16 | typedef int32_t tid_t; 17 | typedef int32_t uid_t; 18 | typedef int32_t gid_t; 19 | 20 | typedef int64_t time_t; 21 | typedef int64_t clockid_t; 22 | 23 | struct timespec { 24 | time_t tv_sec; 25 | long tv_nsec; 26 | }; 27 | 28 | #define S_IFMT 0x0F000 29 | #define S_IFBLK 0x06000 30 | #define S_IFCHR 0x02000 31 | #define S_IFIFO 0x01000 32 | #define S_IFREG 0x08000 33 | #define S_IFDIR 0x04000 34 | #define S_IFLNK 0x0A000 35 | #define S_IFSOCK 0x0C000 36 | 37 | #define S_IRWXU 0700 38 | #define S_IRUSR 0400 39 | #define S_IWUSR 0200 40 | #define S_IXUSR 0100 41 | #define S_IRWXG 070 42 | #define S_IRGRP 040 43 | #define S_IWGRP 020 44 | #define S_IXGRP 010 45 | #define S_IRWXO 07 46 | #define S_IROTH 04 47 | #define S_IWOTH 02 48 | #define S_IXOTH 01 49 | #define S_ISUID 04000 50 | #define S_ISGID 02000 51 | #define S_ISVTX 01000 52 | 53 | #define S_IREAD S_IRUSR 54 | #define S_IWRITE S_IWUSR 55 | #define S_IEXEC S_IXUSR 56 | 57 | #define GETMODE(m) (0xFFF & m) 58 | #define GETTYPE(m) ((m >> 12) & 0xF) 59 | #define MAKETYPE(m) ((m & 0xF) << 12) 60 | 61 | typedef struct { 62 | dev_t st_dev; 63 | ino_t st_ino; 64 | mode_t st_mode; 65 | nlink_t st_nlink; 66 | uid_t st_uid; 67 | gid_t st_gid; 68 | dev_t st_rdev; 69 | off_t st_size; 70 | struct timespec st_atim; 71 | struct timespec st_mtim; 72 | struct timespec st_ctim; 73 | blksize_t st_blksize; 74 | blkcnt_t st_blocks; 75 | } stat; 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /src/lib/stddef.h: -------------------------------------------------------------------------------- 1 | #ifndef stddef_h 2 | #define stddef_h 3 | 4 | #define OFFSET_OF(TYPE, MEMBER) ((uint64_t) & ((TYPE *)0)->MEMBER) 5 | 6 | #define MAX(A, B) \ 7 | ({ \ 8 | __auto_type a = A; \ 9 | __auto_type b = B; \ 10 | a > b ? a : b; \ 11 | }) 12 | #define NULL 0 13 | 14 | #define ALIGN_UP(NUM, ALIGN) (((NUM) + ALIGN - 1) & ~(ALIGN - 1)) 15 | #define ALIGN_DOWN(NUM, ALIGN) ((NUM) & ~(ALIGN - 1)) 16 | #define CONTAINER_OF(PTR, TYPE, MEMBER) \ 17 | ((TYPE *)((void *)PTR - OFFSET_OF(TYPE, MEMBER))) 18 | 19 | #define BIT_SET(BIT) \ 20 | (bitmap[(BIT) / 8] |= (1 << ((BIT) % 8))) // sets BIT to one 21 | #define BIT_CLEAR(BIT) \ 22 | (bitmap[(BIT) / 8] &= ~(1 << ((BIT) % 8))) // sets BIT to zero 23 | #define BIT_TEST(BIT) \ 24 | ((bitmap[(BIT) / 8] >> ((BIT) % 8)) & 1) // returns the BIT 25 | #endif 26 | -------------------------------------------------------------------------------- /src/lib/stdio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | spinlock_t print_lock = LOCK_INIT; 10 | 11 | void out(char *str) { 12 | serial_out(str); 13 | console_write(str); 14 | } 15 | 16 | void printf(char *fmt, ...) { 17 | spinlock_acquire(&print_lock); 18 | va_list args; 19 | va_start(args, fmt); 20 | for (char *c = fmt; *c != '\0'; c++) { 21 | if (*c == '%') { 22 | c++; 23 | switch (*c) { 24 | case 's': 25 | out(va_arg(args, char *)); 26 | break; 27 | case 'd': 28 | out(itoa(va_arg(args, uint64_t), 10)); 29 | break; 30 | case 'x': 31 | out("0x"); 32 | out(itoa(va_arg(args, uint64_t), 16)); 33 | break; 34 | case 'b': 35 | out("0b"); 36 | out(itoa(va_arg(args, uint64_t), 2)); 37 | break; 38 | } 39 | } else { 40 | char str[] = {*c, '\0'}; 41 | out(str); 42 | } 43 | } 44 | va_end(args); // Not needed for GCC (or clang). Here for compatibility. 45 | spinlock_release(&print_lock); 46 | } 47 | -------------------------------------------------------------------------------- /src/lib/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef stdio_h 2 | #define stdio_h 3 | 4 | #include 5 | 6 | #define cRED "\033[1;31m" 7 | #define cBLUE "\033[1;34m" 8 | #define cNONE "\033[0m" 9 | #define cBLACK "\033[0;30m" 10 | 11 | void printf(char *str, ...); 12 | void put(char *str); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /src/lib/str.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int strlen(const char *f) { 7 | int ct = 0; 8 | for (; f[ct] != '\0'; ct++) 9 | ; 10 | return ct; 11 | } 12 | 13 | char *itoa(uint64_t num, int base) { 14 | static char repr[] = "0123456789abcdef"; 15 | static char buffer[50]; 16 | char *ptr; 17 | 18 | ptr = &buffer[49]; 19 | *ptr = '\0'; 20 | 21 | do { 22 | *--ptr = repr[num % base]; 23 | num /= base; 24 | } while (num != 0); 25 | 26 | return (ptr); 27 | } 28 | 29 | void memset(void *ptr, uint8_t n, uint64_t size) { 30 | assert(ptr); 31 | for (uint64_t i = 0; i < size; i++) { 32 | ((uint8_t *)ptr)[i] = (uint8_t)n; 33 | } 34 | } 35 | 36 | // returns 1 or -1 if not equal 37 | int memcmp(const void *s1, const void *s2, uint64_t size) { 38 | const uint8_t *p1 = (const uint8_t *)s1; 39 | const uint8_t *p2 = (const uint8_t *)s2; 40 | 41 | for (uint64_t i = 0; i < size; i++) 42 | if (p1[i] != p2[i]) { 43 | return p1[i] < p2[i] ? -1 : 1; // different (with comparison) 44 | } 45 | 46 | return 0; // equal 47 | } 48 | 49 | void memcpy(void *dest, const void *src, uint64_t n) { 50 | assert(src); 51 | assert(dest); 52 | for (uint64_t i = 0; i < n; i++) { 53 | ((uint8_t *)dest)[i] = ((const uint8_t *)src)[i]; 54 | } 55 | } 56 | 57 | bool strcmp(char *str1, char *str2) { 58 | if (strlen(str1) == strlen(str2) && !(memcmp(str1, str2, strlen(str1)))) { 59 | return 0; // same 60 | } 61 | return 1; 62 | } 63 | 64 | char *strchr(const char *str, char c) { 65 | 66 | while (*str != c) { 67 | if (!*str++) { 68 | return NULL; 69 | } 70 | } 71 | return (char *)str; 72 | } 73 | 74 | char *strtok(char *str, const char *delim) { 75 | static char *s = NULL; 76 | char *token; 77 | if (str != NULL) { 78 | s = str; 79 | } 80 | if (s == NULL) { 81 | return NULL; 82 | } 83 | token = s; 84 | while (*s != '\0') { 85 | if (strchr(delim, *s) != NULL) { 86 | *s = '\0'; 87 | s++; 88 | return token; 89 | } 90 | s++; 91 | } 92 | s = NULL; 93 | return token; 94 | } 95 | 96 | char *basename(char *s) { 97 | uint64_t i; 98 | // This empty string behavior is specified by POSIX. 99 | if (!s || !*s) 100 | return "."; 101 | i = strlen(s) - 1; 102 | for (; i && s[i] == '/'; i--) { 103 | s[i] = 0; 104 | } 105 | for (; i && s[i - 1] != '/'; i--) 106 | ; 107 | return s + i; 108 | } 109 | 110 | char *strdup(const char *str) { 111 | uint64_t l = strlen(str); 112 | char *d = kheap_alloc(l + 1); 113 | if (!d) 114 | return NULL; 115 | memcpy(d, str, l + 1); 116 | return d; 117 | } 118 | -------------------------------------------------------------------------------- /src/lib/str.h: -------------------------------------------------------------------------------- 1 | #ifndef str_h 2 | #define str_h 3 | #include 4 | #include 5 | 6 | char *strchr(const char *str, char c); 7 | char *strtok(char *str, const char *delim); 8 | int strlen(const char *f); 9 | char *itoa(uint64_t num, int base); 10 | void memset(void *ptr, uint8_t n, uint64_t size); 11 | int memcmp(const void *s1, const void *s2, uint64_t size); 12 | void memcpy(void *dest, const void *src, uint64_t n); 13 | bool strcmp(char *str1, char *str2); 14 | char *basename(char *path); 15 | char *strdup(const char *str); 16 | #endif 17 | -------------------------------------------------------------------------------- /src/lib/vector.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void vector_create(vector_t *vector, uint64_t item_size) { 7 | vector->items = 0; 8 | vector->item_size = item_size; 9 | vector->lock = LOCK_INIT; 10 | vector->data = 0; 11 | vector->capacity = 0; 12 | } 13 | 14 | uint64_t vector_size(vector_t *vector) { 15 | return vector->items * vector->item_size; 16 | } 17 | 18 | uint64_t vector_get_items(vector_t *vector) { 19 | spinlock_acquire(&vector->lock); 20 | uint64_t items = vector->items; 21 | spinlock_release(&vector->lock); 22 | return items; 23 | } 24 | 25 | void *vector_get(vector_t *vector, uint64_t index) { 26 | spinlock_acquire(&vector->lock); 27 | if (index >= vector->items) 28 | return 0; 29 | void *data = vector->data + (index * vector->item_size); 30 | spinlock_release(&vector->lock); 31 | return data; 32 | } 33 | 34 | void vector_push(vector_t *vector, void *data) { 35 | spinlock_acquire(&vector->lock); 36 | uint64_t vector_size = vector->items * vector->item_size; 37 | void *ptr = vector->data; 38 | if (vector->capacity < vector_size + vector->item_size) { 39 | ptr = kheap_realloc(vector->data, vector_size + vector->item_size); 40 | assert(ptr); 41 | vector->data = ptr; 42 | vector->capacity = vector_size + vector->item_size; 43 | } 44 | 45 | memcpy(ptr + vector_size, data, vector->item_size); 46 | vector->items++; 47 | spinlock_release(&vector->lock); 48 | } 49 | 50 | void vector_remove(vector_t *vector, uint64_t index) { 51 | spinlock_acquire(&vector->lock); 52 | if (index < vector->items) { 53 | memcpy(vector->data + (index * vector->item_size), 54 | vector->data + ((index + 1) * vector->item_size), 55 | vector->item_size * vector->items - (index * vector->item_size)); 56 | } 57 | vector->items--; 58 | spinlock_release(&vector->lock); 59 | } 60 | 61 | void vector_delete(vector_t *vector) { 62 | kheap_free(vector->data); 63 | kheap_free(vector); 64 | } 65 | 66 | void vector_pop(vector_t *vector) { 67 | spinlock_acquire(&vector->lock); 68 | vector->items--; 69 | spinlock_release(&vector->lock); 70 | } 71 | 72 | void *vector_replace(vector_t *vector, void *data, uint64_t index) { 73 | void *ptr = vector_get(vector, index); 74 | spinlock_acquire(&vector->lock); 75 | memcpy(ptr, data, vector->item_size); 76 | spinlock_release(&vector->lock); 77 | return ptr; 78 | } 79 | 80 | void vector_insert(vector_t *vector, void *data, uint64_t index) { 81 | spinlock_acquire(&vector->lock); 82 | uint64_t vector_size = vector->items * vector->item_size; 83 | if (vector->capacity < vector_size + vector->item_size) { 84 | void *ptr = 85 | kheap_realloc(vector->data, vector_size + vector->item_size); 86 | assert(ptr); 87 | vector->data = ptr; 88 | vector->capacity = (vector_size + vector->item_size); 89 | } 90 | memcpy(vector->data + ((index + 1) * vector->item_size), 91 | vector->data + (index * vector->item_size), 92 | (vector->item_size * (vector->items)) - (index * vector->item_size)); 93 | memcpy(vector->data + (index * vector->item_size), data, vector->item_size); 94 | vector->items += 1; 95 | spinlock_release(&vector->lock); 96 | } 97 | 98 | void vector_reserve(vector_t *vector, uint64_t new_cap) { 99 | spinlock_acquire(&vector->lock); 100 | if (vector->capacity < new_cap * vector->item_size) { 101 | uint64_t new_vector_size = new_cap * vector->item_size; 102 | void *ptr = kheap_realloc(vector->data, new_vector_size); 103 | assert(ptr); 104 | vector->data = ptr; 105 | vector->capacity = new_vector_size; 106 | } 107 | spinlock_release(&vector->lock); 108 | } 109 | 110 | void vector_resize(vector_t *vector, uint64_t items) { 111 | spinlock_acquire(&vector->lock); 112 | if (vector->capacity < items * vector->item_size) { 113 | uint64_t new_vector_size = items * vector->item_size; 114 | void *ptr = kheap_realloc(vector->data, new_vector_size); 115 | assert(ptr); 116 | vector->data = ptr; 117 | vector->capacity = new_vector_size; 118 | } 119 | vector->items = items; 120 | spinlock_release(&vector->lock); 121 | } 122 | 123 | int vector_get_index(vector_t *vector, void *data) { 124 | spinlock_acquire(&vector->lock); 125 | if (vector->data + vector->item_size * vector->items < data || 126 | data < vector->data) { 127 | return -1; 128 | } 129 | uint64_t index = (data - vector->data) / vector->item_size; 130 | spinlock_release(&vector->lock); 131 | return index; 132 | } 133 | -------------------------------------------------------------------------------- /src/lib/vector.h: -------------------------------------------------------------------------------- 1 | #ifndef vector_h 2 | #define vector_h 3 | #include 4 | #include 5 | 6 | typedef struct { 7 | uint64_t items; 8 | uint64_t item_size; 9 | uint64_t capacity; 10 | spinlock_t lock; 11 | void *data; 12 | 13 | } vector_t; 14 | 15 | void vector_create(vector_t *vector, uint64_t item_size); 16 | uint64_t vector_get_items(vector_t *vector); 17 | void *vector_get(vector_t *vector, uint64_t index); 18 | void vector_push(vector_t *vector, void *data); 19 | void vector_remove(vector_t *vector, uint64_t index); 20 | void vector_delete(vector_t *vector); 21 | uint64_t vector_size(vector_t *vector); 22 | void vector_resize(vector_t *vector, uint64_t items); 23 | void vector_pop(vector_t *vector); 24 | void *vector_replace(vector_t *vector, void *data, uint64_t index); 25 | int vector_get_index(vector_t *vector, void *data); 26 | void vector_insert(vector_t *vector, void *data, uint64_t index); 27 | void vector_reserve(vector_t *vector, uint64_t new_cap); 28 | #endif 29 | -------------------------------------------------------------------------------- /src/linker.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT(elf64-x86-64) 2 | 3 | ENTRY(_start) 4 | 5 | 6 | PHDRS 7 | { 8 | text PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */ 9 | rodata PT_LOAD FLAGS((1 << 2)) ; /* Read only */ 10 | data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */ 11 | } 12 | 13 | SECTIONS 14 | { 15 | . = 0xffffffff80000000; 16 | 17 | 18 | .text : { 19 | *(.text .text.*) 20 | } :text 21 | 22 | . += CONSTANT(MAXPAGESIZE); 23 | 24 | 25 | PROVIDE(symbol_table = 1); 26 | 27 | .rodata : { 28 | *(.rodata .rodata.*) 29 | } :rodata 30 | 31 | . += CONSTANT(MAXPAGESIZE); 32 | 33 | .data : { 34 | *(.data .data.*) 35 | } :data 36 | 37 | .bss : { 38 | *(COMMON) 39 | *(.bss .bss.*) 40 | } :data 41 | 42 | kernel_end_addr = .; 43 | 44 | /DISCARD/ : { 45 | *(.eh_frame) 46 | *(.note .note.*) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/makefile: -------------------------------------------------------------------------------- 1 | override KERNEL := $(BUILDDIR)kernel.elf 2 | CC:=x86_64-elf-gcc 3 | LD:=x86_64-elf-ld 4 | 5 | CFLAGS ?= -g -O2 -pipe -Wimplicit-function-declaration 6 | 7 | NASMFLAGS ?= -F dwarf -g -f elf64 8 | 9 | LDFLAGS ?= 10 | 11 | # Internal C flags that should not be changed by the user. 12 | override CFLAGS += \ 13 | -std=gnu11 \ 14 | -ffreestanding \ 15 | -fno-stack-protector \ 16 | -fno-stack-check \ 17 | -fno-lto \ 18 | -fno-pie \ 19 | -fno-pic \ 20 | -m64 \ 21 | -march=x86-64 \ 22 | -mabi=sysv \ 23 | -mno-80387 \ 24 | -mno-mmx \ 25 | -mno-sse \ 26 | -mno-sse2 \ 27 | -mno-red-zone \ 28 | -mcmodel=kernel \ 29 | -MMD \ 30 | -I. \ 31 | -idirafter mlibc-headers \ 32 | -Wall \ 33 | -Wextra \ 34 | -masm=intel 35 | 36 | # Internal linker flags that should not be changed by the user. 37 | override LDFLAGS += \ 38 | -nostdlib \ 39 | -static \ 40 | -m elf_x86_64 \ 41 | -z max-page-size=0x1000 \ 42 | -T linker.ld 43 | 44 | # Check if the linker supports -no-pie and enable it if it does 45 | ifeq ($(shell $(LD) --help 2>&1 | grep 'no-pie' >/dev/null 2>&1; echo $$?),0) 46 | override LDFLAGS += -no-pie 47 | endif 48 | 49 | # Internal nasm flags that should not be changed by the user. 50 | override NASMFLAGS += \ 51 | -f elf64 52 | 53 | BUILDPATH:=$(BUILDDIR) 54 | override CFILES := $(shell find . -type f -name '*.c') 55 | override NASMFILES := $(shell find . -type f -name '*.asm') 56 | override OBJ := $(addprefix $(BUILDDIR), $(CFILES:.c=.o) $(NASMFILES:.asm=.o)) 57 | override HEADER_DEPS:= $(addprefix $(BUILDDIR), $(CFILES:.c=.d) $(NASMFILES:.asm=.d)) 58 | DIRECTORY_GUARD = mkdir -p $(@D) 59 | 60 | .PHONY: all 61 | all: $(KERNEL) 62 | 63 | $(KERNEL): $(OBJ) 64 | $(LD) $(OBJ) $(LDFLAGS) -o $@ 65 | 66 | 67 | -include $(HEADER_DEPS) 68 | 69 | $(BUILDPATH)%.o: %.c 70 | $(DIRECTORY_GUARD) 71 | $(CC) $(CFLAGS) -c $< -o $@ 72 | 73 | $(BUILDPATH)%.o: %.asm 74 | $(DIRECTORY_GUARD) 75 | nasm $(NASMFLAGS) $< -o $@ 76 | 77 | .PHONY: clean 78 | clean: 79 | rm -rf $(BUILDDIR) 80 | 81 | -------------------------------------------------------------------------------- /src/memory/gdt/gdt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | gdt_entry_t gdt[11]; 7 | gdt_register_t gdtr; 8 | 9 | void gdt_load() { 10 | gdtr.limit = (sizeof(gdt) - 1); 11 | gdtr.base = (uint64_t)&gdt; 12 | extern void load_gdt(uint64_t gdtr); 13 | 14 | load_gdt((uint64_t)&gdtr); 15 | } 16 | void gdt_init() { 17 | 18 | gdt[0] = (gdt_entry_t){.limit = 0, 19 | .baselow16 = 0, 20 | .basemid8 = 0, 21 | .access = 0, 22 | .granularity = 0, 23 | .basehigh8 = 0}; 24 | 25 | // ring 0 gdt entries for the limine terminal (16-bit, 32-bit and 64-bit) 26 | 27 | gdt[1] = (gdt_entry_t){// ring 0 16 code 28 | .limit = 0xffff, .baselow16 = 0, .basemid8 = 0, 29 | .access = 0x9a, .granularity = 0, .basehigh8 = 0}; 30 | 31 | gdt[2] = (gdt_entry_t){// ring 0 16 data 32 | .limit = 0xffff, .baselow16 = 0, .basemid8 = 0, 33 | .access = 0x92, .granularity = 0, .basehigh8 = 0}; 34 | 35 | gdt[3] = 36 | (gdt_entry_t){// ring 0 32 code 37 | .limit = 0xffff, .baselow16 = 0, .basemid8 = 0, 38 | .access = 0x9a, .granularity = 0xcf, .basehigh8 = 0}; 39 | 40 | gdt[4] = 41 | (gdt_entry_t){// ring 0 32 data 42 | .limit = 0xffff, .baselow16 = 0, .basemid8 = 0, 43 | .access = 0x92, .granularity = 0xcf, .basehigh8 = 0}; 44 | 45 | // actual standard gdt entries follow (kernel, user) 46 | 47 | gdt[5] = (gdt_entry_t){// kernel 64 code 48 | .limit = 0, .baselow16 = 0, .basemid8 = 0, 49 | .access = 0x9a, .granularity = 0x20, .basehigh8 = 0}; 50 | 51 | gdt[6] = (gdt_entry_t){// kernel 64 data 52 | .limit = 0, .baselow16 = 0, .basemid8 = 0, 53 | .access = 0x92, .granularity = 0, .basehigh8 = 0}; 54 | 55 | gdt[7] = (gdt_entry_t){// user 64 data 56 | .limit = 0, .baselow16 = 0, .basemid8 = 0, 57 | .access = 0xf2, .granularity = 0, .basehigh8 = 0}; 58 | 59 | gdt[8] = (gdt_entry_t){// user 64 code 60 | .limit = 0, .baselow16 = 0, .basemid8 = 0, 61 | .access = 0xfa, .granularity = 0x20, .basehigh8 = 0}; 62 | 63 | gdt[9] = (gdt_entry_t){.limit = 104, 64 | .baselow16 = 0, 65 | .basemid8 = 0, 66 | .basehigh8 = 0, 67 | .access = 0x89, 68 | .granularity = 0x00}; 69 | gdt[10] = (gdt_entry_t){ 70 | .limit = 0, 71 | .baselow16 = 0, 72 | }; 73 | 74 | gdt_load(); 75 | printf("GDT initialized.\n"); 76 | } 77 | 78 | void gdt_load_tss(tss_t *tss) { 79 | static spinlock_t gdt_lock = LOCK_INIT; 80 | spinlock_acquire(&gdt_lock); 81 | gdt[9] = (gdt_entry_t){.limit = 104, 82 | .baselow16 = (uint16_t)((uint64_t)tss), 83 | .basemid8 = (uint8_t)((uint64_t)tss >> 16), 84 | .basehigh8 = (uint8_t)((uint64_t)tss >> 24), 85 | .access = 0x89, 86 | .granularity = 0x00}; 87 | gdt[10] = (gdt_entry_t){.limit = (uint16_t)((uint64_t)tss >> 32), 88 | .baselow16 = (uint16_t)((uint64_t)tss >> 48)}; 89 | asm volatile("ltr %0" : : "rm"((uint16_t)0x48) : "memory"); 90 | spinlock_release(&gdt_lock); 91 | } 92 | -------------------------------------------------------------------------------- /src/memory/gdt/gdt.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef gdt_h 4 | #define gdt_h 5 | 6 | #include 7 | 8 | typedef struct __attribute__((packed)) { 9 | uint16_t limit; 10 | uint16_t baselow16; 11 | uint8_t basemid8; 12 | uint8_t access; 13 | uint8_t granularity; 14 | uint8_t basehigh8; 15 | } gdt_entry_t; 16 | 17 | typedef struct __attribute__((packed)) { 18 | uint16_t limit; // length-1 19 | uint64_t base; // GDT BASE 20 | } gdt_register_t; 21 | 22 | void encodeGdtEntry(); 23 | void gdt_init(); 24 | void gdt_load(); 25 | void gdt_load_tss(tss_t *tss); 26 | #endif 27 | -------------------------------------------------------------------------------- /src/memory/gdt/loadgdt.asm: -------------------------------------------------------------------------------- 1 | global load_gdt 2 | load_gdt: 3 | cli 4 | lgdt [rdi] 5 | mov ax, 0x30 6 | MOV DS, AX 7 | MOV ES, AX 8 | MOV FS, AX 9 | MOV GS, AX 10 | MOV SS, AX 11 | pop rdi 12 | mov rax, 0x28 13 | push rax 14 | push rdi 15 | retfq 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/memory/kheap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define HEADER_SIZE 24 9 | static dll_t free_list = {.next = &free_list, .prev = &free_list}; 10 | spinlock_t kheap_lock = LOCK_INIT; 11 | 12 | void dll_list_add(dll_t *n, dll_t *prev, dll_t *next) { 13 | next->prev = n; 14 | n->next = next; 15 | n->prev = prev; 16 | prev->next = n; 17 | } 18 | 19 | void add_block(void *addr, uint64_t size) { 20 | alloc_node_t *block = (alloc_node_t *)addr; 21 | block->size = size - HEADER_SIZE; 22 | dll_list_add((dll_t *)&block->node, free_list.prev, &free_list); 23 | }; 24 | 25 | void coalesce_dll() { 26 | alloc_node_t *prevBlock = NULL; 27 | for (alloc_node_t *block = CONTAINER_OF(free_list.next, alloc_node_t, node); 28 | &block->node != &free_list; 29 | block = CONTAINER_OF(block->node.next, alloc_node_t, node)) { 30 | if (prevBlock != NULL && (alloc_node_t *)(prevBlock + prevBlock->size + 31 | HEADER_SIZE) == block) { 32 | prevBlock->size += block->size + HEADER_SIZE; 33 | // removes block 34 | block->node.next->prev = block->node.prev; 35 | block->node.prev->next = block->node.next; 36 | continue; 37 | } 38 | prevBlock = block; 39 | } 40 | } 41 | 42 | void *kheap_alloc(uint64_t size) { 43 | spinlock_acquire(&kheap_lock); 44 | void *ptr = NULL; 45 | alloc_node_t *block; 46 | // Try to find a big enough block to alloc (First fit) 47 | for (block = CONTAINER_OF(free_list.next, alloc_node_t, node); 48 | &block->node != &free_list; 49 | block = CONTAINER_OF(block->node.next, alloc_node_t, node)) { 50 | if (block->size >= size) { 51 | ptr = &block->cBlock; 52 | // printf("\nFound block for requested size at: %x\n",ptr); 53 | break; 54 | } 55 | } 56 | if (!ptr) { 57 | uint64_t frames = ALIGN_UP(size + HEADER_SIZE, FRAME_SIZE) / FRAME_SIZE; 58 | void *new = pmm_malloc(frames) + HHDM_OFFSET; 59 | add_block(new, frames * FRAME_SIZE); 60 | coalesce_dll(); 61 | spinlock_release(&kheap_lock); 62 | return kheap_alloc(size); 63 | } 64 | 65 | // Can block be split 66 | if ((block->size - size) >= HEADER_SIZE) { 67 | alloc_node_t *new_block = 68 | (alloc_node_t *)((uint64_t *)((char *)&block->cBlock + size)); 69 | new_block->size = block->size - size - HEADER_SIZE; 70 | block->size = size; 71 | // add new block to list 72 | dll_list_add(&new_block->node, &block->node, block->node.next); 73 | } 74 | // remove block from list since its getting allocated 75 | block->node.next->prev = block->node.prev; 76 | block->node.prev->next = block->node.next; 77 | spinlock_release(&kheap_lock); 78 | // Finally, return pointer to newly allocated adress 79 | return ptr; 80 | } 81 | 82 | void *kheap_calloc(uint64_t size) { 83 | void *ptr = kheap_alloc(size); 84 | if (ptr != NULL) { 85 | memset(ptr, 0, size); 86 | return ptr; 87 | } 88 | return NULL; 89 | } 90 | 91 | void kheap_free(void *ptr) { 92 | alloc_node_t *block, *free_block; 93 | 94 | spinlock_acquire(&kheap_lock); 95 | 96 | block = (void *)CONTAINER_OF(ptr, alloc_node_t, cBlock); 97 | if ((block->size + sizeof(alloc_node_t)) >= FRAME_SIZE && 98 | ((uint64_t)CONTAINER_OF(block, alloc_node_t, cBlock) % FRAME_SIZE) == 99 | 0) { 100 | pmm_free(CONTAINER_OF(block, alloc_node_t, cBlock) - HHDM_OFFSET, 101 | (block->size + sizeof(alloc_node_t)) / FRAME_SIZE); 102 | return; 103 | } 104 | 105 | for (free_block = CONTAINER_OF(free_list.next, alloc_node_t, node); 106 | &free_block->node != &free_list; 107 | free_block = CONTAINER_OF(free_block->node.next, alloc_node_t, node)) { 108 | if (free_block > block) { 109 | dll_list_add(&block->node, free_block->node.prev, 110 | &free_block->node); 111 | coalesce_dll(); // prevent fragmentation 112 | spinlock_release(&kheap_lock); 113 | return; 114 | } 115 | } 116 | dll_list_add(&block->node, &free_block->node, free_block->node.next); 117 | 118 | coalesce_dll(); // prevent fragmentation 119 | spinlock_release(&kheap_lock); 120 | return; 121 | } 122 | void *kheap_realloc(void *ptr, uint64_t new_size) { 123 | if (!ptr && !new_size) { 124 | return NULL; 125 | } 126 | if (!new_size) { 127 | kheap_free(ptr); 128 | return NULL; 129 | } 130 | if (!ptr) { 131 | return kheap_alloc(new_size); 132 | } 133 | alloc_node_t *node = CONTAINER_OF(ptr, alloc_node_t, cBlock); 134 | uint64_t old_size = node->size; 135 | void *ret = kheap_alloc(new_size); 136 | if (!ret) { 137 | return NULL; 138 | } 139 | memcpy(ret, ptr, old_size); 140 | return ret; 141 | } 142 | 143 | void kheap_init() { 144 | add_block(pmm_malloc(1) + HHDM_OFFSET, FRAME_SIZE); 145 | printf("Kernel heap initialized.\n"); 146 | } 147 | -------------------------------------------------------------------------------- /src/memory/kheap.h: -------------------------------------------------------------------------------- 1 | #ifndef kheap_h 2 | #define kheap_h 3 | #include 4 | #include 5 | 6 | typedef struct dll { 7 | struct dll *next; 8 | struct dll *prev; 9 | } dll_t; 10 | 11 | typedef struct alloc_node { 12 | dll_t node; 13 | uint64_t size; 14 | void *cBlock; 15 | } alloc_node_t; 16 | 17 | void dll_add(dll_t *n, dll_t *head); 18 | void add_block(void *addr, uint64_t size); 19 | void coalesce_dll(); 20 | 21 | void dll_list_add(dll_t *n, dll_t *prev, dll_t *next); 22 | 23 | void *kheap_alloc(uint64_t size); 24 | void *kheap_calloc(uint64_t size); 25 | void *kheap_realloc(void *ptr, uint64_t new_size); 26 | void kheap_free(void *ptr); 27 | void kheap_init(); 28 | #endif 29 | -------------------------------------------------------------------------------- /src/memory/pmm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | volatile struct limine_memmap_request memmap_request = { 11 | .id = LIMINE_MEMMAP_REQUEST, .revision = 0}; 12 | 13 | uint8_t *bitmap; 14 | uint64_t limit; 15 | 16 | spinlock_t pmm_lock = LOCK_INIT; 17 | 18 | void pmm_init() { 19 | uint64_t usable = 0; 20 | uint64_t available = 0; 21 | uint64_t highest = 0; 22 | struct limine_memmap_entry **mmaps = memmap_request.response->entries; 23 | uint64_t mmmap_count = memmap_request.response->entry_count; 24 | 25 | printf("There are %d entries in the mmap.\n", 26 | memmap_request.response->entry_count); 27 | for (uint64_t i = 0; i < mmmap_count; i++) { 28 | available += mmaps[i]->length; 29 | 30 | printf("entry %d base: %x length: %x type: %d tail: %x\n", 31 | i + 1, mmaps[i]->base, mmaps[i]->length, mmaps[i]->type, 32 | mmaps[i]->base + mmaps[i]->length); 33 | if (!mmaps[i]->type == LIMINE_MEMMAP_USABLE) { 34 | continue; 35 | } 36 | usable += mmaps[i]->length; 37 | uint64_t top = mmaps[i]->base + mmaps[i]->length; 38 | if (top > highest) 39 | highest = top; 40 | } 41 | limit = highest / FRAME_SIZE; 42 | uint64_t bitmap_size = ALIGN_UP(highest / FRAME_SIZE / 8, FRAME_SIZE); 43 | 44 | for (uint64_t i = 0; i < mmmap_count; i++) { 45 | if (!mmaps[i]->type == LIMINE_MEMMAP_USABLE) 46 | continue; 47 | ; 48 | if (mmaps[i]->length >= bitmap_size) { 49 | bitmap = (uint8_t *)mmaps[i]->base + HHDM_OFFSET; 50 | memset(bitmap, 0xff, bitmap_size); 51 | mmaps[i]->length -= bitmap_size; 52 | mmaps[i]->base += bitmap_size; 53 | available -= bitmap_size; 54 | break; 55 | } 56 | } 57 | for (uint64_t i = 0; i < mmmap_count; i++) { 58 | if (mmaps[i]->type != LIMINE_MEMMAP_USABLE) 59 | continue; 60 | 61 | for (uint64_t t = 0; t < mmaps[i]->length; t += FRAME_SIZE) { 62 | pmm_free((void *)mmaps[i]->base + t, 1); 63 | } 64 | } 65 | printf("%dMiB/%dMiB of usable memmory\n", usable / 1000 / 1000, 66 | available / 1000 / 1000); 67 | printf("PMM initialized.\n"); 68 | } 69 | 70 | void pmm_free(void *ptr, uint64_t frames) { 71 | spinlock_acquire(&pmm_lock); 72 | uint64_t frame = (uint64_t)ptr / FRAME_SIZE; 73 | for (uint64_t i = frame; i < frames + frame; i++) { 74 | BIT_CLEAR(i); 75 | } 76 | spinlock_release(&pmm_lock); 77 | } 78 | 79 | void *pmm_malloc(uint64_t wanted_frames) { 80 | spinlock_acquire(&pmm_lock); 81 | void *ptr; 82 | 83 | uint64_t available_frames = 0; 84 | for (uint64_t frame = 1; frame < limit; frame++) { 85 | if (!BIT_TEST(frame)) { 86 | available_frames++; 87 | } else if (available_frames != wanted_frames) { 88 | available_frames = 0; 89 | continue; 90 | } 91 | if (available_frames == wanted_frames) { 92 | uint64_t i; 93 | for (i = 0; i < wanted_frames; i++) { 94 | BIT_SET(frame - i); 95 | } 96 | frame -= i - 1; 97 | spinlock_release(&pmm_lock); 98 | 99 | ptr = (void *)(FRAME_SIZE * frame); 100 | return ptr; 101 | } 102 | } 103 | spinlock_release(&pmm_lock); 104 | return NULL; 105 | } 106 | 107 | void *pmm_calloc(uint64_t frames) { 108 | void *ptr = pmm_malloc(frames); 109 | memset(ptr + HHDM_OFFSET, 0, frames * FRAME_SIZE); 110 | return ptr; 111 | } 112 | 113 | void *pmm_alloc(uint64_t size) { 114 | uint64_t frames = (size + (FRAME_SIZE - 1)) / FRAME_SIZE; 115 | void *ptr = pmm_calloc(frames); 116 | assert(ptr); 117 | return ptr; 118 | } 119 | -------------------------------------------------------------------------------- /src/memory/pmm.h: -------------------------------------------------------------------------------- 1 | #ifndef pmm_h 2 | #define pmm_h 3 | #include 4 | #include 5 | void pmm_init(); 6 | 7 | void pmm_free(void *ptr, uint64_t frames); 8 | 9 | void *pmm_malloc(uint64_t frames); 10 | void *pmm_calloc(uint64_t frames); 11 | void *pmm_alloc(uint64_t size); 12 | 13 | #define FRAME_SIZE 0x1000 // 4096 bytes pages, 4kb 14 | 15 | extern volatile struct limine_memmap_request memmap_request; 16 | #endif 17 | -------------------------------------------------------------------------------- /src/memory/vmm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | spinlock_t vmm_lock; 11 | extern char kernel_end_addr[]; 12 | 13 | volatile struct limine_hhdm_request hhdm_request = {.id = LIMINE_HHDM_REQUEST, 14 | .revision = 0}; 15 | 16 | volatile struct limine_kernel_address_request kernel_address_request = { 17 | .id = LIMINE_KERNEL_ADDRESS_REQUEST, .revision = 0}; 18 | 19 | pagemap_t *kernel_pagemap; 20 | 21 | #define KERNEL_OFFSET kernel_address_request.response->virtual_base 22 | 23 | static uint64_t *get_next_level(uint64_t *current_level, uint64_t index) { 24 | if ((current_level[index] & 1) != 0) { 25 | return (uint64_t *)((current_level[index] & PTE_ADDR_MASK) + 26 | HHDM_OFFSET); 27 | } 28 | void *next = pmm_calloc(1); 29 | assert(next); 30 | current_level[index] = 31 | (uint64_t)next | PTE_PRESENT | PTE_WRITABLE | PTE_USER; 32 | return (uint64_t *)(next + HHDM_OFFSET); 33 | } 34 | 35 | void vmm_unmap_page(pagemap_t *pagemap, uintptr_t virtual_address) { 36 | 37 | spinlock_acquire(&vmm_lock); 38 | 39 | uint64_t pml4_index = (virtual_address & ((uint64_t)0x1ff << 39)) >> 39; 40 | uint64_t pml3_index = (virtual_address & ((uint64_t)0x1ff << 30)) >> 30; 41 | uint64_t pml2_index = (virtual_address & ((uint64_t)0x1ff << 21)) >> 21; 42 | uint64_t pml1_index = (virtual_address & ((uint64_t)0x1ff << 12)) >> 12; 43 | 44 | uint64_t *pml3 = get_next_level(pagemap->top, pml4_index); 45 | assert(pml3); 46 | uint64_t *pml2 = get_next_level(pml3, pml3_index); 47 | assert(pml2); 48 | uint64_t *pml1 = get_next_level(pml2, pml2_index); 49 | assert(pml1); 50 | 51 | pml1[pml1_index] = 0; 52 | 53 | asm volatile("invlpg [%0]" : : "r"(virtual_address) : "memory"); 54 | 55 | spinlock_release(&vmm_lock); 56 | } 57 | void vmm_map_page(pagemap_t *pagemap, uintptr_t physical_address, 58 | uintptr_t virtual_address, uint64_t flags) { 59 | 60 | spinlock_acquire(&vmm_lock); 61 | uint64_t pml4_index = (virtual_address & ((uint64_t)0x1ff << 39)) >> 39; 62 | uint64_t pml3_index = (virtual_address & ((uint64_t)0x1ff << 30)) >> 30; 63 | uint64_t pml2_index = (virtual_address & ((uint64_t)0x1ff << 21)) >> 21; 64 | uint64_t pml1_index = (virtual_address & ((uint64_t)0x1ff << 12)) >> 12; 65 | uint64_t *pml3 = get_next_level(pagemap->top, pml4_index); 66 | assert(pml3); 67 | uint64_t *pml2 = get_next_level(pml3, pml3_index); 68 | assert(pml2); 69 | uint64_t *pml1 = get_next_level(pml2, pml2_index); 70 | assert(pml1); 71 | 72 | pml1[pml1_index] = physical_address | flags; 73 | 74 | spinlock_release(&vmm_lock); 75 | } 76 | 77 | void vmm_map_pages(pagemap_t *pagemap, uintptr_t physical_address, 78 | uintptr_t virtual_address, uint64_t flags, uint64_t pages) { 79 | for (uint64_t i = 0; i < pages; i++) { 80 | vmm_map_page(pagemap, physical_address + (i * FRAME_SIZE), 81 | virtual_address + (i * FRAME_SIZE), flags); 82 | } 83 | } 84 | 85 | void vmm_switch_pagemap(pagemap_t *pagemap) { 86 | uint64_t *top = (void *)pagemap->top - HHDM_OFFSET; 87 | asm volatile("mov cr3, %0\n" : : "r"(top) : "memory"); 88 | } 89 | 90 | pagemap_t *vmm_new_pagemap() { 91 | pagemap_t *pagemap = pmm_alloc(sizeof(pagemap_t)) + HHDM_OFFSET; 92 | 93 | assert(pagemap); 94 | pagemap->top = pmm_calloc(1); 95 | 96 | assert(pagemap->top); 97 | 98 | pagemap->top = (void *)pagemap->top + HHDM_OFFSET; 99 | for (uint64_t i = 256; i < 512; i++) { 100 | pagemap->top[i] = kernel_pagemap->top[i]; 101 | } 102 | 103 | return pagemap; 104 | } 105 | 106 | void vmm_init() { 107 | printf("Our kernel's physical base: %x\n", 108 | kernel_address_request.response->physical_base); 109 | printf("Our kernel's virtual base: %x\n", KERNEL_OFFSET); 110 | printf("Our HHDM offset is %x\n", HHDM_OFFSET); 111 | 112 | kernel_pagemap = pmm_alloc(sizeof(kernel_pagemap)) + HHDM_OFFSET; 113 | kernel_pagemap->top = pmm_calloc(1); 114 | assert(kernel_pagemap->top); 115 | 116 | kernel_pagemap->top = (void *)kernel_pagemap->top + HHDM_OFFSET; 117 | 118 | uintptr_t virtual = kernel_address_request.response->virtual_base; 119 | uintptr_t physical = kernel_address_request.response->physical_base; 120 | uint64_t length = ALIGN_UP((uintptr_t)kernel_end_addr, FRAME_SIZE) - 121 | virtual; 122 | 123 | for (uint64_t i = 0; i < length; i += FRAME_SIZE) { 124 | vmm_map_page(kernel_pagemap, physical + i, virtual + i, 125 | PTE_PRESENT | PTE_WRITABLE); 126 | } 127 | 128 | // 4gb 129 | for (uintptr_t i = 0x1000; i < 0x100000000; i += FRAME_SIZE) { 130 | vmm_map_page(kernel_pagemap, i, i, PTE_PRESENT | PTE_WRITABLE); 131 | vmm_map_page(kernel_pagemap, i, i + HHDM_OFFSET, 132 | PTE_PRESENT | PTE_WRITABLE); 133 | } 134 | 135 | /* 136 | struct limine_memmap_entry **mmaps = memmap_request.response->entries; 137 | uint64_t mmmap_count = memmap_request.response->entry_count; 138 | 139 | for (int i = 0; i < mmmap_count; i++){ 140 | uint64_t base = ALIGN_DOWN(mmaps[i]->base,FRAME_SIZE); 141 | uint64_t tail = ALIGN_UP(mmaps[i]->base+mmaps[i]->length,FRAME_SIZE); 142 | 143 | if (base<0x100000000){continue;} 144 | 145 | for (uint64_t k = base; k < tail; k++){ 146 | vmm_map_page(kernel_pagemap, k, k, 0b11); 147 | vmm_map_page(kernel_pagemap, k, k + HHDM_OFFSET, 0b111); 148 | } 149 | 150 | } 151 | */ 152 | vmm_switch_pagemap(kernel_pagemap); 153 | printf("VMM intilasized.\n"); 154 | } 155 | 156 | uint64_t *virt_to_pte(pagemap_t *pagemap, uint64_t virtual_address) { 157 | uint64_t pml4_index = (virtual_address & ((uint64_t)0x1ff << 39)) >> 39; 158 | uint64_t pml3_index = (virtual_address & ((uint64_t)0x1ff << 30)) >> 30; 159 | uint64_t pml2_index = (virtual_address & ((uint64_t)0x1ff << 21)) >> 21; 160 | uint64_t pml1_index = (virtual_address & ((uint64_t)0x1ff << 12)) >> 12; 161 | 162 | uint64_t *pml3 = get_next_level(pagemap->top, pml4_index); 163 | assert(pml3); 164 | uint64_t *pml2 = get_next_level(pml3, pml3_index); 165 | assert(pml2); 166 | uint64_t *pml1 = get_next_level(pml2, pml2_index); 167 | assert(pml1); 168 | 169 | return &pml1[pml1_index]; 170 | } 171 | 172 | uint64_t virt_to_phys(pagemap_t *pagemap, uint64_t virtual_address) { 173 | uint64_t *pte = virt_to_pte(pagemap, virtual_address); 174 | return *pte & PTE_ADDR_MASK; 175 | } 176 | -------------------------------------------------------------------------------- /src/memory/vmm.h: -------------------------------------------------------------------------------- 1 | #ifndef vmm_h 2 | #define vmm_h 3 | #include 4 | #include 5 | 6 | typedef struct { 7 | uint64_t *top; 8 | } pagemap_t; 9 | 10 | #define USER_SPACE_END (void *)0x00007FFFFFFFFFFF 11 | 12 | #define PTE_ADDR_MASK 0x000ffffffffff000 13 | #define PTE_PRESENT (1ull << 0ull) 14 | #define PTE_WRITABLE (1ull << 1ull) 15 | #define PTE_USER (1ull << 2ull) 16 | #define PTE_NX (1ull << 63ull) 17 | 18 | void vmm_init(); 19 | void vmm_switch_pagemap(pagemap_t *pagemap); 20 | void vmm_map_page(pagemap_t *pagemap, uintptr_t hysical_address, 21 | uintptr_t virtual_address, uint64_t flags); 22 | void vmm_unmap_page(pagemap_t *pagemap, uintptr_t virtual_address); 23 | pagemap_t *new_pagemap(); 24 | pagemap_t *vmm_new_pagemap(); 25 | void vmm_map_pages(pagemap_t *pagemap, uintptr_t physical_address, 26 | uintptr_t virtual_address, uint64_t flags, uint64_t pages); 27 | uint64_t *virt_to_pte(pagemap_t *pagemap, uint64_t virtual_address); 28 | uint64_t virt_to_phys(pagemap_t *pagemap, uint64_t virtual_address); 29 | 30 | extern volatile struct limine_hhdm_request hhdm_request; 31 | #define HHDM_OFFSET (hhdm_request.response->offset) 32 | extern pagemap_t *kernel_pagemap; 33 | #endif 34 | -------------------------------------------------------------------------------- /src/proc/sched.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define SCHED_VECTOR 34 14 | process_t *kernel_process; 15 | vector_t processes_vector; 16 | 17 | sched_queue_t queue = {.lock = LOCK_INIT, .start = NULL, .end = NULL}; 18 | 19 | thread_t *get_current_thread() { return this_cpu()->current_thread; } 20 | 21 | static __attribute__((__noreturn__)) void switch_to_thread(thread_t *thread) { 22 | thread->running = 1; 23 | interrupt_frame_t *state = thread->state; 24 | 25 | asm volatile("mov rsp, %0\n" 26 | "pop rax\n" 27 | "mov es, eax\n" 28 | "pop rax\n" 29 | "mov ds, eax\n" 30 | "pop r15\n" 31 | "pop r14\n" 32 | "pop r13\n" 33 | "pop r12\n" 34 | "pop r11\n" 35 | "pop r10\n" 36 | "pop r9\n" 37 | "pop r8\n" 38 | "pop rbp\n" 39 | "pop rdi\n" 40 | "pop rsi\n" 41 | "pop rdx\n" 42 | "pop rcx\n" 43 | "pop rbx\n" 44 | "pop rax\n" 45 | "add rsp, 8\n" 46 | "swapgs\n" 47 | "iretq\n" 48 | : 49 | : "rm"(state) 50 | : "memory"); 51 | __builtin_unreachable(); 52 | } 53 | 54 | process_t *sched_process(pagemap_t *pagemap) { 55 | process_t *proc = kheap_alloc(sizeof(process_t)); 56 | assert(proc); 57 | vector_push(&processes_vector, proc); 58 | vector_t *threads = kheap_alloc(sizeof(vector_t)); 59 | vector_create(threads, sizeof(thread_t)); 60 | proc->threads = threads; 61 | proc->pagemap = pagemap; 62 | proc->fildes = kheap_alloc(sizeof(vector_t)); 63 | vector_create(proc->fildes, sizeof(vfs_node_t)); 64 | vector_resize(proc->fildes, MAX_FILDES); 65 | proc->cwd = root; 66 | proc->thread_stack_top = 0x70000000000; 67 | proc->anon_base = 0x80000000000; 68 | return proc; 69 | } 70 | 71 | bool sched_enqueue_thread(thread_t *thread) { 72 | if (thread->enqueued == true) 73 | return true; 74 | 75 | spinlock_acquire(&queue.lock); 76 | if (queue.start == NULL || queue.end == NULL) { 77 | queue.start = thread; 78 | queue.end = thread; 79 | } 80 | thread->prev = queue.end; 81 | 82 | queue.end->next = thread; 83 | queue.end = thread; 84 | thread->next = queue.start; 85 | queue.start->prev = thread; 86 | 87 | spinlock_release(&queue.lock); 88 | thread->enqueued = true; 89 | return true; 90 | } 91 | 92 | thread_t *sched_user_thread(void *start, void *arg, process_t *process, 93 | const char **argv, const char **envp, 94 | struct auxval *aux) { 95 | thread_t *thread = kheap_calloc(sizeof(thread_t)); 96 | thread->lock = LOCK_INIT; 97 | thread->state = kheap_calloc(sizeof(interrupt_frame_t)); 98 | interrupt_frame_t *state = thread->state; 99 | void *stack_phys = pmm_alloc(STACK_SIZE); 100 | assert(stack_phys); 101 | uint64_t pages = ALIGN_UP(STACK_SIZE, FRAME_SIZE) / FRAME_SIZE + 1; 102 | vmm_map_pages(process->pagemap, (uintptr_t)stack_phys, 103 | process->thread_stack_top - STACK_SIZE, 104 | PTE_PRESENT | PTE_WRITABLE | PTE_USER, pages); 105 | state->rsp = (uint64_t)process->thread_stack_top; 106 | process->thread_stack_top -= STACK_SIZE - FRAME_SIZE; 107 | state->cs = 0x40 | 3; 108 | state->ds = state->es = state->ss = 0x38 | 3; 109 | state->rflags = 0x202; 110 | state->rip = (uint64_t)start; 111 | state->rdi = (uint64_t)arg; 112 | thread->process = process; 113 | thread->timeslice = TIME_QUANTUM; 114 | thread->cr3 = (uint64_t)process->pagemap->top - HHDM_OFFSET; 115 | 116 | // Code from https://github.com/Lyre-OS/Lyre/ 117 | if (process->threads->items == 0) { 118 | uintptr_t *stack = stack_phys + STACK_SIZE + HHDM_OFFSET; 119 | void *stack_top = stack; 120 | 121 | int envp_len; 122 | for (envp_len = 0; envp[envp_len] != NULL; envp_len++) { 123 | uint64_t length = strlen(envp[envp_len]); 124 | stack = (void *)stack - length - 1; 125 | memcpy(stack, envp[envp_len], length); 126 | } 127 | 128 | int argv_len; 129 | for (argv_len = 0; argv[argv_len] != NULL; argv_len++) { 130 | uint64_t length = strlen(argv[argv_len]); 131 | stack = (void *)stack - length - 1; 132 | memcpy(stack, argv[argv_len], length); 133 | } 134 | 135 | stack = (uintptr_t *)ALIGN_DOWN((uintptr_t)stack, 16); 136 | if (((argv_len + envp_len + 1) & 1) != 0) { 137 | stack--; 138 | } 139 | 140 | // Auxilary vector 141 | *(--stack) = 0, *(--stack) = 0; 142 | stack -= 2; 143 | stack[0] = AT_ENTRY, stack[1] = aux->at_entry; 144 | stack -= 2; 145 | stack[0] = AT_PHDR, stack[1] = aux->at_phdr; 146 | stack -= 2; 147 | stack[0] = AT_PHENT, stack[1] = aux->at_phent; 148 | stack -= 2; 149 | stack[0] = AT_PHNUM, stack[1] = aux->at_phnum; 150 | 151 | uintptr_t old_rsp = thread->state->rsp; 152 | 153 | // Environment variables 154 | *(--stack) = 0; 155 | stack -= envp_len; 156 | for (int i = 0; i < envp_len; i++) { 157 | old_rsp -= strlen(envp[i]) + 1; 158 | stack[i] = old_rsp; 159 | } 160 | 161 | // Arguments 162 | *(--stack) = 0; 163 | stack -= argv_len; 164 | for (int i = 0; i < argv_len; i++) { 165 | old_rsp -= strlen(argv[i]) + 1; 166 | stack[i] = old_rsp; 167 | } 168 | 169 | *(--stack) = argv_len; 170 | 171 | thread->state->rsp -= stack_top - (void *)stack; 172 | } 173 | vector_push(process->threads, thread); 174 | sched_enqueue_thread(thread); 175 | return thread; 176 | } 177 | 178 | thread_t *sched_kernel_thread(void *start, void *args) { 179 | thread_t *thread = kheap_calloc(sizeof(thread_t)); 180 | thread->lock = LOCK_INIT; 181 | thread->state = kheap_calloc(sizeof(interrupt_frame_t)); 182 | interrupt_frame_t *state = thread->state; 183 | void *stack = pmm_alloc(STACK_SIZE); 184 | assert(stack); 185 | state->rsp = (uint64_t)stack + STACK_SIZE + HHDM_OFFSET; 186 | state->cs = 0x28; 187 | state->ds = state->es = state->ss = 0x30; 188 | state->rflags = 0x202; 189 | state->rip = (uint64_t)start; 190 | state->rdi = (uint64_t)args; 191 | thread->process = kernel_process; 192 | vector_push(kernel_process->threads, thread); 193 | thread->timeslice = TIME_QUANTUM; 194 | thread->cr3 = (uint64_t)kernel_process->pagemap->top - HHDM_OFFSET; 195 | sched_enqueue_thread(thread); 196 | return thread; 197 | } 198 | 199 | static thread_t *get_next_thread() { 200 | thread_t *current_thread = get_current_thread(); 201 | for (thread_t *next_thread = current_thread->next; 202 | next_thread != current_thread && next_thread != NULL; 203 | next_thread = next_thread->next) { 204 | if (next_thread->blocked || next_thread->running) 205 | continue; 206 | if (spinlock_test_and_acq(&next_thread->lock) == true) 207 | return next_thread; 208 | } 209 | return NULL; 210 | } 211 | 212 | static void sched_vector(uint8_t vector, interrupt_frame_t *state) { 213 | (void)vector; 214 | 215 | thread_t *current_thread = get_current_thread(); 216 | if (current_thread->running) { 217 | current_thread->state = state; 218 | current_thread->gs_base = read_gs_base(); 219 | } 220 | 221 | thread_t *next_thread = get_next_thread(); 222 | if (next_thread == NULL) { 223 | lapic_eoi(); 224 | lapic_timer_oneshot(current_thread->timeslice, SCHED_VECTOR); 225 | return; 226 | } 227 | current_thread->running = 0; 228 | spinlock_release(¤t_thread->lock); 229 | 230 | this_cpu()->current_thread = next_thread; 231 | 232 | if (next_thread->state->cs == 0x3b) { // if user 233 | set_kgs_base(next_thread->gs_base); 234 | } else { 235 | set_kgs_base(read_gs_base()); 236 | } 237 | 238 | if (read_cr3() != next_thread->cr3) { 239 | write_cr3(next_thread->cr3); 240 | } 241 | 242 | lapic_eoi(); 243 | lapic_timer_oneshot(current_thread->timeslice, SCHED_VECTOR); 244 | 245 | switch_to_thread(next_thread); 246 | } 247 | 248 | bool dequeue_thread(thread_t *thread) { 249 | if (!thread->enqueued) 250 | return true; 251 | // remove thread frome queue 252 | thread->next->prev = thread->prev; 253 | thread->prev->next = thread->next; 254 | spinlock_release(&thread->lock); 255 | thread->enqueued = false; 256 | thread->running = false; 257 | return true; 258 | } 259 | 260 | __attribute__((__noreturn__)) void dequeue_and_die() { 261 | asm volatile("cli"); 262 | lapic_stop(); 263 | thread_t *current_thread = get_current_thread(); 264 | dequeue_thread(current_thread); 265 | kheap_free(current_thread); 266 | this_cpu()->current_thread = this_cpu()->idle_thread; 267 | asm volatile("sti"); 268 | lapic_ipi(this_cpu()->lapic_id, SCHED_VECTOR); 269 | __builtin_unreachable(); 270 | } 271 | 272 | __attribute__((__noreturn__)) void sched_await() { 273 | lapic_timer_oneshot(TIME_QUANTUM, SCHED_VECTOR); 274 | for (;;) { 275 | asm volatile("hlt;"); 276 | } 277 | __builtin_unreachable(); 278 | } 279 | 280 | __attribute__((__noreturn__)) void sched_init(void *start) { 281 | asm("cli"); 282 | isr[SCHED_VECTOR] = sched_vector; 283 | idt_set_ist(SCHED_VECTOR, 1); 284 | vector_create(&processes_vector, sizeof(process_t)); 285 | 286 | kernel_process = sched_process(kernel_pagemap); 287 | sched_kernel_thread(start, NULL); 288 | asm("sti"); 289 | sched_await(); 290 | } 291 | -------------------------------------------------------------------------------- /src/proc/sched.h: -------------------------------------------------------------------------------- 1 | #ifndef sched_h 2 | #define sched_h 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | struct interrupt_frame; 12 | #define TIME_QUANTUM 3 13 | #define MAX_FILDES 256 14 | 15 | typedef struct { 16 | uint64_t pid; 17 | pagemap_t *pagemap; 18 | vector_t *threads; 19 | vfs_node_t *cwd; 20 | vector_t *fildes; 21 | int current_filde; 22 | uintptr_t thread_stack_top; 23 | uintptr_t anon_base; 24 | } process_t; 25 | 26 | struct thread { 27 | int errno; 28 | struct thread *prev; 29 | struct thread *next; 30 | uint64_t cr3; 31 | struct cpu_local *cpu; 32 | bool running; 33 | process_t *process; 34 | spinlock_t lock; 35 | struct interrupt_frame *state; 36 | uint8_t timeslice; 37 | bool enqueued; 38 | bool blocked; 39 | void *gs_base; 40 | void *fs_base; 41 | }; 42 | typedef struct thread thread_t; 43 | 44 | typedef struct { 45 | thread_t *start; 46 | thread_t *end; 47 | spinlock_t lock; 48 | } sched_queue_t; 49 | 50 | extern process_t *kernel_process; 51 | thread_t *sched_thread(); 52 | bool dequeue_thread(thread_t *thread); 53 | void dequeue_and_die(); 54 | __attribute__((__noreturn__)) void dequeue_and_die(); 55 | process_t *sched_process(pagemap_t *pagemap); 56 | __attribute__((__noreturn__)) void sched_await(); 57 | __attribute__((__noreturn__)) void sched_init(void *start); 58 | thread_t *sched_kernel_thread(void *start, void *args); 59 | thread_t *sched_user_thread(void *start, void *arg, process_t *process, 60 | const char **argv, const char **envp, 61 | struct auxval *aux); 62 | bool sched_enqueue_thread(thread_t *thread); 63 | thread_t *get_current_thread(); 64 | #endif 65 | -------------------------------------------------------------------------------- /src/sys/cpu.h: -------------------------------------------------------------------------------- 1 | #ifndef cpu_h 2 | #define cpu_h 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | struct thread; 10 | #define STACK_SIZE 0x10000 11 | 12 | #define MSR_EFER 0xC0000080 13 | #define MSR_STAR 0xC0000081 14 | #define MSR_LSTAR 0xC0000082 15 | #define MSR_CSTAR 0xC0000083 16 | #define MSR_FMASK 0xC0000084 17 | #define MSR_FSBASE 0xC0000100 18 | #define MSR_GSBASE 0xC0000101 19 | #define MSR_KGSBASE 0xC0000102 20 | 21 | #define cpuid(in, a, b, c, d) \ 22 | asm volatile("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(in)); 23 | 24 | typedef struct __attribute__((packed)) { 25 | uint32_t rsvd0; 26 | uint64_t rsp0; 27 | uint64_t rsp1; 28 | uint64_t rsp2; 29 | uint64_t rsvd1; 30 | uint64_t ist1; 31 | uint64_t ist2; 32 | uint64_t ist3; 33 | uint64_t ist4; 34 | uint64_t ist5; 35 | uint64_t ist6; 36 | uint64_t ist7; 37 | uint64_t rsvd2; 38 | uint32_t iopb; 39 | } tss_t; 40 | 41 | struct interrupt_frame { 42 | uint64_t es; 43 | uint64_t ds; 44 | uint64_t r15; 45 | uint64_t r14; 46 | uint64_t r13; 47 | uint64_t r12; 48 | uint64_t r11; 49 | uint64_t r10; 50 | uint64_t r9; 51 | uint64_t r8; 52 | uint64_t rbp; 53 | uint64_t rdi; 54 | uint64_t rsi; 55 | uint64_t rdx; 56 | uint64_t rcx; 57 | uint64_t rbx; 58 | uint64_t rax; 59 | uint64_t err; 60 | uint64_t rip; 61 | uint64_t cs; 62 | uint64_t rflags; 63 | uint64_t rsp; 64 | uint64_t ss; 65 | } __attribute__((__packed__)); 66 | typedef struct interrupt_frame interrupt_frame_t; 67 | 68 | struct cpu_local { 69 | void *kernel_stack; 70 | struct thread *current_thread; 71 | struct thread *idle_thread; 72 | uint64_t cpu_number; 73 | uint64_t lapic_id; 74 | bool bsp; 75 | bool active; 76 | uint32_t lapic_freq; 77 | tss_t tss; 78 | }; 79 | typedef struct cpu_local cpu_local_t; 80 | 81 | static inline uint64_t wrmsr(uint32_t msr, uint64_t val) { 82 | uint32_t eax = (uint32_t)val, edx = (uint32_t)(val >> 32); 83 | asm volatile("wrmsr" : : "a"(eax), "d"(edx), "c"(msr) : "memory"); 84 | return ((uint64_t)edx << 32) | eax; 85 | } 86 | 87 | static inline uint64_t rdmsr(uint32_t msr) { 88 | uint32_t edx = 0, eax = 0; 89 | asm volatile("rdmsr" : "=a"(eax), "=d"(edx) : "c"(msr) : "memory"); 90 | return ((uint64_t)edx << 32) | eax; 91 | } 92 | 93 | static inline void *read_gs_base() { return (void *)rdmsr(MSR_GSBASE); } 94 | 95 | static inline void *read_kgs_base() { return (void *)rdmsr(MSR_KGSBASE); } 96 | 97 | static inline void *read_fs_base() { return (void *)rdmsr(MSR_FSBASE); } 98 | 99 | static inline void set_gs_base(void *addr) { 100 | wrmsr(MSR_GSBASE, (uint64_t)addr); 101 | } 102 | 103 | static inline void set_fs_base(void *addr) { 104 | wrmsr(MSR_FSBASE, (uint64_t)addr); 105 | } 106 | 107 | static inline void set_kgs_base(void *addr) { 108 | wrmsr(MSR_KGSBASE, (uint64_t)addr); 109 | } 110 | 111 | static inline uint64_t read_cr0(void) { 112 | uint64_t ret = 0; 113 | asm volatile("mov %0, cr0" : "=r"(ret) : : "memory"); 114 | return ret; 115 | } 116 | static inline void write_cr0(uint64_t val) { 117 | asm volatile("mov cr0, %0" : : "r"(val) : "memory"); 118 | } 119 | 120 | static inline uint64_t read_cr3(void) { 121 | uint64_t ret = 0; 122 | asm volatile("mov %0, cr3" : "=r"(ret) : : "memory"); 123 | return ret; 124 | } 125 | static inline void write_cr3(uint64_t val) { 126 | asm volatile("mov cr3, %0" : : "r"(val) : "memory"); 127 | } 128 | 129 | static inline uint64_t read_cr4(void) { 130 | uint64_t ret = 0; 131 | asm volatile("mov %0, cr4" : "=r"(ret) : : "memory"); 132 | return ret; 133 | } 134 | static inline void write_cr4(uint64_t val) { 135 | asm volatile("mov cr4, %0" : : "r"(val) : "memory"); 136 | } 137 | 138 | static inline cpu_local_t *this_cpu() { return (cpu_local_t *)read_gs_base(); } 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /src/sys/idt/idt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | spinlock_t idt_lock = LOCK_INIT; 8 | static idt_gate_t idt[256]; 9 | void *isr[256]; 10 | extern void *isr_stubs[]; 11 | static idtptr_t idtr; 12 | 13 | const char *exception_names[] = {"Division By Zero", 14 | "Debug", 15 | "NMI", 16 | "Breakpoint", 17 | "Overflow", 18 | "Bound Range Exceeded", 19 | "Invalid Opcode", 20 | "Device Not Available", 21 | "Double Fault", 22 | "???", 23 | "Invalid TSS", 24 | "Segment Not Present", 25 | "Stack-Segment Fault", 26 | "General Protection Fault", 27 | "Page Fault", 28 | "???", 29 | "x87 Exception", 30 | "Alignment Check", 31 | "Machine Check", 32 | "SIMD Exception", 33 | "Virtualisation", 34 | "???", 35 | "???", 36 | "???", 37 | "???", 38 | "???", 39 | "???", 40 | "???", 41 | "???", 42 | "???", 43 | "Security"}; 44 | 45 | void idt_load() { 46 | asm volatile("lidt %0" : : "m"(idtr)); 47 | asm volatile("sti"); 48 | } 49 | 50 | static void encode_idt_entry(uint8_t vector, void *handler, uint8_t flags) { 51 | uint64_t ptr = (uint64_t)handler; 52 | 53 | idt[vector].offset_low16 = (uint16_t)ptr; 54 | idt[vector].selector = 0x28; 55 | idt[vector].ist = 0; 56 | idt[vector].flags = flags; 57 | idt[vector].offset_mid16 = (uint16_t)(ptr >> 16); 58 | idt[vector].offset_high32 = (uint32_t)(ptr >> 32); 59 | idt[vector].reserved = 0; 60 | } 61 | 62 | static void exception_handler(uint8_t vector, interrupt_frame_t *state) { 63 | printf("%s\nEXCEPTION RECIVED: %s on core #%d%s\n", cRED, 64 | exception_names[vector], this_cpu()->cpu_number, cNONE); 65 | 66 | printf(" RAX=%x RBX=%x\n" 67 | " RCX=%x RDX=%x\n" 68 | " RSI=%x RDI=%x\n" 69 | " RBP=%x RSP=%x\n" 70 | " R08=%x R09=%x\n" 71 | " R10=%x R11=%x\n" 72 | " R12=%x R13=%x\n" 73 | " R14=%x R15=%x\n" 74 | " RIP=%x RFLAGS=%x\n" 75 | " CS=%x SS=%x ES=%x DS=%x\n" 76 | " ERR=%x", 77 | state->rax, state->rbx, state->rcx, state->rdx, state->rsi, 78 | state->rdi, state->rbp, state->rsp, state->r8, state->r9, state->r10, 79 | state->r11, state->r12, state->r13, state->r14, state->r15, 80 | state->rip, state->rflags, state->cs, state->ss, state->es, 81 | state->ds, state->err); 82 | 83 | asm volatile("cli; hlt"); 84 | } 85 | 86 | static void isr_generic(uint8_t vector, interrupt_frame_t *state) { 87 | (void)state; 88 | printf("Something, %d\n", vector); 89 | } 90 | 91 | void idt_init() { 92 | idtr = (idtptr_t){.limit = sizeof(idt) - 1, .base = (uint64_t)idt}; 93 | 94 | for (uint64_t i = 0; i < 32; i++) { 95 | encode_idt_entry(i, isr_stubs[i], 0x8e); 96 | isr[i] = exception_handler; 97 | } 98 | for (uint64_t i = 32; i < 256; i++) { 99 | encode_idt_entry(i, isr_stubs[i], 0x8e); 100 | isr[i] = isr_generic; 101 | } 102 | idt_load(); 103 | printf("IDT initialized.\n"); 104 | } 105 | 106 | void idt_set_ist(uint8_t vector, uint8_t ist) { idt[vector].ist = ist; } 107 | -------------------------------------------------------------------------------- /src/sys/idt/idt.h: -------------------------------------------------------------------------------- 1 | #ifndef idt_h 2 | #define idt_h 3 | #include 4 | 5 | typedef struct __attribute__((packed)) { 6 | uint16_t limit; 7 | uint64_t base; 8 | } idtptr_t; 9 | 10 | typedef struct __attribute__((packed)) { 11 | uint16_t offset_low16; 12 | uint16_t selector; 13 | uint8_t ist; 14 | uint8_t flags; 15 | uint16_t offset_mid16; 16 | uint32_t offset_high32; 17 | uint32_t reserved; 18 | } idt_gate_t; 19 | 20 | extern void *isr[]; 21 | void idt_init(); 22 | void isr_init(); 23 | void idt_load(); 24 | void idt_set_ist(uint8_t vector, uint8_t ist); 25 | #endif 26 | -------------------------------------------------------------------------------- /src/sys/idt/isr.asm: -------------------------------------------------------------------------------- 1 | extern isr 2 | extern isr_generic 3 | 4 | %macro stub 1 5 | isr_stub_%1: 6 | 7 | %if %1 != 8 && %1 != 10 && %1 != 11 && %1 != 12 && %1 != 13 && %1 != 14 && %1 != 17 && %1 != 30 8 | push qword 0 9 | %endif 10 | 11 | cmp qword [rsp + 16], 0x3b 12 | jne .swap 13 | swapgs 14 | 15 | .swap: 16 | push rax 17 | push rbx 18 | push rcx 19 | push rdx 20 | push rsi 21 | push rdi 22 | push rbp 23 | push r8 24 | push r9 25 | push r10 26 | push r11 27 | push r12 28 | push r13 29 | push r14 30 | push r15 31 | 32 | mov eax, ds 33 | push rax 34 | mov eax, es 35 | push rax 36 | 37 | cld 38 | 39 | mov rax, 0x30 40 | mov ds, eax 41 | mov es, eax 42 | mov ss, eax 43 | 44 | mov rdi, %1 45 | mov rax, (%1 * 8) 46 | lea rbx, qword [isr] 47 | add rbx, rax 48 | mov rsi, rsp 49 | xor rbp, rbp 50 | call [rbx] 51 | 52 | pop rax 53 | mov es, eax 54 | pop rax 55 | mov ds, eax 56 | 57 | pop r15 58 | pop r14 59 | pop r13 60 | pop r12 61 | pop r11 62 | pop r10 63 | pop r9 64 | pop r8 65 | pop rbp 66 | pop rdi 67 | pop rsi 68 | pop rdx 69 | pop rcx 70 | pop rbx 71 | pop rax 72 | add rsp, 8 73 | 74 | cmp qword [rsp + 8], 0x3b 75 | jne .swap1 76 | swapgs 77 | 78 | .swap1: 79 | iretq 80 | %endmacro 81 | 82 | %macro stub_address 1 83 | dq isr_stub_%1 84 | %endmacro 85 | 86 | section .data 87 | 88 | global isr_stubs 89 | align 8 90 | isr_stubs: 91 | %assign i 0 92 | %rep 256 93 | stub_address i 94 | %assign i i+1 95 | %endrep 96 | 97 | section .text 98 | 99 | %assign i 0 100 | %rep 256 101 | stub i 102 | %assign i i+1 103 | %endrep 104 | -------------------------------------------------------------------------------- /src/sys/smp.c: -------------------------------------------------------------------------------- 1 | #include 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 | 16 | spinlock_t smp_lock = LOCK_INIT; 17 | static uint64_t cpus_running; 18 | vector_t cpus; 19 | 20 | static volatile struct limine_smp_request smp_request = { 21 | .id = LIMINE_SMP_REQUEST, .revision = 0}; 22 | 23 | extern void syscall_entry_asm(); 24 | 25 | void core_init(struct limine_smp_info *info) { 26 | uint32_t eax, ebx, ecx, edx; 27 | 28 | cpuid(0x80000001, eax, ebx, ecx, edx); 29 | 30 | if (edx && (uint32_t)1 << 11) { 31 | 32 | uint64_t efer = rdmsr(MSR_EFER); 33 | efer |= 1; 34 | wrmsr(MSR_EFER, efer); 35 | 36 | uint64_t star = 0; 37 | star |= (uint64_t)(0x30 | 3) << 48; 38 | star |= (uint64_t)(0x28) << 32; 39 | 40 | wrmsr(MSR_STAR, star); 41 | wrmsr(MSR_LSTAR, (uint64_t)syscall_entry_asm); 42 | wrmsr(MSR_CSTAR, 0); 43 | wrmsr(MSR_FMASK, 0x200); 44 | } else { 45 | printf("Syscall is not supported."); 46 | assert(0); 47 | } 48 | 49 | cpu_local_t *local = (void *)info->extra_argument; 50 | int cpu_number = local->cpu_number; 51 | vector_replace(&cpus, local, cpu_number); 52 | 53 | gdt_load(); 54 | idt_load(); 55 | 56 | void *int_stack = pmm_alloc(STACK_SIZE); 57 | assert(int_stack); 58 | void *stack = (int_stack + HHDM_OFFSET + STACK_SIZE); 59 | local->tss.rsp0 = (uint64_t)stack; 60 | local->kernel_stack = stack; 61 | 62 | void *sched_stack = pmm_alloc(STACK_SIZE); 63 | assert(sched_stack); 64 | local->tss.ist1 = (uint64_t)(sched_stack + HHDM_OFFSET + STACK_SIZE); 65 | 66 | gdt_load_tss(&local->tss); 67 | 68 | vmm_switch_pagemap(kernel_pagemap); 69 | thread_t *idle_thread = kheap_calloc(sizeof(thread_t)); 70 | idle_thread->blocked = true; 71 | idle_thread->cpu = local; 72 | idle_thread->process = kernel_process; 73 | 74 | local->idle_thread = idle_thread; 75 | local->current_thread = idle_thread; 76 | sched_enqueue_thread(idle_thread); 77 | 78 | set_gs_base(local); 79 | 80 | // enable SSE and SSE2 for SIMD 81 | uint64_t cr0 = read_cr0(); 82 | cr0 &= ~(1 << 2); 83 | cr0 |= (1 << 1); 84 | write_cr0(cr0); 85 | 86 | uint64_t cr4 = read_cr4(); 87 | cr4 |= (3 << 9); 88 | write_cr4(cr4); 89 | 90 | lapic_init(); 91 | printf("Processor #%d is running. \n", cpu_number); 92 | 93 | cpus_running++; 94 | if (!local->bsp) 95 | sched_await(); 96 | } 97 | 98 | void smp_init(void) { 99 | 100 | struct limine_smp_response *smp_response = smp_request.response; 101 | vector_create(&cpus, sizeof(cpu_local_t)); 102 | vector_resize(&cpus, smp_response->cpu_count); 103 | 104 | for (uint64_t i = 0; i < smp_response->cpu_count; i++) { 105 | struct limine_smp_info *cpu = smp_response->cpus[i]; 106 | cpu_local_t *local = kheap_calloc(sizeof(cpu_local_t)); 107 | cpu->extra_argument = (uint64_t)local; 108 | local->cpu_number = i; 109 | local->lapic_id = cpu->lapic_id; 110 | if (cpu->lapic_id != smp_response->bsp_lapic_id) { 111 | smp_response->cpus[i]->goto_address = core_init; 112 | // while(cpus_running != i + 1); 113 | } else { 114 | local->bsp = 1; 115 | core_init(cpu); 116 | } 117 | } 118 | while (cpus_running != smp_response->cpu_count) { 119 | asm("pause"); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/sys/smp.h: -------------------------------------------------------------------------------- 1 | #ifndef smp_h 2 | #define smp_h 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct cpu_local; 9 | extern vector_t cpus; 10 | void smp_init(); 11 | void single_cpu_init(struct limine_smp_info *smp_info); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/sys/syscalls/syscall_handler.asm: -------------------------------------------------------------------------------- 1 | section .rodata 2 | 3 | extern syscall_log 4 | extern syscall_mmap 5 | extern syscall_openat 6 | extern syscall_read 7 | extern syscall_seek 8 | extern syscall_set_fs_base 9 | extern syscall_exit_thread 10 | syscall_table: 11 | dq syscall_log ;0 12 | dq syscall_mmap ;1 13 | dq syscall_openat ;2 14 | dq syscall_read ;3 15 | dq syscall_seek ;4 16 | dq syscall_set_fs_base ; 5 17 | dq syscall_exit_thread ;6 18 | 19 | section .text 20 | 21 | global syscall_entry_asm 22 | syscall_entry_asm: 23 | 24 | swapgs 25 | 26 | xchg rsp, [gs:0] 27 | push qword [gs:0] ; push old stack 28 | mov [gs:0], rsp 29 | add qword [gs:0], 8 30 | 31 | push qword 0x43 ; ss 32 | push qword [rsp+8] ; rsp 33 | push r11 ; rflags 34 | push qword 0x3b ; cs 35 | push rcx ; rip 36 | push qword 0 ; err 37 | 38 | push rax 39 | push rbx 40 | push rcx 41 | push rdx 42 | push rsi 43 | push rdi 44 | push rbp 45 | push r8 46 | push r9 47 | push r10 48 | push r11 49 | push r12 50 | push r13 51 | push r14 52 | push r15 53 | 54 | mov r11, ds 55 | push r11 56 | mov r11, es 57 | push r11 58 | 59 | mov rcx, r10 60 | 61 | cld 62 | 63 | mov r11, 0x30 64 | mov ds, r11 65 | mov es, r11 66 | 67 | call [syscall_table + rax * 8] 68 | 69 | pop r11 70 | mov es, r11 71 | pop r11 72 | mov ds, r11 73 | 74 | pop r15 75 | pop r14 76 | pop r13 77 | pop r12 78 | pop r11 79 | pop r10 80 | pop r9 81 | pop r8 82 | pop rbp 83 | pop rdi 84 | pop rsi 85 | add rsp, 0x8 ; rdx 86 | pop rcx 87 | pop rbx 88 | add rsp, 0x38 ; rax, err, rip, cs, rflags, rsp, ss 89 | pop rsp ; get old stack back 90 | cli 91 | swapgs 92 | o64 sysret 93 | -------------------------------------------------------------------------------- /src/sys/syscalls/syscalls.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int syscall_set_fs_base(void *pointer) { 12 | set_fs_base(pointer); 13 | return 0; 14 | } 15 | 16 | off_t syscall_seek(int fd, off_t offset, int whence) { 17 | off_t ret = -1; 18 | vfs_node_t *node = fd_to_node(fd); 19 | 20 | off_t new_off = 0; 21 | switch (whence) { 22 | case SEEK_SET: 23 | new_off = offset; 24 | break; 25 | case SEEK_CUR: 26 | new_off = node->offset + offset; 27 | break; 28 | case SEEK_END: 29 | new_off = node->st.st_size + offset; 30 | break; 31 | default: 32 | errno = EINVAL; 33 | return -1; 34 | } 35 | 36 | if (new_off < 0) { 37 | errno = EINVAL; 38 | return -1; 39 | } 40 | 41 | node->offset = new_off; 42 | ret = new_off; 43 | return ret; 44 | } 45 | 46 | int syscall_read(int fd, void *buf, uint64_t count) { 47 | vfs_node_t *node = fd_to_node(fd); 48 | int ret = -1; 49 | 50 | if (node == NULL) { 51 | errno = ENOENT; 52 | return ret; 53 | } 54 | 55 | return vfs_read(node, buf, count, node->offset); 56 | } 57 | 58 | int syscall_openat(int dirfd, const char *pathname, int flags, mode_t mode) { 59 | vfs_node_t *dir = fd_to_node(dirfd); 60 | int ret = -1; 61 | vfs_node_t *node = vfs_open(dir, pathname); 62 | if (node == NULL) { 63 | 64 | if ((flags & O_CREAT) == NULL) { 65 | errno = ENOENT; 66 | return ret; 67 | } 68 | 69 | vfs_node_t *parent = path_to_parent(dir, pathname); 70 | if (parent == NULL) { 71 | errno = ENOENT; 72 | return ret; 73 | } 74 | char *new_pathname = strdup(pathname); 75 | if (new_pathname == NULL) { 76 | errno = ENOMEM; 77 | return ret; 78 | } 79 | 80 | node = vfs_create(parent, basename, S_IFREG); 81 | } 82 | ret = node_to_fd(node); 83 | return ret; 84 | } 85 | 86 | void *syscall_mmap(void *hint, uint64_t length, int prot, int flags, int fd, 87 | off_t offset) { 88 | (void)offset; 89 | (void)fd; 90 | 91 | process_t *proc = get_current_thread()->process; 92 | 93 | if ((flags & MAP_ANON) == 0) { 94 | printf("Not implemented.\n"); 95 | return MAP_FAILED; 96 | } 97 | 98 | uintptr_t virt; 99 | uint64_t pages = ALIGN_UP(length, FRAME_SIZE) / FRAME_SIZE; 100 | 101 | if (flags & MAP_FIXED) { 102 | 103 | if (hint > USER_SPACE_END || length == 0 || hint == NULL) { 104 | errno = EINVAL; 105 | return MAP_FAILED; 106 | } 107 | virt = (uintptr_t)hint; 108 | } else { 109 | virt = proc->anon_base; 110 | proc->anon_base += (pages * FRAME_SIZE); 111 | } 112 | 113 | void *phys = pmm_calloc(pages); 114 | if (phys == NULL) 115 | return MAP_FAILED; 116 | 117 | vmm_map_pages(proc->pagemap, (uintptr_t)phys, virt, 118 | prot | PTE_PRESENT | PTE_WRITABLE | PTE_USER, pages); 119 | 120 | return (void *)virt; 121 | } 122 | 123 | void syscall_log(char *str) { printf(str); } 124 | 125 | __attribute__((__noreturn__)) void syscall_exit_thread() { dequeue_and_die(); } 126 | --------------------------------------------------------------------------------