├── .github └── workflows │ └── mkimg.yml ├── .gitignore ├── LICENSE ├── Makefile.in ├── README.md ├── autogen.sh ├── base ├── etc │ └── passwd ├── run │ └── .keep ├── tmp │ └── .keep └── var │ └── .keep ├── configure.ac ├── meta ├── cat.bmp ├── limine.cfg ├── qnixx.bmp └── termfont.F16 ├── sys ├── include │ ├── acpi │ │ ├── acpi.h │ │ └── def.h │ ├── arch │ │ ├── bus │ │ │ └── pci.h │ │ ├── x86 │ │ │ ├── apic │ │ │ │ ├── ioapic.h │ │ │ │ └── lapic.h │ │ │ ├── cpu.h │ │ │ └── io.h │ │ └── x86_64 │ │ │ ├── exceptions.h │ │ │ └── idt.h │ ├── drivers │ │ ├── serial.h │ │ ├── timer │ │ │ └── pit.h │ │ └── video │ │ │ └── framebuffer.h │ ├── fs │ │ ├── devfs.h │ │ ├── tmpfs.h │ │ └── vfs.h │ ├── intr │ │ ├── init.h │ │ └── irq.h │ ├── lib │ │ ├── asm.h │ │ ├── assert.h │ │ ├── hashmap.h │ │ ├── limine.h │ │ ├── log.h │ │ ├── math.h │ │ ├── string.h │ │ └── types.h │ ├── mm │ │ ├── heap.h │ │ ├── pmm.h │ │ └── vmm.h │ ├── sched │ │ ├── proc.h │ │ └── sched.h │ └── sync │ │ └── spinlock.h ├── link.ld └── src │ ├── acpi │ └── acpi.c │ ├── arch │ ├── bus │ │ └── pci.c │ ├── x86 │ │ ├── apic │ │ │ ├── ioapic.c │ │ │ └── lapic.c │ │ ├── cpu.c │ │ └── io.c │ └── x86_64 │ │ ├── exceptions.c │ │ └── idt.c │ ├── drivers │ ├── serial.c │ ├── timer │ │ └── pit.c │ └── video │ │ └── framebuffer.c │ ├── fs │ ├── devfs.c │ ├── tmpfs.c │ └── vfs.c │ ├── init.c │ ├── intr │ ├── init.c │ ├── irq.asm │ ├── trap.asm │ └── trap.c │ ├── lib │ ├── hashmap.c │ ├── log.c │ └── string.c │ ├── mm │ ├── heap.c │ ├── pmm.c │ └── vmm.c │ └── sched │ └── sched.c └── tools └── cross.sh /.github/workflows/mkimg.yml: -------------------------------------------------------------------------------- 1 | name: mkimg 2 | on: 3 | push: 4 | branches: [ main ] 5 | pull_request: 6 | branches: [ main ] 7 | workflow_dispatch: 8 | jobs: 9 | job: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | 14 | - name: Build 15 | run: | 16 | sudo apt-get -y update 17 | sudo apt-get -y install gcc 18 | sudo apt-get -y install make 19 | sudo apt-get -y install git 20 | sudo apt-get -y install nasm 21 | sudo apt-get -y install xorriso 22 | sudo apt-get -y install autoconf 23 | bash tools/cross.sh 24 | bash autogen.sh 25 | ./configure 26 | make 27 | - name: Uploading ISO as artifact 28 | uses: actions/upload-artifact@v3 29 | with: 30 | name: Qnixx 31 | path: Qnixx.iso 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.iso 3 | sys/kernel.sys 4 | buildcc/ 5 | cross/ 6 | configure/ 7 | limine/ 8 | autom4te.cache/ 9 | config.log 10 | config.status 11 | /Makefile 12 | configure 13 | install-sh 14 | meta/system/init.sys 15 | initrd.sys 16 | meta/initrd/*.sys 17 | sbin/ 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2022, Ian Marco Moffett 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | QEMU_ARGS = -cpu qemu64 -M q35 -m 3G -cdrom Qnixx.iso -boot d -smp 4 -rtc base=localtime -audiodev pa,id=audio0 -machine pcspk-audiodev=audio0 2 | LOCAL_IP = @LOCAL_IP@ 3 | CFLAGS = @KERNEL_CFLAGS@ 4 | CC = cross/bin/x86_64-elf-gcc 5 | LD = cross/bin/x86_64-elf-ld 6 | OBJDIR = obj 7 | SRCDIR = sys/src/ 8 | 9 | rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d)) 10 | OBJDIR = obj 11 | SRCDIR = sys/src 12 | SRC = $(call rwildcard,$(SRCDIR),*.c) 13 | OBJS = $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SRC)) 14 | 15 | .PHONY: all 16 | all: $(OBJS) asmfiles limine link iso 17 | 18 | .PHONY: iso 19 | iso: 20 | @echo "Generating ISO..." 21 | @mkdir -p iso_root 22 | @mkdir -p iso_root/boot 23 | @cp meta/limine.cfg \ 24 | limine/limine.sys limine/limine-cd.bin limine/limine-cd-efi.bin iso_root/ 25 | @cp sys/kernel.sys meta/*.bmp meta/termfont.F16 iso_root/boot/ 26 | @xorriso -as mkisofs -b limine-cd.bin \ 27 | -no-emul-boot -boot-load-size 4 -boot-info-table \ 28 | --efi-boot limine-cd-efi.bin \ 29 | -efi-boot-part --efi-boot-image --protective-msdos-label \ 30 | iso_root -o Qnixx.iso 31 | @echo "Deploying Limine..." 32 | @limine/limine-deploy Qnixx.iso 33 | @rm -rf iso_root 34 | 35 | limine: 36 | @echo "Fetching Limine binaries..." 37 | @git clone https://github.com/limine-bootloader/limine.git --branch=v4.0-binary --depth=1 38 | @make -C limine 39 | 40 | $(OBJDIR)/%.o: $(SRCDIR)/%.c 41 | mkdir -p $(shell dirname $@) 42 | $(CC) $(CFLAGS) -c $^ -o $@ 43 | 44 | .PHONY: asmfiles 45 | asmfiles: 46 | @echo "Compiling assembly sources..." 47 | @for source in $$(find sys/src/ -name "*.asm"); do nasm -felf64 $$source; done 48 | 49 | .PHONY: link 50 | link: 51 | mkdir -p asmobj/ 52 | @mv $(shell find sys/src/ -name "*.o") asmobj/ 53 | @echo "Linking object files..." 54 | @$(LD) $(shell find obj/ -name "*.o") asmobj/* -nostdlib -zmax-page-size=0x1000 -static -Tsys/link.ld -o sys/kernel.sys 55 | 56 | .PHONY: run 57 | run: 58 | qemu-system-x86_64 --enable-kvm $(QEMU_ARGS) -serial stdio 59 | 60 | .PHONY: clean 61 | clean: 62 | rm -rf obj 63 | 64 | .PHONY: clean_all 65 | clean_all: 66 | rm -rf configure autom4te.cache config.status config.log install-sh Makefile 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Qnixx 2 | 3 | ## Note: This repo is now used for reporting issues. 4 | ## Qnixx is now hosted at https://git.mkall.org/svr/Qnixx.git 5 | 6 | ## Build instructions: 7 | ``bash autogen.sh; ./configure; make`` 8 | 9 | ## Author: 10 | Ian Marco Moffett 11 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # find the location of the source code 4 | srcdir="$(dirname "$0")" 5 | test -z "$srcdir" && srcdir=. 6 | cd "$srcdir" 7 | 8 | # get system "install-sh" and run autoconf 9 | cp "$(automake --print-libdir)/install-sh" . && autoconf 10 | -------------------------------------------------------------------------------- /base/etc/passwd: -------------------------------------------------------------------------------- 1 | root:x:0:0::/root:/bin/bash 2 | -------------------------------------------------------------------------------- /base/run/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qnixx/src/272267f7eed507c58bd8e8da52f6187f6659e3f8/base/run/.keep -------------------------------------------------------------------------------- /base/tmp/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qnixx/src/272267f7eed507c58bd8e8da52f6187f6659e3f8/base/tmp/.keep -------------------------------------------------------------------------------- /base/var/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qnixx/src/272267f7eed507c58bd8e8da52f6187f6659e3f8/base/var/.keep -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([Qnixx]) 2 | AC_CONFIG_SRCDIR([LICENSE]) 3 | AC_PREREQ([2.71]) 4 | 5 | 6 | BUILDDIR="$(pwd -P)" 7 | AC_ARG_WITH([ip], 8 | [AS_HELP_STRING([--with-ip], 9 | [local ip @<:@default=unknown@:>@])], 10 | [], 11 | [with_ip=unknown]) 12 | 13 | # Build variables. 14 | AC_SUBST(LOCAL_IP, [$with_ip]) 15 | AC_SUBST(KERNEL_CFLAGS, ["-fexceptions -std=gnu11 -ffreestanding -fno-stack-protector \ 16 | -fno-pic -Werror=implicit -Werror=implicit-function-declaration -Werror=implicit-int \ 17 | -Werror=int-conversion \ 18 | -Werror=incompatible-pointer-types -Werror=int-to-pointer-cast -Werror=return-type -Wunused \ 19 | -mabi=sysv -mno-80387 -mno-mmx \ 20 | -mno-3dnow -mno-sse -mno-sse2 -mno-red-zone -mcmodel=kernel -I sys/include/"]) 21 | 22 | AC_PROG_INSTALL 23 | AC_CHECK_FILE([$BUILDDIR/cross],[],AC_MSG_ERROR("Please run 'bash tools/cross.sh'")) 24 | AC_CHECK_PROG(NASM_LOCATED, [nasm], [yes]) 25 | AC_CHECK_PROG(XORRISO_LOCATED, [xorriso], [yes]) 26 | AC_CHECK_PROG(MAKE_LOCATED, [make], [yes]) 27 | AC_CHECK_PROG(GIT_LOCATED, [git], [yes]) 28 | 29 | 30 | if ! test "x$NASM_LOCATED" = "xyes"; then 31 | AC_MSG_ERROR("Please install nasm") 32 | fi 33 | 34 | 35 | if ! test "x$XORRISO_LOCATED" = "xyes"; then 36 | AC_MSG_ERROR("Please install xorriso") 37 | fi 38 | 39 | 40 | if ! test "x$MAKE_LOCATED" = "xyes"; then 41 | AC_MSG_ERROR("Please install make") 42 | fi 43 | 44 | 45 | if ! test "x$GIT_LOCATED" = "xyes"; then 46 | AC_MSG_ERROR("Please install git") 47 | fi 48 | 49 | AC_CONFIG_FILES([Makefile]) 50 | AC_OUTPUT 51 | -------------------------------------------------------------------------------- /meta/cat.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qnixx/src/272267f7eed507c58bd8e8da52f6187f6659e3f8/meta/cat.bmp -------------------------------------------------------------------------------- /meta/limine.cfg: -------------------------------------------------------------------------------- 1 | TIMEOUT=60 2 | TERM_WALLPAPER=boot:///boot/qnixx.bmp 3 | TERM_FONT=boot:///boot/termfont.F16 4 | EDITOR_ENABLED=no 5 | 6 | :Qnixx 7 | PROTOCOL=limine 8 | KERNEL_PATH=boot:///boot/kernel.sys 9 | -------------------------------------------------------------------------------- /meta/qnixx.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qnixx/src/272267f7eed507c58bd8e8da52f6187f6659e3f8/meta/qnixx.bmp -------------------------------------------------------------------------------- /meta/termfont.F16: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qnixx/src/272267f7eed507c58bd8e8da52f6187f6659e3f8/meta/termfont.F16 -------------------------------------------------------------------------------- /sys/include/acpi/acpi.h: -------------------------------------------------------------------------------- 1 | #ifndef ACPI_H_ 2 | #define ACPI_H_ 3 | 4 | #include 5 | 6 | void acpi_init(void); 7 | uint16_t acpi_remap_irq(uint8_t irq); 8 | 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /sys/include/acpi/def.h: -------------------------------------------------------------------------------- 1 | #ifndef ACPI_TABLES_H 2 | #define ACPI_TABLES_H 3 | 4 | #include 5 | #include 6 | 7 | 8 | typedef struct { 9 | char signature[8]; 10 | uint8_t checksum; 11 | char OEMID[6]; 12 | uint8_t rev; 13 | uint32_t rsdtaddr; 14 | } _packed acpi_rsdp_t; 15 | 16 | 17 | typedef struct { 18 | acpi_rsdp_t rsdp1; 19 | uint32_t length; 20 | uint64_t xsdtAddr; 21 | uint8_t extendedChecksum; 22 | uint8_t reserved[3]; 23 | } _packed acpi_rsdp2_t; 24 | 25 | 26 | typedef struct { 27 | char signature[8]; 28 | uint8_t checksum; 29 | char oem[6]; 30 | uint8_t rev; 31 | uint32_t rsdt; 32 | uint32_t length; 33 | uint64_t xsdt; 34 | uint8_t extended_checksum; 35 | } _packed acpi_xsdp_t; 36 | 37 | 38 | typedef struct { 39 | char signature[4]; 40 | uint32_t length; 41 | uint8_t revision; 42 | uint8_t checksum; 43 | char oem[6]; 44 | char oem_table[8]; 45 | uint32_t oem_revision; 46 | uint32_t creator_id; 47 | uint32_t creator_revision; 48 | } _packed acpi_header_t; 49 | 50 | 51 | typedef struct { 52 | acpi_header_t header; 53 | uint32_t tables[]; 54 | } _packed acpi_rsdt_t; 55 | 56 | 57 | typedef struct { 58 | acpi_header_t header; 59 | uint64_t tables[]; 60 | } _packed acpi_xsdt_t; 61 | 62 | 63 | typedef struct { 64 | uint8_t address_space; 65 | uint8_t bit_width; 66 | uint8_t bit_offset; 67 | uint8_t access_size; 68 | uint64_t base; 69 | } _packed acpi_gas_t; 70 | 71 | 72 | typedef struct { 73 | acpi_header_t header; 74 | uint32_t firmware_control; 75 | uint32_t dsdt; // pointer to dsdt 76 | 77 | uint8_t reserved; 78 | 79 | uint8_t profile; 80 | uint16_t sci_irq; 81 | uint32_t smi_command_port; 82 | uint8_t acpi_enable; 83 | uint8_t acpi_disable; 84 | uint8_t s4bios_req; 85 | uint8_t pstate_control; 86 | uint32_t pm1a_event_block; 87 | uint32_t pm1b_event_block; 88 | uint32_t pm1a_control_block; 89 | uint32_t pm1b_control_block; 90 | uint32_t pm2_control_block; 91 | uint32_t pm_timer_block; 92 | uint32_t gpe0_block; 93 | uint32_t gpe1_block; 94 | uint8_t pm1_event_length; 95 | uint8_t pm1_control_length; 96 | uint8_t pm2_control_length; 97 | uint8_t pm_timer_length; 98 | uint8_t gpe0_length; 99 | uint8_t gpe1_length; 100 | uint8_t gpe1_base; 101 | uint8_t cstate_control; 102 | uint16_t worst_c2_latency; 103 | uint16_t worst_c3_latency; 104 | uint16_t flush_size; 105 | uint16_t flush_stride; 106 | uint8_t duty_offset; 107 | uint8_t duty_width; 108 | 109 | // cmos registers 110 | uint8_t day_alarm; 111 | uint8_t month_alarm; 112 | uint8_t century; 113 | 114 | // ACPI 2.0 fields 115 | uint16_t iapc_boot_flags; 116 | uint8_t reserved2; 117 | uint32_t flags; 118 | 119 | acpi_gas_t reset_register; 120 | uint8_t reset_command; 121 | uint16_t arm_boot_flags; 122 | uint8_t minor_version; 123 | 124 | uint64_t x_firmware_control; 125 | uint64_t x_dsdt; 126 | 127 | acpi_gas_t x_pm1a_event_block; 128 | acpi_gas_t x_pm1b_event_block; 129 | acpi_gas_t x_pm1a_control_block; 130 | acpi_gas_t x_pm1b_control_block; 131 | acpi_gas_t x_pm2_control_block; 132 | acpi_gas_t x_pm_timer_block; 133 | acpi_gas_t x_gpe0_block; 134 | acpi_gas_t x_gpe1_block; 135 | } _packed acpi_fadt_t; 136 | 137 | 138 | typedef struct { 139 | acpi_header_t header; 140 | uint32_t lapic_addr; 141 | uint32_t flags; 142 | } _packed acpi_madt_t; 143 | 144 | typedef struct { 145 | uint8_t type; 146 | uint8_t length; 147 | } _packed apic_header_t; 148 | 149 | typedef struct { 150 | apic_header_t header; 151 | uint8_t processor_id; 152 | uint8_t apic_id; 153 | uint32_t flags; 154 | } _packed local_apic_t; 155 | 156 | 157 | typedef struct { 158 | apic_header_t header; 159 | uint8_t io_apic_id; 160 | uint8_t reserved; 161 | uint32_t io_apic_addr; 162 | uint32_t global_system_interrupt_base; 163 | } _packed io_apic_t; 164 | 165 | typedef struct { 166 | apic_header_t header; 167 | uint8_t bus; 168 | uint8_t source; // IRQ. 169 | uint32_t interrupt; // GSI. 170 | uint16_t flags; 171 | } _packed apic_interrupt_override_t; 172 | 173 | #endif 174 | -------------------------------------------------------------------------------- /sys/include/arch/bus/pci.h: -------------------------------------------------------------------------------- 1 | #ifndef PCI_H_ 2 | #define PCI_H_ 3 | 4 | #include 5 | 6 | 7 | typedef struct { 8 | uint64_t bars[5]; 9 | uint8_t irq_line; 10 | uint8_t bus; 11 | uint8_t slot; 12 | uint8_t func; 13 | } pci_dev_t; 14 | 15 | 16 | pci_dev_t* pci_find_any(uint8_t class, uint8_t subclass, int8_t interface); 17 | pci_dev_t* pci_find(uint16_t vendor_id, uint16_t device_id); 18 | void pci_enable_bus_mastering(pci_dev_t* dev); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /sys/include/arch/x86/apic/ioapic.h: -------------------------------------------------------------------------------- 1 | #ifndef IOAPIC_H_ 2 | #define IOAPIC_H_ 3 | 4 | #include 5 | 6 | void ioapic_set_entry(uint8_t index, uint64_t data); 7 | void ioapic_init(void); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /sys/include/arch/x86/apic/lapic.h: -------------------------------------------------------------------------------- 1 | #ifndef LAPIC_H_ 2 | #define LAPIC_H_ 3 | 4 | #include 5 | 6 | 7 | void lapic_send_ipi(uint8_t apic_id, uint8_t vector); 8 | void lapic_send_init(uint8_t apic_id); 9 | void lapic_send_startup(uint8_t apic_id, uint8_t vector); 10 | uint32_t lapic_read_id(void); 11 | void lapic_send_eoi(void); 12 | void lapic_init(void); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /sys/include/arch/x86/cpu.h: -------------------------------------------------------------------------------- 1 | #ifndef CPU_H_ 2 | #define CPU_H_ 3 | 4 | 5 | void halt(void); 6 | void disable_processor(void); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /sys/include/arch/x86/io.h: -------------------------------------------------------------------------------- 1 | #ifndef IO_H_ 2 | #define IO_H_ 3 | 4 | #include 5 | 6 | uint8_t inb(uint16_t port); 7 | void outb(uint16_t port, uint8_t data); 8 | 9 | void outw(uint16_t port, uint16_t data); 10 | uint16_t inw(uint16_t port); 11 | 12 | void outl(uint16_t port, uint32_t data); 13 | uint32_t inl(uint16_t port); 14 | 15 | void io_wait(); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /sys/include/arch/x86_64/exceptions.h: -------------------------------------------------------------------------------- 1 | #ifndef EXCEPTIONS_H_ 2 | #define EXCEPTIONS_H_ 3 | 4 | #include 5 | 6 | #define E_ISR(vec) _isr void __vec##vec(void* stackframe) 7 | #define REF_E_ISR(vec) __vec##vec 8 | 9 | void init_exceptions(void); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /sys/include/arch/x86_64/idt.h: -------------------------------------------------------------------------------- 1 | #ifndef IDT_H_ 2 | #define IDT_H_ 3 | 4 | #include 5 | #include 6 | 7 | 8 | struct interrupt_gate_descriptor { 9 | uint16_t offlow16; 10 | uint16_t cs; 11 | uint8_t ist : 2; 12 | uint8_t zero : 4; 13 | uint8_t attr : 4; 14 | uint8_t zero1 : 1; 15 | uint8_t dpl : 2; 16 | uint8_t p : 1; 17 | uint16_t offmid16; 18 | uint32_t offhigh32; 19 | uint32_t reserved; 20 | }; 21 | 22 | 23 | struct idtr { 24 | uint16_t limit; 25 | uint64_t base; 26 | } _packed; 27 | 28 | void register_exception_handler(uint8_t vector, void* isr); 29 | void register_irq(uint8_t irq, void* isr); 30 | void load_idt(void); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /sys/include/drivers/serial.h: -------------------------------------------------------------------------------- 1 | #ifndef SERIAL_H_ 2 | #define SERIAL_H_ 3 | 4 | 5 | void serial_init(void); 6 | void serial_write(const char* str); 7 | 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /sys/include/drivers/timer/pit.h: -------------------------------------------------------------------------------- 1 | #ifndef PIT_H_ 2 | #define PIT_H_ 3 | 4 | #include 5 | 6 | #define PIT_DIVIDEND 1193180 7 | 8 | 9 | void pit_set_count(uint16_t count); 10 | uint16_t pit_get_count(void); 11 | 12 | 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /sys/include/drivers/video/framebuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef FRAMEBUFFER_H_ 2 | #define FRAMEBUFFER_H_ 3 | 4 | #include 5 | 6 | 7 | void framebuffer_init(void); 8 | 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /sys/include/fs/devfs.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVFS_H_ 2 | #define DEVFS_H_ 3 | 4 | #include 5 | #include 6 | 7 | #define DEVFS_OPEN_RETVAL NULL 8 | 9 | void devfs_init(void); 10 | int register_chrdev(const char* name, file_ops_t* fops); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /sys/include/fs/tmpfs.h: -------------------------------------------------------------------------------- 1 | #ifndef TMPFS_H_ 2 | #define TMPFS_H_ 3 | 4 | #include 5 | 6 | 7 | void tmpfs_init(void); 8 | 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /sys/include/fs/vfs.h: -------------------------------------------------------------------------------- 1 | #ifndef FS_VFS_H_ 2 | #define FS_VFS_H_ 3 | 4 | 5 | #include 6 | #include 7 | 8 | struct vfs_fs; 9 | 10 | 11 | typedef struct { 12 | int(*create)(const char* name); 13 | void*(*open)(const char* name); 14 | void(*read)(void* fs_node, char* buf, size_t n_bytes); 15 | void(*write)(void* fs_node, char* buf, size_t n_bytes); 16 | void(*close)(void* fs_node); 17 | } file_ops_t; 18 | 19 | typedef struct vfs_node { 20 | struct vfs_fs* filesystem; 21 | char* name; 22 | struct vfs_node* parent; 23 | size_t n_children; 24 | file_ops_t* fops; 25 | HASHMAP_TYPE(struct vfs_node*) children; 26 | } vfs_node_t; 27 | 28 | typedef struct { 29 | vfs_node_t* vfs_node; 30 | void* fs_node; /* Could point to any structure the filesystem defines */ 31 | } FILE; 32 | 33 | typedef struct vfs_fs { 34 | file_ops_t* fops; 35 | file_ops_t* default_fops; /* File operations for each file in this filesystem */ 36 | } vfs_fs_t; 37 | 38 | vfs_node_t* vfs_make_node(vfs_fs_t* fs, vfs_node_t* parent, const char* name, uint8_t is_dir, file_ops_t* fops); 39 | vfs_node_t* vfs_get_root(void); 40 | void vfs_init(void); 41 | 42 | FILE* fopen(const char* path, const char* mode); 43 | void fread(FILE* stream, char* out_ptr, size_t n_bytes); 44 | void fwrite(FILE* stream, char* in_ptr, size_t n_bytes); 45 | void fclose(FILE* stream); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /sys/include/intr/init.h: -------------------------------------------------------------------------------- 1 | #ifndef INTR_INIT_H_ 2 | #define INTR_INIT_H_ 3 | 4 | void init_interrupts(void); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /sys/include/intr/irq.h: -------------------------------------------------------------------------------- 1 | #ifndef IRQ_H_ 2 | #define IRQ_H_ 3 | 4 | #include 5 | 6 | _naked void _irq0(void); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /sys/include/lib/asm.h: -------------------------------------------------------------------------------- 1 | #ifndef ASM_H_ 2 | #define ASM_H_ 3 | 4 | 5 | #define ASMV(_asm) __asm__ __volatile__(_asm) 6 | #define _packed __attribute__((packed)) 7 | #define _isr __attribute__((interrupt)) 8 | #define _noreturn __attribute__((noreturn)) 9 | #define _naked __attribute__((naked)) 10 | #define _aligned(n) __attribute__((aligned(n))) 11 | #define _unused __attribute__((unused)) 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sys/include/lib/assert.h: -------------------------------------------------------------------------------- 1 | #ifndef ASSERT_H_ 2 | #define ASSERT_H_ 3 | 4 | #include 5 | #include 6 | 7 | #define ASSERT(condition, failmsg) \ 8 | if (!(condition)) { \ 9 | printk(PRINTK_PANIC "ASSERTION \"" #condition "\" FAILED (%s:%d)\n" failmsg, __FILE__, __LINE__); \ 10 | ASMV("cli; hlt"); \ 11 | } 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sys/include/lib/hashmap.h: -------------------------------------------------------------------------------- 1 | #ifndef HASHMAP_H_ 2 | #define HASHMAP_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | uint32_t hashmap_hash(const void* data, size_t length); 10 | 11 | #define HASHMAP_KEY_DATA_MAX 256 12 | 13 | #define HASHMAP_INIT(CAP) { .cap = (CAP), .buckets = NULL } 14 | 15 | #define HASHMAP_TYPE(TYPE) \ 16 | struct { \ 17 | size_t cap; \ 18 | struct { \ 19 | size_t cap; \ 20 | size_t filled; \ 21 | struct { \ 22 | uint8_t key_data[HASHMAP_KEY_DATA_MAX]; \ 23 | size_t key_length; \ 24 | TYPE item; \ 25 | } *items; \ 26 | } *buckets; \ 27 | } 28 | 29 | #define HASHMAP_GET(HASHMAP, RET, KEY_DATA, KEY_LENGTH) ({ \ 30 | bool HASHMAP_GET_ok = false; \ 31 | \ 32 | __auto_type HASHMAP_GET_key_data = KEY_DATA; \ 33 | __auto_type HASHMAP_GET_key_length = KEY_LENGTH; \ 34 | \ 35 | __auto_type HASHMAP_GET_hashmap = HASHMAP; \ 36 | \ 37 | size_t HASHMAP_GET_hash = hashmap_hash(HASHMAP_GET_key_data, HASHMAP_GET_key_length); \ 38 | size_t HASHMAP_GET_index = HASHMAP_GET_hash % HASHMAP_GET_hashmap->cap; \ 39 | \ 40 | __auto_type HASHMAP_GET_bucket = &HASHMAP_GET_hashmap->buckets[HASHMAP_GET_index]; \ 41 | \ 42 | for (size_t HASHMAP_GET_i = 0; HASHMAP_GET_i < HASHMAP_GET_bucket->filled; HASHMAP_GET_i++) { \ 43 | if (HASHMAP_GET_key_length != HASHMAP_GET_bucket->items[HASHMAP_GET_i].key_length) { \ 44 | continue; \ 45 | } \ 46 | if (kmemcmp(HASHMAP_GET_key_data, \ 47 | HASHMAP_GET_bucket->items[HASHMAP_GET_i].key_data, \ 48 | HASHMAP_GET_key_length) == 0) { \ 49 | RET = HASHMAP_GET_bucket->items[HASHMAP_GET_i].item; \ 50 | HASHMAP_GET_ok = true; \ 51 | break; \ 52 | } \ 53 | } \ 54 | \ 55 | HASHMAP_GET_ok; \ 56 | }) 57 | 58 | #define HASHMAP_SGET(HASHMAP, RET, STRING) ({ \ 59 | const char *HASHMAP_SGET_string = (STRING); \ 60 | HASHMAP_GET(HASHMAP, RET, HASHMAP_SGET_string, kstrlen(HASHMAP_SGET_string)); \ 61 | }) 62 | 63 | #define HASHMAP_INSERT(HASHMAP, KEY_DATA, KEY_LENGTH, ITEM) do { \ 64 | __auto_type HASHMAP_INSERT_key_data = KEY_DATA; \ 65 | __auto_type HASHMAP_INSERT_key_length = KEY_LENGTH; \ 66 | \ 67 | __auto_type HASHMAP_INSERT_hashmap = HASHMAP; \ 68 | if (HASHMAP_INSERT_hashmap->buckets == NULL) { \ 69 | HASHMAP_INSERT_hashmap->buckets = \ 70 | kmalloc(HASHMAP_INSERT_hashmap->cap * sizeof(*HASHMAP_INSERT_hashmap->buckets)); \ 71 | } \ 72 | \ 73 | size_t HASHMAP_INSERT_hash = hashmap_hash(HASHMAP_INSERT_key_data, HASHMAP_INSERT_key_length); \ 74 | size_t HASHMAP_INSERT_index = HASHMAP_INSERT_hash % HASHMAP_INSERT_hashmap->cap; \ 75 | \ 76 | __auto_type HASHMAP_INSERT_bucket = &HASHMAP_INSERT_hashmap->buckets[HASHMAP_INSERT_index]; \ 77 | \ 78 | if (HASHMAP_INSERT_bucket->cap == 0) { \ 79 | HASHMAP_INSERT_bucket->cap = 16; \ 80 | HASHMAP_INSERT_bucket->items = \ 81 | kmalloc(HASHMAP_INSERT_bucket->cap * sizeof(*HASHMAP_INSERT_bucket->items)); \ 82 | } \ 83 | \ 84 | if (HASHMAP_INSERT_bucket->filled == HASHMAP_INSERT_bucket->cap) { \ 85 | HASHMAP_INSERT_bucket->cap *= 2; \ 86 | HASHMAP_INSERT_bucket->items = \ 87 | krealloc(HASHMAP_INSERT_bucket->items, \ 88 | HASHMAP_INSERT_bucket->cap * sizeof(*HASHMAP_INSERT_bucket->items)); \ 89 | } \ 90 | \ 91 | __auto_type HASHMAP_INSERT_item = &HASHMAP_INSERT_bucket->items[HASHMAP_INSERT_bucket->filled]; \ 92 | \ 93 | kmemcpy(HASHMAP_INSERT_item->key_data, HASHMAP_INSERT_key_data, HASHMAP_INSERT_key_length); \ 94 | HASHMAP_INSERT_item->key_length = HASHMAP_INSERT_key_length; \ 95 | HASHMAP_INSERT_item->item = ITEM; \ 96 | \ 97 | HASHMAP_INSERT_bucket->filled++; \ 98 | } while (0) 99 | 100 | #define HASHMAP_SINSERT(HASHMAP, STRING, ITEM) do { \ 101 | const char *HASHMAP_SINSERT_string = (STRING); \ 102 | HASHMAP_INSERT(HASHMAP, HASHMAP_SINSERT_string, kstrlen(HASHMAP_SINSERT_string), ITEM); \ 103 | } while (0) 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /sys/include/lib/limine.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIMINE_H 2 | #define _LIMINE_H 1 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | 10 | /* Misc */ 11 | 12 | #ifdef LIMINE_NO_POINTERS 13 | # define LIMINE_PTR(TYPE) uint64_t 14 | #else 15 | # define LIMINE_PTR(TYPE) TYPE 16 | #endif 17 | 18 | #define LIMINE_COMMON_MAGIC 0xc7b1dd30df4c8b88, 0x0a82e883a194f07b 19 | 20 | struct limine_uuid { 21 | uint32_t a; 22 | uint16_t b; 23 | uint16_t c; 24 | uint8_t d[8]; 25 | }; 26 | 27 | #define LIMINE_MEDIA_TYPE_GENERIC 0 28 | #define LIMINE_MEDIA_TYPE_OPTICAL 1 29 | #define LIMINE_MEDIA_TYPE_TFTP 2 30 | 31 | struct limine_file { 32 | uint64_t revision; 33 | LIMINE_PTR(void *) address; 34 | uint64_t size; 35 | LIMINE_PTR(char *) path; 36 | LIMINE_PTR(char *) cmdline; 37 | uint32_t media_type; 38 | uint32_t unused; 39 | uint32_t tftp_ip; 40 | uint32_t tftp_port; 41 | uint32_t partition_index; 42 | uint32_t mbr_disk_id; 43 | struct limine_uuid gpt_disk_uuid; 44 | struct limine_uuid gpt_part_uuid; 45 | struct limine_uuid part_uuid; 46 | }; 47 | 48 | /* Boot info */ 49 | 50 | #define LIMINE_BOOTLOADER_INFO_REQUEST { LIMINE_COMMON_MAGIC, 0xf55038d8e2a1202f, 0x279426fcf5f59740 } 51 | 52 | struct limine_bootloader_info_response { 53 | uint64_t revision; 54 | LIMINE_PTR(char *) name; 55 | LIMINE_PTR(char *) version; 56 | }; 57 | 58 | struct limine_bootloader_info_request { 59 | uint64_t id[4]; 60 | uint64_t revision; 61 | LIMINE_PTR(struct limine_bootloader_info_response *) response; 62 | }; 63 | 64 | /* Stack size */ 65 | 66 | #define LIMINE_STACK_SIZE_REQUEST { LIMINE_COMMON_MAGIC, 0x224ef0460a8e8926, 0xe1cb0fc25f46ea3d } 67 | 68 | struct limine_stack_size_response { 69 | uint64_t revision; 70 | }; 71 | 72 | struct limine_stack_size_request { 73 | uint64_t id[4]; 74 | uint64_t revision; 75 | LIMINE_PTR(struct limine_stack_size_response *) response; 76 | uint64_t stack_size; 77 | }; 78 | 79 | /* HHDM */ 80 | 81 | #define LIMINE_HHDM_REQUEST { LIMINE_COMMON_MAGIC, 0x48dcf1cb8ad2b852, 0x63984e959a98244b } 82 | 83 | struct limine_hhdm_response { 84 | uint64_t revision; 85 | uint64_t offset; 86 | }; 87 | 88 | struct limine_hhdm_request { 89 | uint64_t id[4]; 90 | uint64_t revision; 91 | LIMINE_PTR(struct limine_hhdm_response *) response; 92 | }; 93 | 94 | /* Framebuffer */ 95 | 96 | #define LIMINE_FRAMEBUFFER_REQUEST { LIMINE_COMMON_MAGIC, 0x9d5827dcd881dd75, 0xa3148604f6fab11b } 97 | 98 | #define LIMINE_FRAMEBUFFER_RGB 1 99 | 100 | struct limine_framebuffer { 101 | LIMINE_PTR(void *) address; 102 | uint64_t width; 103 | uint64_t height; 104 | uint64_t pitch; 105 | uint16_t bpp; 106 | uint8_t memory_model; 107 | uint8_t red_mask_size; 108 | uint8_t red_mask_shift; 109 | uint8_t green_mask_size; 110 | uint8_t green_mask_shift; 111 | uint8_t blue_mask_size; 112 | uint8_t blue_mask_shift; 113 | uint8_t unused[7]; 114 | uint64_t edid_size; 115 | LIMINE_PTR(void *) edid; 116 | }; 117 | 118 | struct limine_framebuffer_response { 119 | uint64_t revision; 120 | uint64_t framebuffer_count; 121 | LIMINE_PTR(struct limine_framebuffer **) framebuffers; 122 | }; 123 | 124 | struct limine_framebuffer_request { 125 | uint64_t id[4]; 126 | uint64_t revision; 127 | LIMINE_PTR(struct limine_framebuffer_response *) response; 128 | }; 129 | 130 | /* Framebuffer (legacy) */ 131 | 132 | #define LIMINE_FRAMEBUFFER_LEGACY_REQUEST { LIMINE_COMMON_MAGIC, 0xcbfe81d7dd2d1977, 0x063150319ebc9b71 } 133 | 134 | struct limine_framebuffer_legacy { 135 | LIMINE_PTR(void *) address; 136 | uint16_t width; 137 | uint16_t height; 138 | uint16_t pitch; 139 | uint16_t bpp; 140 | uint8_t memory_model; 141 | uint8_t red_mask_size; 142 | uint8_t red_mask_shift; 143 | uint8_t green_mask_size; 144 | uint8_t green_mask_shift; 145 | uint8_t blue_mask_size; 146 | uint8_t blue_mask_shift; 147 | uint8_t unused; 148 | uint64_t edid_size; 149 | LIMINE_PTR(void *) edid; 150 | }; 151 | 152 | struct limine_framebuffer_legacy_response { 153 | uint64_t revision; 154 | uint64_t framebuffer_count; 155 | LIMINE_PTR(struct limine_framebuffer_legacy **) framebuffers; 156 | }; 157 | 158 | struct limine_framebuffer_legacy_request { 159 | uint64_t id[4]; 160 | uint64_t revision; 161 | LIMINE_PTR(struct limine_framebuffer_legacy_response *) response; 162 | }; 163 | 164 | /* Terminal */ 165 | 166 | #define LIMINE_TERMINAL_REQUEST { LIMINE_COMMON_MAGIC, 0xc8ac59310c2b0844, 0xa68d0c7265d38878 } 167 | 168 | #define LIMINE_TERMINAL_CB_DEC 10 169 | #define LIMINE_TERMINAL_CB_BELL 20 170 | #define LIMINE_TERMINAL_CB_PRIVATE_ID 30 171 | #define LIMINE_TERMINAL_CB_STATUS_REPORT 40 172 | #define LIMINE_TERMINAL_CB_POS_REPORT 50 173 | #define LIMINE_TERMINAL_CB_KBD_LEDS 60 174 | #define LIMINE_TERMINAL_CB_MODE 70 175 | #define LIMINE_TERMINAL_CB_LINUX 80 176 | 177 | #define LIMINE_TERMINAL_CTX_SIZE ((uint64_t)(-1)) 178 | #define LIMINE_TERMINAL_CTX_SAVE ((uint64_t)(-2)) 179 | #define LIMINE_TERMINAL_CTX_RESTORE ((uint64_t)(-3)) 180 | #define LIMINE_TERMINAL_FULL_REFRESH ((uint64_t)(-4)) 181 | 182 | struct limine_terminal; 183 | 184 | typedef void (*limine_terminal_write)(struct limine_terminal *, const char *, uint64_t); 185 | typedef void (*limine_terminal_callback)(struct limine_terminal *, uint64_t, uint64_t, uint64_t, uint64_t); 186 | 187 | struct limine_terminal { 188 | uint64_t columns; 189 | uint64_t rows; 190 | LIMINE_PTR(struct limine_framebuffer *) framebuffer; 191 | }; 192 | 193 | struct limine_terminal_response { 194 | uint64_t revision; 195 | uint64_t terminal_count; 196 | LIMINE_PTR(struct limine_terminal **) terminals; 197 | LIMINE_PTR(limine_terminal_write) write; 198 | }; 199 | 200 | struct limine_terminal_request { 201 | uint64_t id[4]; 202 | uint64_t revision; 203 | LIMINE_PTR(struct limine_terminal_response *) response; 204 | LIMINE_PTR(limine_terminal_callback) callback; 205 | }; 206 | 207 | /* Terminal (legacy) */ 208 | 209 | #define LIMINE_TERMINAL_LEGACY_REQUEST { LIMINE_COMMON_MAGIC, 0x0785a0aea5d0750f, 0x1c1936fee0d6cf6e } 210 | 211 | struct limine_terminal_legacy; 212 | 213 | typedef void (*limine_terminal_legacy_write)(struct limine_terminal_legacy *, const char *, uint64_t); 214 | typedef void (*limine_terminal_legacy_callback)(struct limine_terminal_legacy *, uint64_t, uint64_t, uint64_t, uint64_t); 215 | 216 | struct limine_terminal_legacy { 217 | uint32_t columns; 218 | uint32_t rows; 219 | LIMINE_PTR(struct limine_framebuffer_legacy *) framebuffer; 220 | }; 221 | 222 | struct limine_terminal_legacy_response { 223 | uint64_t revision; 224 | uint64_t terminal_count; 225 | LIMINE_PTR(struct limine_terminal_legacy **) terminals; 226 | LIMINE_PTR(limine_terminal_legacy_write) write; 227 | }; 228 | 229 | struct limine_terminal_legacy_request { 230 | uint64_t id[4]; 231 | uint64_t revision; 232 | LIMINE_PTR(struct limine_terminal_legacy_response *) response; 233 | LIMINE_PTR(limine_terminal_legacy_callback) callback; 234 | }; 235 | 236 | /* 5-level paging */ 237 | 238 | #define LIMINE_5_LEVEL_PAGING_REQUEST { LIMINE_COMMON_MAGIC, 0x94469551da9b3192, 0xebe5e86db7382888 } 239 | 240 | struct limine_5_level_paging_response { 241 | uint64_t revision; 242 | }; 243 | 244 | struct limine_5_level_paging_request { 245 | uint64_t id[4]; 246 | uint64_t revision; 247 | LIMINE_PTR(struct limine_5_level_paging_response *) response; 248 | }; 249 | 250 | /* SMP */ 251 | 252 | #define LIMINE_SMP_REQUEST { LIMINE_COMMON_MAGIC, 0x95a67b819a1b857e, 0xa0b61b723b6a73e0 } 253 | 254 | #define LIMINE_SMP_X2APIC (1 << 0) 255 | 256 | struct limine_smp_info; 257 | 258 | typedef void (*limine_goto_address)(struct limine_smp_info *); 259 | 260 | struct limine_smp_info { 261 | uint32_t processor_id; 262 | uint32_t lapic_id; 263 | uint64_t reserved; 264 | LIMINE_PTR(limine_goto_address) goto_address; 265 | uint64_t extra_argument; 266 | }; 267 | 268 | struct limine_smp_response { 269 | uint64_t revision; 270 | uint32_t flags; 271 | uint32_t bsp_lapic_id; 272 | uint64_t cpu_count; 273 | LIMINE_PTR(struct limine_smp_info **) cpus; 274 | }; 275 | 276 | struct limine_smp_request { 277 | uint64_t id[4]; 278 | uint64_t revision; 279 | LIMINE_PTR(struct limine_smp_response *) response; 280 | uint64_t flags; 281 | }; 282 | 283 | /* Memory map */ 284 | 285 | #define LIMINE_MEMMAP_REQUEST { LIMINE_COMMON_MAGIC, 0x67cf3d9d378a806f, 0xe304acdfc50c3c62 } 286 | 287 | #define LIMINE_MEMMAP_USABLE 0 288 | #define LIMINE_MEMMAP_RESERVED 1 289 | #define LIMINE_MEMMAP_ACPI_RECLAIMABLE 2 290 | #define LIMINE_MEMMAP_ACPI_NVS 3 291 | #define LIMINE_MEMMAP_BAD_MEMORY 4 292 | #define LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE 5 293 | #define LIMINE_MEMMAP_KERNEL_AND_MODULES 6 294 | #define LIMINE_MEMMAP_FRAMEBUFFER 7 295 | 296 | struct limine_memmap_entry { 297 | uint64_t base; 298 | uint64_t length; 299 | uint64_t type; 300 | }; 301 | 302 | struct limine_memmap_response { 303 | uint64_t revision; 304 | uint64_t entry_count; 305 | LIMINE_PTR(struct limine_memmap_entry **) entries; 306 | }; 307 | 308 | struct limine_memmap_request { 309 | uint64_t id[4]; 310 | uint64_t revision; 311 | LIMINE_PTR(struct limine_memmap_response *) response; 312 | }; 313 | 314 | /* Entry point */ 315 | 316 | #define LIMINE_ENTRY_POINT_REQUEST { LIMINE_COMMON_MAGIC, 0x13d86c035a1cd3e1, 0x2b0caa89d8f3026a } 317 | 318 | typedef void (*limine_entry_point)(void); 319 | 320 | struct limine_entry_point_response { 321 | uint64_t revision; 322 | }; 323 | 324 | struct limine_entry_point_request { 325 | uint64_t id[4]; 326 | uint64_t revision; 327 | LIMINE_PTR(struct limine_entry_point_response *) response; 328 | LIMINE_PTR(limine_entry_point) entry; 329 | }; 330 | 331 | /* Kernel File */ 332 | 333 | #define LIMINE_KERNEL_FILE_REQUEST { LIMINE_COMMON_MAGIC, 0xad97e90e83f1ed67, 0x31eb5d1c5ff23b69 } 334 | 335 | struct limine_kernel_file_response { 336 | uint64_t revision; 337 | LIMINE_PTR(struct limine_file *) kernel_file; 338 | }; 339 | 340 | struct limine_kernel_file_request { 341 | uint64_t id[4]; 342 | uint64_t revision; 343 | LIMINE_PTR(struct limine_kernel_file_response *) response; 344 | }; 345 | 346 | /* Module */ 347 | 348 | #define LIMINE_MODULE_REQUEST { LIMINE_COMMON_MAGIC, 0x3e7e279702be32af, 0xca1c4f3bd1280cee } 349 | 350 | struct limine_module_response { 351 | uint64_t revision; 352 | uint64_t module_count; 353 | LIMINE_PTR(struct limine_file **) modules; 354 | }; 355 | 356 | struct limine_module_request { 357 | uint64_t id[4]; 358 | uint64_t revision; 359 | LIMINE_PTR(struct limine_module_response *) response; 360 | }; 361 | 362 | /* RSDP */ 363 | 364 | #define LIMINE_RSDP_REQUEST { LIMINE_COMMON_MAGIC, 0xc5e77b6b397e7b43, 0x27637845accdcf3c } 365 | 366 | struct limine_rsdp_response { 367 | uint64_t revision; 368 | LIMINE_PTR(void *) address; 369 | }; 370 | 371 | struct limine_rsdp_request { 372 | uint64_t id[4]; 373 | uint64_t revision; 374 | LIMINE_PTR(struct limine_rsdp_response *) response; 375 | }; 376 | 377 | /* SMBIOS */ 378 | 379 | #define LIMINE_SMBIOS_REQUEST { LIMINE_COMMON_MAGIC, 0x9e9046f11e095391, 0xaa4a520fefbde5ee } 380 | 381 | struct limine_smbios_response { 382 | uint64_t revision; 383 | LIMINE_PTR(void *) entry_32; 384 | LIMINE_PTR(void *) entry_64; 385 | }; 386 | 387 | struct limine_smbios_request { 388 | uint64_t id[4]; 389 | uint64_t revision; 390 | LIMINE_PTR(struct limine_smbios_response *) response; 391 | }; 392 | 393 | /* EFI system table */ 394 | 395 | #define LIMINE_EFI_SYSTEM_TABLE_REQUEST { LIMINE_COMMON_MAGIC, 0x5ceba5163eaaf6d6, 0x0a6981610cf65fcc } 396 | 397 | struct limine_efi_system_table_response { 398 | uint64_t revision; 399 | LIMINE_PTR(void *) address; 400 | }; 401 | 402 | struct limine_efi_system_table_request { 403 | uint64_t id[4]; 404 | uint64_t revision; 405 | LIMINE_PTR(struct limine_efi_system_table_response *) response; 406 | }; 407 | 408 | /* Boot time */ 409 | 410 | #define LIMINE_BOOT_TIME_REQUEST { LIMINE_COMMON_MAGIC, 0x502746e184c088aa, 0xfbc5ec83e6327893 } 411 | 412 | struct limine_boot_time_response { 413 | uint64_t revision; 414 | int64_t boot_time; 415 | }; 416 | 417 | struct limine_boot_time_request { 418 | uint64_t id[4]; 419 | uint64_t revision; 420 | LIMINE_PTR(struct limine_boot_time_response *) response; 421 | }; 422 | 423 | /* Kernel address */ 424 | 425 | #define LIMINE_KERNEL_ADDRESS_REQUEST { LIMINE_COMMON_MAGIC, 0x71ba76863cc55f63, 0xb2644a48c516a487 } 426 | 427 | struct limine_kernel_address_response { 428 | uint64_t revision; 429 | uint64_t physical_base; 430 | uint64_t virtual_base; 431 | }; 432 | 433 | struct limine_kernel_address_request { 434 | uint64_t id[4]; 435 | uint64_t revision; 436 | LIMINE_PTR(struct limine_kernel_address_response *) response; 437 | }; 438 | 439 | #ifdef __cplusplus 440 | } 441 | #endif 442 | 443 | #endif 444 | -------------------------------------------------------------------------------- /sys/include/lib/log.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_H_ 2 | #define LOG_H_ 3 | 4 | #include 5 | #include 6 | 7 | #define PRINTK_RED "\e[0;31m" 8 | #define PRINTK_PANIC PRINTK_RED "kpanic: " 9 | 10 | void printk(const char* fmt, ...); 11 | 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sys/include/lib/math.h: -------------------------------------------------------------------------------- 1 | #ifndef MATH_H_ 2 | #define MATH_H_ 3 | 4 | #define ALIGN_DOWN(address, align) ((address) & ~((align)-1)) 5 | #define ALIGN_UP(address, align) (((address) + (align)-1) & ~((align)-1)) 6 | #define BIG_ENDIAN(v) ((((v) & 0xFF) << 8) | (((v) >> 8) & 0xFF)) 7 | #define IS_POWER_OF_2(x) ((x & (x-1)) == 0) 8 | #define OFF_BY(off, by) (~(off % ~(by))) 9 | #define DIV_ROUNDUP(VALUE, DIV) ({ \ 10 | typeof(VALUE) DIV_ROUNDUP_value = VALUE; \ 11 | typeof(DIV) DIV_ROUNDUP_div = DIV; \ 12 | (DIV_ROUNDUP_value + (DIV_ROUNDUP_div - 1)) / DIV_ROUNDUP_div; \ 13 | }) 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sys/include/lib/string.h: -------------------------------------------------------------------------------- 1 | #ifndef STRING_H_ 2 | #define STRING_H_ 3 | 4 | #include 5 | 6 | size_t kstrlen(const char* str); 7 | bool kmemcmp(const char* str1, const char* str2, size_t n); 8 | char* dec2str(size_t dec); 9 | uint8_t* kstrncpy(uint8_t* dst, const uint8_t* src, const uint8_t len); 10 | void kmemcpy(void* dst, const void* src, size_t len); 11 | uint8_t* hex2str(uint64_t hex_num); 12 | void kmemzero(void* ptr, size_t n); 13 | void kmemset(void* ptr, uint8_t data, size_t n); 14 | void kmemset16(void* ptr, uint16_t data, size_t n); 15 | void kmemset32(void* ptr, uint32_t data, size_t n); 16 | void kmemset64(void* ptr, uint64_t data, size_t n); 17 | uint8_t kstrcmp(const char* str1, const char* str2); 18 | uint8_t kstrncmp(const char* str1, const char* str2, size_t n); 19 | uint64_t hex2int(char* hex, size_t len); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /sys/include/lib/types.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPES_H_ 2 | #define TYPES_H_ 3 | 4 | #include 5 | 6 | #define NULL (void*)0ULL 7 | #define true 1 8 | #define false 0 9 | 10 | #if defined(__x86_64__) || defined(__aarch64__) 11 | typedef unsigned long long size_t; 12 | typedef signed long long ssize_t; 13 | #elif defined(__i386__) 14 | typedef unsigned int size_t; 15 | typedef signed int ssize_t; 16 | #endif 17 | 18 | typedef size_t uintptr_t; 19 | typedef signed int int32_t; 20 | typedef signed long long int64_t; 21 | typedef unsigned int uint32_t; 22 | typedef unsigned short uint16_t; 23 | typedef signed short int16_t; 24 | typedef unsigned char uint8_t; 25 | typedef signed char int8_t; 26 | typedef unsigned long long uint64_t; 27 | typedef uint8_t bool; 28 | typedef uint32_t wchar_t; 29 | typedef size_t off_t; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /sys/include/mm/heap.h: -------------------------------------------------------------------------------- 1 | #ifndef HEAP_H_ 2 | #define HEAP_H_ 3 | 4 | #include 5 | 6 | 7 | #define HEAP_SIZE_PAGES 10 8 | 9 | 10 | void* kmalloc(size_t sz); 11 | void* krealloc(void* oldptr, size_t sz); 12 | void kfree(void* ptr); 13 | 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sys/include/mm/pmm.h: -------------------------------------------------------------------------------- 1 | #ifndef PMM_H_ 2 | #define PMM_H_ 3 | 4 | #include 5 | 6 | 7 | void pmm_init(void); 8 | uintptr_t pmm_alloc(size_t frames); 9 | void pmm_free(uintptr_t ptr, size_t frames); 10 | 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /sys/include/mm/vmm.h: -------------------------------------------------------------------------------- 1 | #ifndef VMM_H_ 2 | #define VMM_H_ 3 | 4 | #include 5 | #include 6 | 7 | #define VMM_HIGHER_HALF (hhdm_request.response->offset) 8 | 9 | extern volatile struct limine_hhdm_request hhdm_request; 10 | 11 | 12 | typedef uintptr_t pagemap_t; 13 | typedef uintptr_t vaddr_t; 14 | typedef uintptr_t paddr_t; 15 | 16 | #define PTE_ADDR_MASK 0x000FFFFFFFFFF000 17 | #define PTE_PRESENT (1ull << 0) 18 | #define PTE_WRITABLE (1ull << 1) 19 | #define PTE_USER (1ULL << 2) 20 | #define PTE_NX (1ULL << 63) 21 | #define PTE_GET_ADDR(VALUE) ((VALUE) & PTE_ADDR_MASK) 22 | #define PAGE_SIZE 0x1000 23 | 24 | 25 | void vmm_map_page(pagemap_t top_level, vaddr_t vaddr, paddr_t paddr, uint64_t flags); 26 | void* vmm_alloc(size_t pages); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /sys/include/sched/proc.h: -------------------------------------------------------------------------------- 1 | #ifndef PROC_H_ 2 | #define PROC_H_ 3 | 4 | #include 5 | 6 | 7 | typedef struct { 8 | uint8_t is_running : 1; 9 | uint32_t timeslice; 10 | uintptr_t cr3; 11 | } thread_t; 12 | 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /sys/include/sched/sched.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHED_H_ 2 | #define SCHED_H_ 3 | 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | uint64_t rdi; 9 | uint64_t rsi; 10 | uint64_t rbx; 11 | uint64_t rdx; 12 | uint64_t rcx; 13 | uint64_t rax; 14 | uint64_t r8; 15 | uint64_t r9; 16 | uint64_t r10; 17 | uint64_t r11; 18 | uint64_t r12; 19 | uint64_t r13; 20 | uint64_t r14; 21 | uint64_t r15; 22 | uint64_t rbp; 23 | uint64_t trapno; 24 | uint64_t rip; 25 | uint16_t cs; 26 | uint64_t rflags; 27 | uint64_t rsp; 28 | uint16_t ss; 29 | } _packed trapframe_t; 30 | 31 | void sched_init(void); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /sys/include/sync/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifndef SYNC_SPINLOCK_H_ 2 | #define SYNC_SPINLOCK_H_ 3 | 4 | #include 5 | #include 6 | 7 | typedef uint8_t spinlock_t; 8 | 9 | #define SPINLOCK_ACQUIRE(LOCK) \ 10 | do { \ 11 | if (__sync_bool_compare_and_swap(&LOCK, 0, 1)) { \ 12 | break; \ 13 | } \ 14 | ASMV("pause"); \ 15 | } while (1); 16 | 17 | 18 | #define SPINLOCK_RELEASE(LOCK) __sync_bool_compare_and_swap(&LOCK, 1, 0) 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /sys/link.ld: -------------------------------------------------------------------------------- 1 | /* Tell the linker that we want an x86_64 ELF64 output file */ 2 | OUTPUT_FORMAT(elf64-x86-64) 3 | OUTPUT_ARCH(i386:x86-64) 4 | 5 | /* We want the symbol _start to be our entry point */ 6 | ENTRY(_start) 7 | 8 | /* Define the program headers we want so the bootloader gives us the right */ 9 | /* MMU permissions */ 10 | PHDRS 11 | { 12 | text PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */ 13 | rodata PT_LOAD FLAGS((1 << 2)) ; /* Read only */ 14 | data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */ 15 | } 16 | 17 | SECTIONS 18 | { 19 | /* We wanna be placed in the topmost 2GiB of the address space, for optimisations */ 20 | /* and because that is what the Limine spec mandates. */ 21 | /* Any address in this region will do, but often 0xffffffff80000000 is chosen as */ 22 | /* that is the beginning of the region. */ 23 | . = 0xffffffff80000000; 24 | 25 | .text : { 26 | *(.text .text.*) 27 | } :text 28 | 29 | /* Move to the next memory page for .rodata */ 30 | . += CONSTANT(MAXPAGESIZE); 31 | 32 | .rodata : { 33 | *(.rodata .rodata.*) 34 | } :rodata 35 | 36 | /* Move to the next memory page for .data */ 37 | . += CONSTANT(MAXPAGESIZE); 38 | 39 | .data : { 40 | *(.data .data.*) 41 | } :data 42 | 43 | .bss : { 44 | *(COMMON) 45 | *(.bss .bss.*) 46 | } :data 47 | 48 | /* Discard notes since they may cause issues on some hosts. */ 49 | /DISCARD/ : { 50 | *(.note .note.*) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /sys/src/acpi/acpi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define APIC_TYPE_IO_APIC 1 9 | #define APIC_TYPE_INTERRUPT_OVERRIDE 2 10 | 11 | static volatile struct limine_rsdp_request rsdp_req = { 12 | .id = LIMINE_RSDP_REQUEST, 13 | .revision = 0 14 | }; 15 | 16 | 17 | static acpi_rsdt_t* rsdt = NULL; 18 | static acpi_madt_t* madt = NULL; 19 | 20 | void* ioapic_base = 0; 21 | void* lapic_base = 0; 22 | 23 | static size_t rsdt_entry_count = 0; 24 | 25 | static void find_madt(void) { 26 | for (uint32_t i = 0; i < rsdt_entry_count; ++i) { 27 | acpi_header_t* current = (acpi_header_t*)(uint64_t)rsdt->tables[i]; 28 | if (kstrncmp(current->signature, "APIC", 4) == 0) { 29 | madt = (acpi_madt_t*)current; 30 | return; 31 | } 32 | } 33 | } 34 | 35 | static void parse_madt(void) { 36 | lapic_base = (void*)(uint64_t)(madt->lapic_addr); 37 | uint8_t* cur = (uint8_t*)(madt + 1); 38 | uint8_t* end = (uint8_t*)madt + madt->header.length; 39 | 40 | while (cur < end) { 41 | apic_header_t* apic_header = (apic_header_t*)cur; 42 | if (apic_header->type == APIC_TYPE_IO_APIC) { 43 | io_apic_t* ioapic = (io_apic_t*)cur; 44 | ioapic_base = (void*)(uint64_t)ioapic->io_apic_addr; 45 | } 46 | 47 | cur += apic_header->length; 48 | } 49 | } 50 | 51 | 52 | static uint8_t do_checksum(const acpi_header_t* header) { 53 | uint8_t sum = 0; 54 | 55 | for (uint32_t i = 0; i < header->length; ++i) { 56 | sum += ((char*)header)[i]; 57 | } 58 | 59 | return sum % 0x100 == 0; 60 | } 61 | 62 | 63 | uint16_t acpi_remap_irq(uint8_t irq) { 64 | uint8_t* cur = (uint8_t*)(madt + 1); 65 | uint8_t* end = (uint8_t*)madt + madt->header.length; 66 | 67 | while (cur < end) { 68 | apic_header_t* apic_header = (apic_header_t*)cur; 69 | if (apic_header->type == APIC_TYPE_INTERRUPT_OVERRIDE) { 70 | apic_interrupt_override_t* intr_override = (apic_interrupt_override_t*)cur; 71 | if (intr_override->source == irq) { 72 | return intr_override->interrupt; 73 | } 74 | } 75 | 76 | cur += apic_header->length; 77 | } 78 | 79 | return irq; 80 | } 81 | 82 | void acpi_init(void) { 83 | printk("[acpi]: Initializing..\n"); 84 | acpi_rsdp_t* rsdp = rsdp_req.response->address; 85 | rsdt = (acpi_rsdt_t*)(uint64_t)rsdp->rsdtaddr; 86 | 87 | printk("[acpi]: Verifying RSDT..\n"); 88 | ASSERT(do_checksum(&rsdt->header), "ACPI RSDT checksum invalid!\n"); 89 | 90 | rsdt_entry_count = (rsdt->header.length - sizeof(rsdt->header)) / 4; 91 | printk("[acpi]: RSDT has %d entries\n", rsdt_entry_count); 92 | 93 | printk("[acpi]: Locating ACPI MADT..\n"); 94 | find_madt(); 95 | 96 | printk("[acpi]: ACPI MADT located @%x\n", madt); 97 | 98 | printk("[acpi]: Verifying ACPI MADT\n"); 99 | ASSERT(do_checksum(&madt->header), "ACPI MADT checksum invalid!\n"); 100 | 101 | parse_madt(); 102 | printk("[acpi]: I/O APIC base @%x\n", ioapic_base); 103 | printk("[acpi]: Local APIC base @%x\n", lapic_base); 104 | } 105 | -------------------------------------------------------------------------------- /sys/src/arch/bus/pci.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define CONFIG_ADDR 0xCF8 6 | #define CONFIG_DATA 0xCFC 7 | 8 | 9 | static uint16_t pci_config_read(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { 10 | uint32_t lbus = (uint32_t)bus; 11 | uint32_t lslot = (uint32_t)slot; 12 | uint32_t lfunc = (uint32_t)func; 13 | 14 | uint32_t address = (uint32_t)((lbus << 16) | (lslot << 11) | (lfunc << 8) | (offset & 0xFC) | ((uint32_t)0x80000000)); 15 | outl(CONFIG_ADDR, address); 16 | return (uint16_t)((inl(CONFIG_DATA) >> ((offset & 2) * 8)) & 0xFFFF); 17 | } 18 | 19 | 20 | static inline uint32_t get_bar0(uint8_t bus, uint8_t slot, uint8_t func) { 21 | uint16_t lo = pci_config_read(bus, slot, func, 0x10); 22 | uint16_t hi = pci_config_read(bus, slot, func, 0x12); 23 | return ((uint32_t)hi << 16 | lo); 24 | } 25 | 26 | 27 | static inline uint32_t get_bar1(uint8_t bus, uint8_t slot, uint8_t func) { 28 | uint16_t lo = pci_config_read(bus, slot, func, 0x14); 29 | uint16_t hi = pci_config_read(bus, slot, func, 0x16); 30 | return ((uint32_t)hi << 16 | lo); 31 | } 32 | 33 | 34 | static inline uint32_t get_bar2(uint8_t bus, uint8_t slot, uint8_t func) { 35 | uint16_t lo = pci_config_read(bus, slot, func, 0x18); 36 | uint16_t hi = pci_config_read(bus, slot, func, 0x1A); 37 | return ((uint32_t)hi << 16 | lo); 38 | } 39 | 40 | 41 | static inline uint32_t get_bar3(uint8_t bus, uint8_t slot, uint8_t func) { 42 | uint16_t lo = pci_config_read(bus, slot, func, 0x1C); 43 | uint16_t hi = pci_config_read(bus, slot, func, 0xE); 44 | return ((uint32_t)hi << 16 | lo); 45 | } 46 | 47 | static inline uint32_t get_bar4(uint8_t bus, uint8_t slot, uint8_t func) { 48 | uint16_t lo = pci_config_read(bus, slot, func, 0x20); 49 | uint16_t hi = pci_config_read(bus, slot, func, 0x22); 50 | return ((uint32_t)hi << 16 | lo); 51 | } 52 | 53 | static inline uint32_t get_bar5(uint8_t bus, uint8_t slot, uint8_t func) { 54 | uint16_t lo = pci_config_read(bus, slot, func, 0x24); 55 | uint16_t hi = pci_config_read(bus, slot, func, 0x26); 56 | return ((uint32_t)hi << 16 | lo); 57 | } 58 | 59 | 60 | static void config_write(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint16_t value) { 61 | uint32_t address = (uint32_t)(((uint32_t)bus << 16) | ((uint32_t)slot << 11) | ((uint32_t)func << 8) | (offset & 0xFC) | ((uint32_t)0x80000000)); 62 | outl(CONFIG_ADDR, address); 63 | outl(CONFIG_DATA, (uint16_t)value); 64 | } 65 | 66 | static inline uint8_t read_irq_line(uint8_t bus, uint8_t slot, uint8_t func) { 67 | return pci_config_read(bus, slot, func, 0x3C) & 0xFF; 68 | } 69 | 70 | 71 | static inline uint16_t read_vendor(uint8_t bus, uint8_t slot, uint8_t func) { 72 | return pci_config_read(bus, slot, func, 0x0); 73 | } 74 | 75 | 76 | static inline uint16_t read_devid(uint8_t bus, uint8_t slot, uint8_t func) { 77 | return pci_config_read(bus, slot, func, 0x2); 78 | } 79 | 80 | static inline uint8_t read_class(uint8_t bus, uint8_t slot, uint8_t func) { 81 | return pci_config_read(bus, slot, func, 0xA) >> 8; 82 | } 83 | 84 | static inline uint8_t read_subclass(uint8_t bus, uint8_t slot, uint8_t func) { 85 | return pci_config_read(bus, slot, func, 0xA) & 0xFF; 86 | } 87 | 88 | 89 | static inline uint8_t read_prog_if(uint8_t bus, uint8_t slot, uint8_t func) { 90 | return pci_config_read(bus, slot, func, 0x8) >> 8; 91 | } 92 | 93 | 94 | static inline void init_dev(pci_dev_t* dev, uint8_t bus, uint8_t slot, uint8_t func) { 95 | dev->bars[0] = get_bar0(bus, slot, func); 96 | dev->bars[1] = get_bar1(bus, slot, func); 97 | dev->bars[2] = get_bar2(bus, slot, func); 98 | dev->bars[3] = get_bar3(bus, slot, func); 99 | dev->bars[4] = get_bar4(bus, slot, func); 100 | dev->bars[5] = get_bar5(bus, slot, func); 101 | dev->bus = bus; 102 | dev->slot = slot; 103 | dev->func = func; 104 | } 105 | 106 | void pci_enable_bus_mastering(pci_dev_t* dev) { 107 | uint16_t val = pci_config_read(dev->bus, dev->slot, dev->func, 0x4); 108 | config_write(dev->bus, dev->slot, dev->func, 0x4, (val | (1 << 2) | (1 << 0))); 109 | } 110 | 111 | pci_dev_t* pci_find_any(uint8_t class, uint8_t subclass, int8_t interface) { 112 | pci_dev_t* dev = kmalloc(sizeof(pci_dev_t)); 113 | 114 | for (uint8_t bus = 0; bus < 5; ++bus) { 115 | for (uint8_t slot = 0; slot < 32; ++slot) { 116 | for (uint8_t func = 0; func < 8; ++func) { 117 | if (read_class(bus, slot, func) == class && read_subclass(bus, slot, func) == subclass) { 118 | if (interface != -1) { 119 | if (read_prog_if(bus, slot, func) != interface) continue; 120 | } 121 | 122 | init_dev(dev, bus, slot, func); 123 | return dev; 124 | } 125 | } 126 | } 127 | } 128 | 129 | kfree(dev); 130 | return NULL; 131 | } 132 | 133 | 134 | pci_dev_t* pci_find(uint16_t vendor_id, uint16_t device_id) { 135 | pci_dev_t* dev = kmalloc(sizeof(pci_dev_t)); 136 | 137 | for (uint8_t bus = 0; bus < 5; ++bus) { 138 | for (uint8_t slot = 0; slot < 32; ++slot) { 139 | for (uint8_t func = 0; func < 8; ++func) { 140 | if (read_vendor(bus, slot, func) == vendor_id && read_devid(bus, slot, func) == device_id) { 141 | init_dev(dev, bus, slot, func); 142 | return dev; 143 | } 144 | } 145 | } 146 | } 147 | 148 | kfree(dev); 149 | return NULL; 150 | } 151 | -------------------------------------------------------------------------------- /sys/src/arch/x86/apic/ioapic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Memory mapped register for I/O APIC access. 5 | #define IOREGSEL 0x00 6 | #define IOWIN 0x10 7 | 8 | // Other I/O APIC registers. 9 | #define IOAPICID 0x00 10 | #define IOAPICVER 0x01 11 | #define IOAPICARB 0x02 12 | #define IOREDTBL 0x10 13 | 14 | extern void* ioapic_base; 15 | 16 | static uint32_t read(uint8_t reg) { 17 | // Select the register by setting IOREGSEL to reg. 18 | *(volatile uint32_t*)ioapic_base = reg; 19 | 20 | // Return value in register by reading IOWIN. 21 | return *(volatile uint32_t*)(ioapic_base + IOWIN); 22 | } 23 | 24 | static void write(uint8_t reg, uint32_t value) { 25 | *(volatile uint32_t*)ioapic_base = reg; 26 | *(volatile uint32_t*)(ioapic_base + IOWIN) = value; 27 | } 28 | 29 | void ioapic_set_entry(uint8_t index, uint64_t data) { 30 | write(IOREDTBL + index * 2, (uint32_t)data); 31 | write(IOREDTBL + index * 2 + 1, (uint32_t)(data >> 32)); 32 | } 33 | 34 | void ioapic_init(void) { 35 | // Get the max amount of redirection entries from 36 | // bits 16:23 of IOAPICVER. 37 | uint32_t max_red_entries = ((read(IOAPICVER) >> 16) & 0xFF) + 1; 38 | 39 | // Mask all redirection entries. 40 | for (uint32_t i = 0; i < max_red_entries; ++i) { 41 | ioapic_set_entry(i, 1 << 16); 42 | } 43 | 44 | printk("[ioapic]: All redirection table entries masked.\n"); 45 | } 46 | -------------------------------------------------------------------------------- /sys/src/arch/x86/apic/lapic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | // Local APIC Registers 8 | #define LAPIC_ID 0x0020 // Local APIC ID 9 | #define LAPIC_VER 0x0030 // Local APIC Version 10 | #define LAPIC_TPR 0x0080 // Task Priority 11 | #define LAPIC_APR 0x0090 // Arbitration Priority 12 | #define LAPIC_PPR 0x00a0 // Processor Priority 13 | #define LAPIC_EOI 0x00b0 // EOI 14 | #define LAPIC_RRD 0x00c0 // Remote Read 15 | #define LAPIC_LDR 0x00d0 // Logical Destination 16 | #define LAPIC_DFR 0x00e0 // Destination Format 17 | #define LAPIC_SVR 0x00f0 // Spurious Interrupt Vector 18 | #define LAPIC_ISR 0x0100 // In-Service (8 registers) 19 | #define LAPIC_TMR 0x0180 // Trigger Mode (8 registers) 20 | #define LAPIC_IRR 0x0200 // Interrupt Request (8 registers) 21 | #define LAPIC_ESR 0x0280 // Error Status 22 | #define LAPIC_ICRLO 0x0300 // Interrupt Command 23 | #define LAPIC_ICRHI 0x0310 // Interrupt Command [63:32] 24 | #define LAPIC_TIMER 0x0320 // LVT Timer 25 | #define LAPIC_THERMAL 0x0330 // LVT Thermal Sensor 26 | #define LAPIC_PERF 0x0340 // LVT Performance Counter 27 | #define LAPIC_LINT0 0x0350 // LVT LINT0 28 | #define LAPIC_LINT1 0x0360 // LVT LINT1 29 | #define LAPIC_ERROR 0x0370 // LVT Error 30 | #define LAPIC_TICR 0x0380 // Initial Count (for Timer) 31 | #define LAPIC_TCCR 0x0390 // Current Count (for Timer) 32 | #define LAPIC_TDCR 0x03e0 // Divide Configuration (for Timer) 33 | 34 | // Delivery Mode 35 | #define ICR_FIXED 0x00000000 36 | #define ICR_LOWEST 0x00000100 37 | #define ICR_SMI 0x00000200 38 | #define ICR_NMI 0x00000400 39 | #define ICR_INIT 0x00000500 40 | #define ICR_STARTUP 0x00000600 41 | 42 | // Destination Mode 43 | #define ICR_PHYSICAL 0x00000000 44 | #define ICR_LOGICAL 0x00000800 45 | 46 | // Delivery Status 47 | #define ICR_IDLE 0x00000000 48 | #define ICR_SEND_PENDING 0x00001000 49 | 50 | // Level 51 | #define ICR_DEASSERT 0x00000000 52 | #define ICR_ASSERT 0x00004000 53 | 54 | // Trigger Mode 55 | #define ICR_EDGE 0x00000000 56 | #define ICR_LEVEL 0x00008000 57 | 58 | // Destination Shorthand 59 | #define ICR_NO_SHORTHAND 0x00000000 60 | #define ICR_SELF 0x00040000 61 | #define ICR_ALL_INCLUDING_SELF 0x00080000 62 | #define ICR_ALL_EXCLUDING_SELF 0x000c0000 63 | 64 | extern void* lapic_base; 65 | 66 | static void write(uint16_t reg, uint32_t value) { 67 | *(volatile uint32_t*)(lapic_base + reg) = value; 68 | } 69 | 70 | static uint32_t read(uint16_t reg) { 71 | return *(volatile uint32_t*)(lapic_base + reg); 72 | } 73 | 74 | 75 | static void lapic_timer_stop(void) { 76 | write(LAPIC_TICR, 0); 77 | write(LAPIC_TIMER, 1 << 16); 78 | } 79 | 80 | 81 | static void init_lapic_timer(void) { 82 | lapic_timer_stop(); 83 | register_irq(0, _irq0); 84 | 85 | // Setup PIT. 86 | pit_set_count(0xFFFF); 87 | 88 | // Set up the timer. 89 | write(LAPIC_TIMER, (1 << 16) | 0xFF); 90 | write(LAPIC_TDCR, 0); 91 | 92 | uint32_t init_tick = pit_get_count(); 93 | uint32_t samples = 0xFFFFF; 94 | write(LAPIC_TICR, samples); 95 | 96 | // Wait until TCCR is zero. 97 | ASMV("sti"); 98 | while (read(LAPIC_TCCR) != 0); 99 | 100 | uint32_t final_tick = pit_get_count(); 101 | uint32_t total_ticks = init_tick - final_tick; 102 | 103 | printk("[lapic]: Local APIC timer frequency: @%dGHz\n", (((samples/total_ticks)*PIT_DIVIDEND))/1000000000); 104 | } 105 | 106 | 107 | void lapic_send_ipi(uint8_t apic_id, uint8_t vector) { 108 | while (read(LAPIC_VER) & ICR_SEND_PENDING); 109 | uint32_t control = vector | ICR_ASSERT; 110 | write(LAPIC_ICRHI, (uint32_t)apic_id << 24); 111 | write(LAPIC_ICRLO, control); 112 | } 113 | 114 | 115 | void lapic_send_init(uint8_t apic_id) { 116 | while (read(LAPIC_VER) & ICR_SEND_PENDING); 117 | write(LAPIC_ICRHI, apic_id << 24); 118 | write(LAPIC_ICRLO, ICR_INIT 119 | | ICR_PHYSICAL 120 | | ICR_ASSERT 121 | | ICR_EDGE 122 | | ICR_NO_SHORTHAND); 123 | 124 | while (read(LAPIC_ICRLO) & ICR_SEND_PENDING); 125 | } 126 | 127 | 128 | void lapic_send_startup(uint8_t apic_id, uint8_t vector) { 129 | while (read(LAPIC_VER) & ICR_SEND_PENDING); 130 | write(LAPIC_ICRHI, apic_id << 24); 131 | write(LAPIC_ICRLO, ICR_STARTUP 132 | | ICR_PHYSICAL 133 | | ICR_ASSERT 134 | | ICR_EDGE 135 | | ICR_NO_SHORTHAND); 136 | 137 | while (read(LAPIC_ICRLO) & ICR_SEND_PENDING); 138 | } 139 | 140 | uint32_t lapic_read_id(void) { 141 | return read(LAPIC_ID) >> 24; 142 | } 143 | 144 | void lapic_send_eoi(void) { 145 | write(LAPIC_EOI, 0); 146 | } 147 | 148 | void lapic_init(void) { 149 | // Use flat model. 150 | write(LAPIC_DFR, 0xFFFFFFFF); 151 | 152 | // All cores will use logical ID of 1. 153 | write(LAPIC_LDR, 0x01000000); 154 | 155 | /* 156 | * Enable the local APIC for the current core. 157 | * 158 | */ 159 | 160 | write(LAPIC_SVR, (1 << 8) | 0xFF); 161 | init_lapic_timer(); 162 | } 163 | -------------------------------------------------------------------------------- /sys/src/arch/x86/cpu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void halt(void) { 5 | ASMV("hlt"); 6 | } 7 | 8 | 9 | void disable_processor(void) { 10 | ASMV("cli"); 11 | halt(); 12 | } 13 | -------------------------------------------------------------------------------- /sys/src/arch/x86/io.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | uint8_t inb(uint16_t port) { 4 | uint8_t res; 5 | __asm__ __volatile__("in %%dx, %%al" : "=a" (res) : "d" (port)); 6 | return res; 7 | } 8 | 9 | void outb(uint16_t port, uint8_t data) { 10 | __asm__ __volatile__("out %%al, %%dx" :: "a" (data), "d" (port)); 11 | } 12 | 13 | void outw(uint16_t port, uint16_t data) { 14 | __asm__ __volatile__("outw %w0, %w1" :: "a" (data), "Nd" (port)); 15 | } 16 | 17 | uint16_t inw(uint16_t port) { 18 | uint16_t data; 19 | __asm__ __volatile__("inw %w1, %w0" : "=a" (data) : "Nd" (port)); 20 | return data; 21 | } 22 | 23 | void outl(uint16_t port, uint32_t data) { 24 | __asm__ __volatile__("outl %0, %w1" :: "a" (data), "Nd" (port)); 25 | } 26 | 27 | uint32_t inl(uint16_t port) { 28 | uint32_t data; 29 | __asm__ __volatile__("inl %w1, %0" : "=a" (data) : "Nd" (port)); 30 | return data; 31 | } 32 | 33 | void io_wait() { 34 | __asm__ __volatile__("out %%al, %%dx" :: "a" (0x0), "d" (0x80)); 35 | } 36 | -------------------------------------------------------------------------------- /sys/src/arch/x86_64/exceptions.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #if defined(__x86_64__) 7 | 8 | #define INTR_END \ 9 | ASMV("cli; hlt\n"); 10 | 11 | typedef struct { 12 | uint64_t error_code; 13 | uint64_t rip; 14 | uint64_t cs; 15 | uint64_t rflags; 16 | uint64_t rsp; 17 | uint64_t ss; 18 | } stackframe_t; 19 | 20 | 21 | static void dump_state(void* stackframe) { 22 | stackframe_t* frame = stackframe; 23 | printk(PRINTK_PANIC "-- Begin dump of exception stackframe --\n"); 24 | printk(PRINTK_PANIC "ERROR_CODE=%x RIP=%x\n", frame->error_code, frame->rip); 25 | printk(PRINTK_PANIC "RFLAGS=%x RSP=%x\n", frame->rflags, frame->rsp); 26 | printk(PRINTK_PANIC "SS=%x\n", frame->ss); 27 | } 28 | 29 | E_ISR(0x0) { 30 | ASMV("cli"); 31 | printk(PRINTK_PANIC "Division by zero\n"); 32 | dump_state(stackframe); 33 | INTR_END; 34 | } 35 | 36 | E_ISR(0x1) { 37 | ASMV("cli"); 38 | printk(PRINTK_PANIC "Debug exception\n"); 39 | dump_state(stackframe); 40 | INTR_END; 41 | } 42 | 43 | E_ISR(0x2) { 44 | ASMV("cli"); 45 | printk(PRINTK_PANIC "Non-Maskable Interrupt\n"); 46 | dump_state(stackframe); 47 | INTR_END; 48 | } 49 | 50 | E_ISR(0x3) { 51 | ASMV("cli"); 52 | printk(PRINTK_PANIC "Breakpoint exception\n"); 53 | dump_state(stackframe); 54 | INTR_END; 55 | } 56 | 57 | E_ISR(0x4) { 58 | ASMV("cli"); 59 | printk(PRINTK_PANIC "Overflow exception\n"); 60 | dump_state(stackframe); 61 | INTR_END; 62 | } 63 | 64 | E_ISR(0x5) { 65 | ASMV("cli"); 66 | printk(PRINTK_PANIC "BOUND range exceeded\n"); 67 | dump_state(stackframe); 68 | INTR_END; 69 | } 70 | 71 | E_ISR(0x6) { 72 | ASMV("cli"); 73 | printk(PRINTK_PANIC "Invalid opcode\n"); 74 | dump_state(stackframe); 75 | INTR_END; 76 | } 77 | 78 | E_ISR(0x7) { 79 | ASMV("cli"); 80 | printk(PRINTK_PANIC "Coprocessor not available\n"); 81 | dump_state(stackframe); 82 | INTR_END; 83 | } 84 | 85 | E_ISR(0x8) { 86 | ASMV("cli"); 87 | printk(PRINTK_PANIC "Double fault\n"); 88 | dump_state(stackframe); 89 | INTR_END; 90 | } 91 | 92 | E_ISR(0x9) { 93 | ASMV("cli"); 94 | printk(PRINTK_PANIC "Coprocessor segment overrun\n"); 95 | dump_state(stackframe); 96 | INTR_END; 97 | } 98 | 99 | E_ISR(0xA) { 100 | ASMV("cli"); 101 | printk(PRINTK_PANIC "Invalid TSS\n"); 102 | dump_state(stackframe); 103 | INTR_END; 104 | } 105 | 106 | E_ISR(0xB) { 107 | ASMV("cli"); 108 | printk(PRINTK_PANIC "Segment not present\n"); 109 | dump_state(stackframe); 110 | INTR_END; 111 | } 112 | 113 | E_ISR(0xC) { 114 | ASMV("cli"); 115 | printk(PRINTK_PANIC "Stack segment fault\n"); 116 | dump_state(stackframe); 117 | INTR_END; 118 | } 119 | 120 | E_ISR(0xD) { 121 | ASMV("cli"); 122 | printk(PRINTK_PANIC "General protection fault\n"); 123 | dump_state(stackframe); 124 | INTR_END; 125 | } 126 | 127 | E_ISR(0xE) { 128 | ASMV("cli"); 129 | printk(PRINTK_PANIC "Page fault\n"); 130 | dump_state(stackframe); 131 | INTR_END; 132 | } 133 | 134 | E_ISR(0xF) { 135 | printk(PRINTK_PANIC "Reserved exception\n"); 136 | dump_state(stackframe); 137 | INTR_END; 138 | } 139 | 140 | E_ISR(0x10) { 141 | printk(PRINTK_PANIC "Coprocessor error\n"); 142 | dump_state(stackframe); 143 | INTR_END; 144 | } 145 | 146 | void init_exceptions(void) { 147 | register_exception_handler(0x0, REF_E_ISR(0x0)); 148 | register_exception_handler(0x1, REF_E_ISR(0x1)); 149 | register_exception_handler(0x2, REF_E_ISR(0x2)); 150 | register_exception_handler(0x3, REF_E_ISR(0x3)); 151 | register_exception_handler(0x4, REF_E_ISR(0x4)); 152 | register_exception_handler(0x5, REF_E_ISR(0x5)); 153 | register_exception_handler(0x6, REF_E_ISR(0x6)); 154 | register_exception_handler(0x7, REF_E_ISR(0x7)); 155 | register_exception_handler(0x8, REF_E_ISR(0x8)); 156 | register_exception_handler(0x9, REF_E_ISR(0x9)); 157 | register_exception_handler(0xA, REF_E_ISR(0xA)); 158 | register_exception_handler(0xB, REF_E_ISR(0xB)); 159 | register_exception_handler(0xC, REF_E_ISR(0xC)); 160 | register_exception_handler(0xD, REF_E_ISR(0xD)); 161 | register_exception_handler(0xE, REF_E_ISR(0xE)); 162 | register_exception_handler(0xF, REF_E_ISR(0xF)); 163 | register_exception_handler(0x10, REF_E_ISR(0x10)); 164 | } 165 | 166 | #endif // defined(__x86_64__) 167 | -------------------------------------------------------------------------------- /sys/src/arch/x86_64/idt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: Interrupt descriptor table module. 3 | * Author(s): Ian Marco Moffett. 4 | * 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #if defined(__x86_64__) 12 | 13 | #define TRAP_GATE_FLAGS 0x8F 14 | #define INT_GATE_FLAGS 0x8E 15 | #define IDT_INT_GATE_USER 0xEE 16 | 17 | struct interrupt_gate_descriptor idt[256]; 18 | struct idtr idtr = { 19 | .limit = sizeof(struct interrupt_gate_descriptor) * 256 - 1, 20 | .base = (uint64_t)&idt 21 | }; 22 | 23 | static void set_desc(uint8_t vector, void* isr, uint8_t flags) { 24 | uint64_t addr = (uint64_t)isr; 25 | struct interrupt_gate_descriptor* desc = &idt[vector]; 26 | 27 | desc->offlow16 = addr & 0xFFFF; 28 | desc->offmid16 = (addr >> 16) & 0xFFFF; 29 | desc->offhigh32 = (addr >> 32); 30 | desc->cs = 0x28; 31 | desc->ist = 0; 32 | desc->zero = 0; 33 | desc->zero1 = 0; 34 | desc->reserved = 0; 35 | desc->attr = flags; 36 | desc->dpl = 3; 37 | desc->p = 1; 38 | } 39 | 40 | void register_exception_handler(uint8_t vector, void* isr) { 41 | set_desc(vector, isr, TRAP_GATE_FLAGS); 42 | } 43 | 44 | 45 | void register_irq(uint8_t irq, void* isr) { 46 | set_desc(0x20 + irq, isr, INT_GATE_FLAGS); 47 | ioapic_set_entry(acpi_remap_irq(irq), 0x20 + irq); 48 | } 49 | 50 | 51 | void load_idt(void) { 52 | ASMV("lidt %0" :: "m" (idtr)); 53 | } 54 | 55 | #endif // defined(__x86_64__) 56 | -------------------------------------------------------------------------------- /sys/src/drivers/serial.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define COM1 0x3F8 9 | 10 | static uint8_t faulty = 0; 11 | 12 | static uint8_t is_transmit_empty(void) { 13 | return inb(COM1 + 5) & 0x20; 14 | } 15 | 16 | 17 | static void put_char(char c) { 18 | while (is_transmit_empty() == 0); 19 | outb(COM1, c); 20 | } 21 | 22 | 23 | static void serial_dev_write(void* _unused fsnode, char* buf, size_t n_bytes) { 24 | for (size_t i = 0; i < n_bytes; ++i) { 25 | put_char(buf[i]); 26 | } 27 | } 28 | 29 | static file_ops_t serial_fops = { 30 | .open = NULL, 31 | .write = serial_dev_write, 32 | .read = NULL, 33 | }; 34 | 35 | void serial_init(void) { 36 | outb(COM1 + 1, 0x00); // Disable interrupts 37 | outb(COM1 + 3, 0x80); // Enable DLAB (set baud rate divisor) 38 | outb(COM1 + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud 39 | outb(COM1 + 1, 0x00); // (hi byte) 40 | outb(COM1 + 3, 0x03); // 8 bits, no parity, one stop bit 41 | outb(COM1 + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold 42 | outb(COM1 + 4, 0x0B); // IRQs enabled, RTS/DSR set 43 | outb(COM1 + 4, 0x1E); // Set in loopback mode, test the serial chip 44 | outb(COM1 + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) 45 | 46 | // Ensure serial is not faulty. 47 | if (inb(COM1 + 0) != 0xAE) { 48 | faulty = 1; 49 | return; 50 | } 51 | 52 | // Set normal operation mode. 53 | outb(COM1 + 4, 0x0F); 54 | register_chrdev("serial", &serial_fops); 55 | 56 | } 57 | 58 | void serial_write(const char* str) { 59 | if (faulty) 60 | return; 61 | 62 | for (const char* s = str; *s; ++s) { 63 | put_char(*s); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /sys/src/drivers/timer/pit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | void pit_set_count(uint16_t count) { 6 | outb(0x43, 0x34); 7 | outb(0x40, count & 0xFF); 8 | outb(0x40, (count >> 8) & 0xFF); 9 | } 10 | 11 | 12 | uint16_t pit_get_count(void) { 13 | outb(0x43, 0x00); 14 | uint8_t lo = inb(0x40); 15 | uint8_t hi = inb(0x40) >> 8; 16 | return ((uint16_t)hi << 8) | lo; 17 | } 18 | -------------------------------------------------------------------------------- /sys/src/drivers/video/framebuffer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | static volatile struct limine_framebuffer_request framebuffer_req = { 6 | .id = LIMINE_FRAMEBUFFER_REQUEST, 7 | .revision = 0 8 | }; 9 | 10 | 11 | void framebuffer_init(void) {} 12 | -------------------------------------------------------------------------------- /sys/src/fs/devfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static vfs_fs_t devfs; 9 | static vfs_node_t* devfs_loc = NULL; 10 | 11 | typedef struct { 12 | vfs_node_t* node; 13 | file_ops_t* fops; 14 | uint8_t lock; 15 | } devfs_fileheader_t; 16 | 17 | static HASHMAP_TYPE(devfs_fileheader_t*) devfs_lookup_book = HASHMAP_INIT(355); 18 | static size_t lookup_book_entries = 0; 19 | 20 | 21 | /* 22 | * This will not do anything since register_chrdev() needs to be 23 | * called instead 24 | * 25 | */ 26 | static int devfs_stub_create(const char* _unused name) { return 1; } 27 | 28 | static void* devfs_open(const char* name) { 29 | devfs_fileheader_t* dev; 30 | 31 | if (lookup_book_entries > 0) { 32 | if (HASHMAP_SGET(&devfs_lookup_book, dev, name) == 0) return NULL; 33 | } else { 34 | return NULL; 35 | } 36 | 37 | // TODO: Add lock only per process. 38 | if (dev->lock) return NULL; 39 | dev->lock = 1; 40 | 41 | if (dev->fops->open) dev->fops->open(name); 42 | return dev; 43 | } 44 | 45 | static void devfs_read(void* fs_node, char* out_buf, size_t n_bytes) { 46 | devfs_fileheader_t* dev = (devfs_fileheader_t*)fs_node; 47 | if (!(dev->lock)) return; 48 | 49 | if (dev->fops->read) dev->fops->read(fs_node, out_buf, n_bytes); 50 | } 51 | 52 | 53 | static void devfs_write(void* fs_node, char* in_buf, size_t n_bytes) { 54 | devfs_fileheader_t* dev = (devfs_fileheader_t*)fs_node; 55 | if (!(dev->lock)) return; 56 | if (dev->fops->write) dev->fops->write(fs_node, in_buf, n_bytes); 57 | } 58 | 59 | 60 | static void devfs_close(void* fs_node) { 61 | devfs_fileheader_t* dev = (devfs_fileheader_t*)fs_node; 62 | if (dev->fops->close) dev->fops->close(fs_node); 63 | dev->lock = 0; 64 | } 65 | 66 | static file_ops_t default_file_ops = { 67 | .open = devfs_open, 68 | .read = devfs_read, 69 | .write = devfs_write, 70 | .close = NULL 71 | }; 72 | 73 | int register_chrdev(const char* name, file_ops_t* fops) { 74 | _unused devfs_fileheader_t* unused; 75 | 76 | if (lookup_book_entries > 0) { 77 | if (HASHMAP_SGET(&devfs_lookup_book, unused, name) != 0) return 1; 78 | } 79 | 80 | devfs_fileheader_t* dev = kmalloc(sizeof(devfs_fileheader_t)); 81 | dev->fops = fops; 82 | dev->node = vfs_make_node(&devfs, devfs_loc, name, 0, fops); 83 | HASHMAP_SINSERT(&devfs_lookup_book, name, dev); 84 | ++lookup_book_entries; 85 | return 0; 86 | } 87 | 88 | void devfs_init(void) { 89 | devfs.fops = kmalloc(sizeof(file_ops_t)); 90 | kmemzero(devfs.fops, sizeof(file_ops_t)); 91 | 92 | devfs.fops->create = devfs_stub_create; 93 | devfs.fops->open = devfs_open; 94 | devfs.fops->close = devfs_close; 95 | devfs.default_fops = &default_file_ops; 96 | 97 | devfs_loc = vfs_make_node(&devfs, vfs_get_root(), "dev", 1, devfs.fops); 98 | } 99 | -------------------------------------------------------------------------------- /sys/src/fs/tmpfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define TMPFS_BLOCKSIZE 256 // Measured in bytes. 10 | #define TMPFS_SIZE_BLOCKS 90 11 | 12 | typedef struct { 13 | uint8_t lock : 1; 14 | uint8_t* buf; 15 | size_t size; 16 | vfs_node_t* node; 17 | } tmpfs_fileheader_t; 18 | 19 | static HASHMAP_TYPE(tmpfs_fileheader_t*) tmpfs_lookup_book = HASHMAP_INIT(256); 20 | static size_t lookup_book_entries = 0; 21 | static vfs_node_t* tmpfs_loc = NULL; 22 | static vfs_fs_t tmpfs; 23 | 24 | 25 | static void* tmpfs_open_file(const char* name); 26 | static void tmpfs_read(void* fs_node, char* buf, size_t n_bytes); 27 | static void tmpfs_write(void* fs_node, char* buf, size_t n_bytes); 28 | static void tmpfs_close_file(void* fs_node); 29 | 30 | static file_ops_t default_file_ops = { 31 | .open = tmpfs_open_file, 32 | .read = tmpfs_read, 33 | .write = tmpfs_write, 34 | .close = tmpfs_close_file 35 | }; 36 | 37 | static int tmpfs_create_file(const char* name) { 38 | _unused tmpfs_fileheader_t* unused; 39 | 40 | if (lookup_book_entries > 0) { 41 | if (HASHMAP_SGET(&tmpfs_lookup_book, unused, name) != 0) return 1; 42 | } 43 | 44 | tmpfs_fileheader_t* file = kmalloc(sizeof(tmpfs_fileheader_t)); 45 | file->buf = kmalloc(2); 46 | file->node = vfs_make_node(&tmpfs, tmpfs_loc, name, 0, &default_file_ops); 47 | 48 | HASHMAP_SINSERT(&tmpfs_lookup_book, name, file); 49 | ++lookup_book_entries; 50 | return 0; 51 | } 52 | 53 | static void* tmpfs_open_file(const char* name) { 54 | tmpfs_fileheader_t* file; 55 | 56 | if (lookup_book_entries > 0) { 57 | if (HASHMAP_SGET(&tmpfs_lookup_book, file, name) == 0) return NULL; 58 | } else { 59 | return NULL; 60 | } 61 | 62 | /* Don't open the file if already opened */ 63 | /* TODO: Add lock only per process */ 64 | if (file->lock) return NULL; 65 | 66 | file->lock = 1; 67 | return file; 68 | } 69 | 70 | static void tmpfs_close_file(void* fs_node) { 71 | tmpfs_fileheader_t* file = (tmpfs_fileheader_t*)fs_node; 72 | file->lock = 0; 73 | } 74 | 75 | static void tmpfs_read(void* fs_node, char* buf, size_t n_bytes) { 76 | tmpfs_fileheader_t* file = (tmpfs_fileheader_t*)fs_node; 77 | 78 | /* Don't read if file lock not acquired */ 79 | if (!(file->lock)) return; 80 | 81 | for (size_t i = 0; i < n_bytes; ++i) { 82 | buf[i] = file->buf[i]; 83 | } 84 | } 85 | 86 | 87 | static void tmpfs_write(void* fs_node, char* buf, size_t n_bytes) { 88 | tmpfs_fileheader_t* file = (tmpfs_fileheader_t*)fs_node; 89 | 90 | /* Don't write if file lock not acquired */ 91 | if (!(file->lock)) return; 92 | 93 | for (size_t i = 0; i < n_bytes; ++i) { 94 | if (i >= file->size-1) { 95 | file->size += 2; 96 | file->buf = krealloc(file->buf, file->size); 97 | } 98 | 99 | file->buf[i] = buf[i]; 100 | } 101 | } 102 | 103 | void tmpfs_init(void) { 104 | tmpfs.fops = kmalloc(sizeof(file_ops_t)); 105 | 106 | kmemzero(tmpfs.fops, sizeof(file_ops_t)); /* Make sure every field is NULL */ 107 | tmpfs.fops->create = tmpfs_create_file; 108 | tmpfs.fops->open = tmpfs_open_file; 109 | tmpfs.default_fops = &default_file_ops; 110 | 111 | tmpfs_loc = vfs_make_node(&tmpfs, vfs_get_root(), "tmp", 1, tmpfs.fops); 112 | } 113 | -------------------------------------------------------------------------------- /sys/src/fs/vfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | _unused static spinlock_t lock = 0; 9 | static vfs_node_t* vfs_root = NULL; 10 | static HASHMAP_TYPE(vfs_fs_t*) filesystems; 11 | 12 | 13 | _unused static uint8_t is_path_valid(const char* path) { 14 | for (const char* ptr = path; *ptr; ++ptr) { 15 | switch (*ptr) { 16 | case '0': 17 | case '1': 18 | case '2': 19 | case '3': 20 | case '4': 21 | case '5': 22 | case '6': 23 | case '7': 24 | case '8': 25 | case '9': 26 | case '/': 27 | case '-': 28 | case '_': 29 | break; 30 | default: 31 | if (*ptr >= 'A' && *ptr <= 'Z') break; 32 | if (*ptr >= 'a' && *ptr <= 'z') break; 33 | return 0; 34 | } 35 | } 36 | 37 | return 1; 38 | } 39 | 40 | 41 | static inline vfs_node_t* get_node(vfs_node_t* parent, const char* name) { 42 | vfs_node_t* node; 43 | 44 | if (parent->n_children == 0) { 45 | return NULL; 46 | } 47 | 48 | if (!(HASHMAP_GET(&parent->children, node, name, kstrlen(name)))) return NULL; 49 | return node; 50 | } 51 | 52 | 53 | // A fs mountpoint could be '/tmp' for example. 54 | // '/' does not count!! 55 | static vfs_node_t* get_fs_mountpoint(const char* path) { 56 | if (*path == '/') ++path; 57 | 58 | size_t bufidx = 0; 59 | char* buf = kmalloc(kstrlen(path) + 1); 60 | vfs_node_t* ret = NULL; 61 | 62 | const char* ptr = path; 63 | 64 | while (1) { 65 | if (*ptr == '/' || *ptr == '\0') { 66 | buf[bufidx++] = '\0'; 67 | ret = get_node(vfs_root, buf); 68 | kfree(buf); 69 | return ret; 70 | } 71 | 72 | buf[bufidx++] = *ptr; 73 | ++ptr; 74 | } 75 | } 76 | 77 | /* 78 | * In /tmp/blah.txt this will yield blah.txt 79 | * 80 | */ 81 | static const char* get_fs_last_pathname(const char* path) { 82 | if (*path == '/') ++path; 83 | 84 | size_t path_size = kstrlen(path); 85 | size_t bufidx = 0; 86 | char* buf = kmalloc(path_size + 1); 87 | 88 | const char* ptr = path + path_size; 89 | size_t i = path_size; 90 | while (*ptr != '/') { 91 | if (i <= 0) { 92 | kfree(buf); 93 | return NULL; 94 | } 95 | --ptr; 96 | --i; 97 | } 98 | 99 | while (1) { 100 | if (*ptr != '/') buf[bufidx++] = *ptr; 101 | if (*ptr == '\0') break; 102 | ++ptr; 103 | } 104 | 105 | return buf; 106 | } 107 | 108 | vfs_node_t* vfs_get_root(void) { 109 | return vfs_root; 110 | } 111 | 112 | static vfs_node_t* vfs_path_to_node(const char* path) { 113 | if (*path == '/') ++path; 114 | 115 | vfs_node_t* last_parent = vfs_root; 116 | size_t bufidx = 0; 117 | char* buf = kmalloc(kstrlen(path) + 1); 118 | buf[kstrlen(path)] = 0; 119 | 120 | const char* ptr = path; 121 | 122 | while (1) { 123 | if (*ptr == '\0' || (*ptr == '/' && *(ptr + 1) != '\0')) { 124 | buf[bufidx++] = 0; 125 | last_parent = get_node(last_parent, buf); 126 | if (last_parent == NULL) { 127 | kfree(buf); 128 | return NULL; 129 | } 130 | 131 | if (*ptr == '\0') { 132 | kfree(buf); 133 | break; 134 | } 135 | 136 | bufidx = 0; 137 | ++ptr; 138 | } 139 | 140 | buf[bufidx++] = *ptr; 141 | ++ptr; 142 | } 143 | 144 | 145 | return last_parent != vfs_root ? last_parent : NULL; 146 | } 147 | 148 | #define FOPEN_MODE_READ (1 << 0) 149 | #define FOPEN_MODE_WRITE (1 << 1) 150 | 151 | FILE* fopen(const char* path, const char* mode) { 152 | if (vfs_root == NULL) { 153 | /* Do not run if the filesystem is not initialized */ 154 | return NULL; 155 | } 156 | 157 | FILE* fp = kmalloc(sizeof(FILE)); 158 | uint8_t mode_flags = 0; 159 | 160 | /* Set mode flags */ 161 | if (kstrcmp(mode, "w") == 0) { 162 | mode_flags |= FOPEN_MODE_WRITE; 163 | } else { 164 | mode_flags |= FOPEN_MODE_READ; 165 | } 166 | 167 | vfs_node_t* mountpoint = get_fs_mountpoint(path); 168 | if (mountpoint == NULL) return NULL; 169 | 170 | vfs_node_t* node = vfs_path_to_node(path); 171 | const char* path_end = get_fs_last_pathname(path); 172 | if (node == NULL) { 173 | /* If we are reading and the file is not found, return NULL */ 174 | if (!(mode_flags & FOPEN_MODE_WRITE)) { 175 | kfree(fp); 176 | return NULL; 177 | } 178 | 179 | /* If we are writing and the path is not found, create the file */ 180 | if ((mountpoint->filesystem->fops->create(path_end)) == 1) { 181 | /* File already exists */ 182 | kfree(fp); 183 | return NULL; 184 | } 185 | 186 | /* Now create the node */ 187 | node = vfs_make_node(mountpoint->filesystem, mountpoint, path_end, 0, mountpoint->filesystem->default_fops); 188 | 189 | /* Now return the file node */ 190 | fp->fs_node = mountpoint->filesystem->fops->open(path_end); 191 | fp->vfs_node = node; 192 | return fp; 193 | } 194 | 195 | fp->fs_node = mountpoint->filesystem->fops->open(path_end); 196 | fp->vfs_node = node; 197 | return fp; 198 | } 199 | 200 | 201 | void fread(FILE* stream, char* out_ptr, size_t n_bytes) { 202 | /* Call the filesystems read() function */ 203 | stream->vfs_node->fops->read(stream->fs_node, out_ptr, n_bytes); 204 | } 205 | 206 | 207 | void fwrite(FILE* stream, char* in_ptr, size_t n_bytes) { 208 | /* Call the filesystems write() function */ 209 | stream->vfs_node->fops->write(stream->fs_node, in_ptr, n_bytes); 210 | } 211 | 212 | 213 | void fclose(FILE* stream) { 214 | stream->vfs_node->filesystem->fops->close(stream->fs_node); 215 | } 216 | 217 | 218 | vfs_node_t* vfs_make_node(vfs_fs_t* fs, vfs_node_t* parent, const char* name, uint8_t is_dir, file_ops_t* fops) { 219 | vfs_node_t* node = kmalloc(sizeof(vfs_node_t)); 220 | node->name = kmalloc(kstrlen(name) + 1); 221 | kmemcpy(node->name, name, kstrlen(name)); 222 | 223 | node->parent = parent; 224 | node->filesystem = fs; 225 | node->fops = fops; 226 | 227 | if (is_dir) { 228 | node->children = (typeof(node->children))HASHMAP_INIT(256); 229 | node->n_children = 0; 230 | } 231 | 232 | if (parent != NULL) { 233 | HASHMAP_SINSERT(&parent->children, name, node); 234 | ++parent->n_children; 235 | } 236 | 237 | return node; 238 | } 239 | 240 | void vfs_init(void) { 241 | vfs_root = vfs_make_node(NULL, NULL, "", 1, NULL); 242 | filesystems = (typeof(filesystems))HASHMAP_INIT(256); 243 | printk("[vfs]: Finished setting up.\n"); 244 | } 245 | -------------------------------------------------------------------------------- /sys/src/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | static void init_mm(void) { 14 | pmm_init(); 15 | } 16 | 17 | static void init_fs(void) { 18 | vfs_init(); 19 | tmpfs_init(); 20 | devfs_init(); 21 | } 22 | 23 | 24 | static void init_drivers(void) { 25 | serial_init(); 26 | } 27 | 28 | 29 | void _start(void) { 30 | printk("Beginning boot process..\n"); 31 | init_interrupts(); 32 | init_mm(); 33 | 34 | init_fs(); 35 | init_drivers(); 36 | 37 | acpi_init(); 38 | ioapic_init(); 39 | lapic_init(); 40 | 41 | char buf[] = "Hello, World!"; 42 | FILE* fp = fopen("/dev/serial", "w"); 43 | fwrite(fp, buf, sizeof(buf)); 44 | fclose(fp); 45 | 46 | while (1); 47 | } 48 | -------------------------------------------------------------------------------- /sys/src/intr/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #if defined(__x86_64__) 4 | #include 5 | #include 6 | #endif 7 | 8 | #if defined(__x86_64__) 9 | void init_interrupts(void) { 10 | load_idt(); 11 | init_exceptions(); 12 | printk("Finished setting up interrupts.\n"); 13 | 14 | } 15 | #endif 16 | -------------------------------------------------------------------------------- /sys/src/intr/irq.asm: -------------------------------------------------------------------------------- 1 | bits 64 2 | 3 | global _irq0 4 | extern trap_entry 5 | extern lapic_send_eoi 6 | 7 | %macro pre_eoi 0 8 | push rax 9 | push rbx 10 | push rcx 11 | push rdx 12 | push rsi 13 | push rdi 14 | %endmacro 15 | 16 | %macro post_eoi 0 17 | pop rdi 18 | pop rsi 19 | pop rdx 20 | pop rcx 21 | pop rbx 22 | pop rax 23 | %endmacro 24 | 25 | _irq0: 26 | cli 27 | pre_eoi 28 | call lapic_send_eoi 29 | post_eoi 30 | push 0x20 31 | push rbp 32 | jmp trap_entry 33 | -------------------------------------------------------------------------------- /sys/src/intr/trap.asm: -------------------------------------------------------------------------------- 1 | bits 64 2 | 3 | global trap_entry 4 | global trap_new_task_entry 5 | global trap_exit 6 | 7 | extern trap 8 | 9 | trap_entry: 10 | push r15 11 | push r14 12 | push r13 13 | push r12 14 | push r11 15 | push r10 16 | push r9 17 | push r8 18 | push rax 19 | push rcx 20 | push rdx 21 | push rbx 22 | push rsi 23 | push rdi 24 | 25 | mov rdi, rsp 26 | call trap 27 | 28 | trap_exit: 29 | pop rdi 30 | pop rsi 31 | pop rbx 32 | pop rdx 33 | pop rcx 34 | pop rax 35 | pop r8 36 | pop r9 37 | pop r10 38 | pop r11 39 | pop r12 40 | pop r13 41 | pop r14 42 | pop r15 43 | pop rbp 44 | add rsp, 8 45 | iretq 46 | -------------------------------------------------------------------------------- /sys/src/intr/trap.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void trap(trapframe_t* tf) { 4 | switch (tf->trapno) { 5 | default: 6 | break; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /sys/src/lib/hashmap.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | HASHMAP_TYPE(int) a; 4 | 5 | 6 | uint32_t hashmap_hash(const void* data, size_t length) { 7 | const uint8_t* data_u8 = data; 8 | uint32_t result = 0; 9 | 10 | for (size_t i = 0; i < length; ++i) { 11 | uint32_t c = data_u8[i]; 12 | result = c + (result << 6) + (result << 16) - result; 13 | } 14 | 15 | return result; 16 | } 17 | -------------------------------------------------------------------------------- /sys/src/lib/log.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | static volatile struct limine_terminal_request term_req = { 7 | .id = LIMINE_TERMINAL_REQUEST, 8 | .revision = 0 9 | }; 10 | 11 | 12 | static inline void putstr(const char* str) { 13 | term_req.response->write(term_req.response->terminals[0], str, kstrlen(str)); 14 | } 15 | 16 | 17 | 18 | void printk(const char* fmt, ...) { 19 | va_list ap; 20 | va_start(ap, fmt); 21 | 22 | for (const char* ptr = fmt; *ptr; ++ptr) { 23 | if (*ptr == '%') { 24 | ++ptr; 25 | 26 | switch (*ptr) { 27 | case 'd': 28 | putstr(dec2str(va_arg(ap, uint64_t))); 29 | break; 30 | case 'x': 31 | putstr(hex2str(va_arg(ap, uint64_t))); 32 | break; 33 | case 'X': 34 | putstr(hex2str(va_arg(ap, uint64_t)) + 2); 35 | break; 36 | case 's': 37 | putstr(va_arg(ap, char*)); 38 | break; 39 | case 'c': 40 | putstr((char[2]){va_arg(ap, int), 0}); 41 | break; 42 | } 43 | } else { 44 | putstr((char[2]){*ptr, 0}); 45 | } 46 | } 47 | 48 | va_end(ap); 49 | } 50 | 51 | -------------------------------------------------------------------------------- /sys/src/lib/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | size_t kstrlen(const char* str) { 4 | const char* s2 = str; 5 | while(*s2) s2++; 6 | 7 | return (s2 - str); 8 | } 9 | 10 | 11 | bool kmemcmp(const char* str1, const char* str2, size_t n) { 12 | while (*str1 && *str2) { 13 | if (*str1 != *str2) { 14 | return 1; 15 | } 16 | 17 | ++str1; 18 | ++str2; 19 | } 20 | 21 | return 0; 22 | } 23 | 24 | char* dec2str(size_t number) { 25 | static uint8_t dec_string[80]; 26 | uint8_t i = 0, j, temp; 27 | uint8_t negative = 0; // Is number negative? 28 | 29 | if (number == 0) dec_string[i++] = '0'; // If passed in 0, print a 0 30 | else if (number < 0) { 31 | negative = 1; // Number is negative 32 | number = -number; // Easier to work with positive values 33 | } 34 | 35 | while (number > 0) { 36 | dec_string[i] = (number % 10) + '0'; 37 | number /= 10; 38 | i++; 39 | } 40 | 41 | if (negative) dec_string[i++] = '-'; 42 | 43 | dec_string[i] = '\0'; 44 | 45 | i--; 46 | for (j = 0; j < i; j++, i--) { 47 | temp = dec_string[j]; 48 | dec_string[j] = dec_string[i]; 49 | dec_string[i] = temp; 50 | } 51 | 52 | return dec_string; 53 | } 54 | 55 | 56 | void kmemcpy(void* dst, const void* src, size_t len) { 57 | asm( 58 | "cld\n" 59 | "rep\n" 60 | "movsb\n" 61 | ::"c"(len), "S"(src), "D"(dst) 62 | ); 63 | } 64 | 65 | 66 | 67 | uint8_t* hex2str(uint64_t hex_num) { 68 | static uint8_t hex_string[80]; 69 | uint8_t *ascii_numbers = "0123456789ABCDEF"; 70 | uint8_t nibble; 71 | uint8_t i = 0, j, temp; 72 | uint8_t pad = 0; 73 | 74 | // If passed in 0, print a 0 75 | if (hex_num == 0) { 76 | kstrncpy(hex_string, "0\0", 2); 77 | i = 1; 78 | } 79 | 80 | if (hex_num < 0x10) pad = 1; // If one digit, will pad out to 2 later 81 | 82 | while (hex_num > 0) { 83 | // Convert hex values to ascii string 84 | nibble = (uint8_t)hex_num & 0x0F; // Get lowest 4 bits 85 | nibble = ascii_numbers[nibble]; // Hex to ascii 86 | hex_string[i] = nibble; // Move ascii char into string 87 | hex_num >>= 4; // Shift right by 4 for next nibble 88 | i++; 89 | } 90 | 91 | if (pad) hex_string[i++] = '0'; // Pad out string with extra 0 92 | 93 | // Add initial "0x" to front of hex string 94 | hex_string[i++] = 'x'; 95 | hex_string[i++] = '0'; 96 | hex_string[i] = '\0'; // Null terminate string 97 | 98 | // Number is stored backwards in hex_string, reverse the string by swapping ends 99 | // until they meet in the middle 100 | i--; // Skip null byte 101 | for (j = 0; j < i; j++, i--) { 102 | temp = hex_string[j]; 103 | hex_string[j] = hex_string[i]; 104 | hex_string[i] = temp; 105 | } 106 | 107 | // Print hex string 108 | return hex_string; 109 | } 110 | 111 | uint8_t* kstrncpy(uint8_t *dst, const uint8_t *src, const uint8_t len) { 112 | for (uint8_t i = 0; src[i] && i < len; i++) 113 | dst[i] = src[i]; 114 | 115 | return dst; 116 | } 117 | 118 | 119 | void kmemzero(void* ptr, size_t n) { 120 | asm( 121 | "cld\n" 122 | "rep\n" 123 | "stosb\n" 124 | ::"a"(0), "D"(ptr), "c"(n) 125 | ); 126 | } 127 | 128 | 129 | void kmemset(void* ptr, uint8_t data, size_t n) { 130 | asm( 131 | "cld\n" 132 | "rep\n" 133 | "stosb\n" 134 | ::"a"(data), "D"(ptr), "c"(n) 135 | ); 136 | } 137 | 138 | void kmemset16(void* ptr, uint16_t data, size_t n) { 139 | asm( 140 | "cld\n" 141 | "rep\n" 142 | "stosw\n" 143 | ::"a"(data), "D"(ptr), "c"(n) 144 | ); 145 | } 146 | 147 | void kmemset32(void* ptr, uint32_t data, size_t n) { 148 | asm( 149 | "cld\n" 150 | "rep\n" 151 | "stosl\n" 152 | ::"a"(data), "D"(ptr), "c"(n) 153 | ); 154 | } 155 | 156 | void kmemset64(void* ptr, uint64_t data, size_t n) { 157 | asm( 158 | "cld\n" 159 | "rep\n" 160 | "stosq\n" 161 | ::"a"(data), "D"(ptr), "c"(n) 162 | ); 163 | } 164 | 165 | 166 | uint8_t kstrcmp(const char* str1, const char* str2) { 167 | uint32_t str1_len, str2_len; 168 | str1_len = kstrlen(str1); 169 | str2_len = kstrlen(str2); 170 | 171 | if (str1_len != str2_len) { 172 | return 1; 173 | } 174 | 175 | for (uint32_t i = 0; i < str1_len; ++i) { 176 | if (str1[i] != str2[i]) { 177 | return 1; 178 | } 179 | } 180 | 181 | return 0; 182 | } 183 | 184 | 185 | uint8_t kstrncmp(const char* str1, const char* str2, size_t n) { 186 | for (uint32_t i = 0; i < n; ++i) { 187 | if (str1[i] != str2[i]) { 188 | return 1; 189 | } 190 | } 191 | 192 | return 0; 193 | } 194 | 195 | uint64_t hex2int(char* hex, size_t len) { 196 | uint64_t val = 0; 197 | 198 | while (*hex == ' ') { ++hex; } 199 | if (*hex == '0' && *(hex + 1) == 'x') 200 | hex += 2; 201 | 202 | for (int i = 0; i < len; ++i) { 203 | // get current character then increment 204 | uint8_t byte = *hex++; 205 | // transform hex character to the 4bit equivalent number, using the ascii table indexes 206 | if (byte >= '0' && byte <= '9') byte = byte - '0'; 207 | else if (byte >= 'a' && byte <='f') byte = byte - 'a' + 10; 208 | else if (byte >= 'A' && byte <='F') byte = byte - 'A' + 10; 209 | // shift 4 to make space for new digit, and add the 4 bits of the new digit 210 | val = (val << 4) | (byte & 0xF); 211 | } 212 | return val; 213 | } 214 | -------------------------------------------------------------------------------- /sys/src/mm/heap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: Kernel heap alloctor. 3 | * Author(s): Ian Marco Moffett 4 | * 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define MIN_PAGE_COUNT 16 16 | #define MAX_EXP 32 17 | #define MIN_EXP 8 18 | #define DATA_START(mem_block) (((char*) mem_block) + sizeof(block_tag_t)) 19 | 20 | #define DEBUG 0 21 | 22 | static size_t bytes_allocated = 0; /* How many bytes are allocated */ 23 | static uint8_t is_heap_init = 0; /* 1 if heap has been set up */ 24 | static uint8_t lock = 0; 25 | 26 | 27 | typedef struct _BlockTag { 28 | uint8_t is_free : 1; 29 | size_t size; 30 | struct _BlockTag* next; 31 | } block_tag_t; 32 | 33 | static block_tag_t* tail = NULL; 34 | static block_tag_t* head = NULL; 35 | 36 | 37 | static block_tag_t* best_fit(size_t size) { 38 | block_tag_t* best = NULL; 39 | 40 | for (block_tag_t* tag = tail; tag != NULL; tag = tag->next) { 41 | if (tag->is_free && best == NULL) { 42 | best = tag; 43 | } else if (tag->is_free && tag->size > size && tag->size < best->size) { 44 | best = tag; 45 | } 46 | } 47 | 48 | return best; 49 | } 50 | 51 | 52 | static void init(void) { 53 | head = (void*)vmm_alloc(HEAP_SIZE_PAGES); 54 | tail = head; 55 | kmemzero(tail, HEAP_SIZE_PAGES*PAGE_SIZE); 56 | } 57 | 58 | 59 | void* kmalloc(size_t size) { 60 | SPINLOCK_ACQUIRE(lock); 61 | 62 | if (!(is_heap_init)) { 63 | init(); 64 | is_heap_init = 1; 65 | } 66 | 67 | /* Check if there is enough memory */ 68 | if (bytes_allocated + size > HEAP_SIZE_PAGES*PAGE_SIZE) { 69 | SPINLOCK_RELEASE(lock); 70 | return NULL; 71 | } 72 | 73 | block_tag_t* region = best_fit(size); 74 | 75 | if (region == NULL) { 76 | char* next = DATA_START(head + head->size); 77 | ASSERT(head != NULL, "head is NULL"); 78 | 79 | head->next = (block_tag_t*)next; 80 | head = head->next; 81 | region = head; 82 | region->next = NULL; 83 | region->is_free = 0; 84 | region->size = size; 85 | tail = head; 86 | } 87 | 88 | bytes_allocated += size; 89 | 90 | if (DEBUG) { 91 | printk("[heap]: Allocated %d bytes, %d KiB used.\n", size, bytes_allocated/1024); 92 | } 93 | 94 | SPINLOCK_RELEASE(lock); 95 | return DATA_START(region); 96 | } 97 | 98 | 99 | void kfree(void* ptr) { 100 | block_tag_t* region = ptr - sizeof(block_tag_t); 101 | 102 | for (block_tag_t* block = region; (block != NULL) && (DATA_START(block) != ptr); block = block->next) { 103 | block->is_free = 1; 104 | } 105 | 106 | tail = region; 107 | bytes_allocated -= region->size; 108 | } 109 | 110 | 111 | void* krealloc(void* oldptr, size_t sz) { 112 | void* new = kmalloc(sz); 113 | kmemcpy(new, oldptr, sz); 114 | kfree(oldptr); 115 | return new; 116 | } 117 | -------------------------------------------------------------------------------- /sys/src/mm/pmm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: Physical memory manager. 3 | * Author(s): Ian Marco Moffett 4 | * 5 | */ 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define PMM_DEBUG 0 16 | 17 | 18 | static volatile struct limine_memmap_request mmap_req = { 19 | .id = LIMINE_MEMMAP_REQUEST, 20 | .revision = 0 21 | }; 22 | 23 | static struct limine_memmap_response* mmap_resp = NULL; 24 | static uint8_t* bitmap = NULL; 25 | 26 | #if defined(__x86_64__) 27 | 28 | static inline void bitmap_set_bit(size_t bit) { 29 | bitmap[bit / 8] |= (1 << (bit % 8)); 30 | } 31 | 32 | static inline void bitmap_unset_bit(size_t bit) { 33 | bitmap[bit / 8] &= ~(1 << (bit % 8)); 34 | } 35 | 36 | 37 | static inline uint8_t bitmap_test(size_t bit) { 38 | return bitmap[bit / 8] & (1 << (bit % 8)); 39 | } 40 | 41 | static struct limine_memmap_entry* find_highest_mem_chunk(void) { 42 | struct limine_memmap_entry* chunk = NULL; 43 | 44 | for (size_t i = 0; i < mmap_resp->entry_count; ++i) { 45 | struct limine_memmap_entry* entry = mmap_resp->entries[i]; 46 | if (entry->type != LIMINE_MEMMAP_USABLE) continue; 47 | 48 | if (PMM_DEBUG) printk("[pmm]: Found usable memory chunk @%x\n", entry->base); 49 | if (chunk == NULL) { 50 | chunk = entry; 51 | } else if (entry->base > chunk->base) { 52 | chunk = entry; 53 | } 54 | } 55 | 56 | if (PMM_DEBUG) printk("[pmm]: Found highest memory chunk @%x\n", chunk->base); 57 | return chunk; 58 | } 59 | 60 | static inline size_t get_bitmap_size(void) { 61 | struct limine_memmap_entry* highest_entry = find_highest_mem_chunk(); 62 | size_t highest_address = highest_entry->base + highest_entry->length; 63 | size_t bitmap_size = ALIGN_UP((highest_address/0x1000)/8, 0x1000); 64 | return bitmap_size; 65 | } 66 | 67 | static void init_bitmap(void) { 68 | /* Compute the bitmap size */ 69 | printk("[pmm]: Computing PMM bitmap size..\n"); 70 | size_t bitmap_size = get_bitmap_size(); 71 | printk("[pmm]: Bitmap size => %d bytes\n", bitmap_size); 72 | 73 | /* Find a memory chunk for our bitmap */ 74 | for (size_t i = 0; i < mmap_resp->entry_count; ++i) { 75 | struct limine_memmap_entry* entry = mmap_resp->entries[i]; 76 | if (entry->type == LIMINE_MEMMAP_USABLE && entry->length >= bitmap_size) { 77 | bitmap = (uint8_t*)(entry->base + VMM_HIGHER_HALF); 78 | kmemset(bitmap, 0xFF, bitmap_size); 79 | entry->length -= bitmap_size; 80 | entry->base += bitmap_size; 81 | break; 82 | } 83 | } 84 | 85 | printk("[pmm]: Bitmap location => %x\n", bitmap); 86 | 87 | /* Setup bitmap based on memory map */ 88 | for (size_t i = 0; i < mmap_resp->entry_count; ++i) { 89 | struct limine_memmap_entry* entry = mmap_resp->entries[i]; 90 | if (entry->type == LIMINE_MEMMAP_USABLE && entry->length >= bitmap_size) { 91 | for (size_t j = 0; j < entry->length; j += 0x1000) { 92 | bitmap_unset_bit((entry->base + j)/0x1000); 93 | } 94 | } 95 | } 96 | } 97 | 98 | 99 | void pmm_init(void) { 100 | mmap_resp = mmap_req.response; 101 | init_bitmap(); 102 | } 103 | 104 | 105 | static uintptr_t pmm_alloc_inner(void) { 106 | for (size_t bit = 0; bit < get_bitmap_size()*8; ++bit) { 107 | if (!(bitmap_test(bit))) { 108 | bitmap_set_bit(bit); 109 | return 0x1000*bit; 110 | } 111 | } 112 | 113 | return 0; 114 | } 115 | 116 | 117 | uintptr_t pmm_alloc(size_t frames) { 118 | uintptr_t mem = 0; 119 | for (size_t i = 0; i < frames; ++i) { 120 | if (mem == 0) mem = pmm_alloc_inner(); 121 | if (mem == 0) return 0; 122 | } 123 | 124 | return mem; 125 | } 126 | 127 | 128 | void pmm_free(uintptr_t ptr, size_t frames) { 129 | for (size_t i = 0; i < frames; ++i) { 130 | bitmap_unset_bit(ptr/0x1000); 131 | ptr += 0x1000; 132 | } 133 | } 134 | 135 | #endif //defined(__x86_64__) 136 | -------------------------------------------------------------------------------- /sys/src/mm/vmm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | volatile struct limine_hhdm_request hhdm_request = { 8 | .id = LIMINE_HHDM_REQUEST, 9 | .revision = 0 10 | }; 11 | 12 | 13 | static inline void __tlb_flush_single(vaddr_t ptr) { 14 | ASMV("invlpg (%0)" :: "r" (ptr) : "memory"); 15 | } 16 | 17 | 18 | static uintptr_t* get_next_level(pagemap_t* pagemap, uint16_t index, uint8_t do_alloc) { 19 | if (pagemap[index] & PTE_PRESENT) { 20 | return ((uintptr_t*)pagemap[index]); 21 | } 22 | 23 | if (!(do_alloc)) { 24 | return NULL; 25 | } 26 | 27 | uintptr_t next_level = pmm_alloc(1); 28 | ASSERT(next_level != 0, "Failed to allocate frame!\n"); 29 | 30 | pagemap[index] = (pagemap_t)next_level | PTE_PRESENT | PTE_WRITABLE; 31 | return (uintptr_t*)next_level; 32 | } 33 | 34 | 35 | void* vmm_alloc(size_t pages) { 36 | return (void*)(pmm_alloc(pages) + VMM_HIGHER_HALF); 37 | } 38 | 39 | 40 | void vmm_map_page(pagemap_t top_level, vaddr_t vaddr, paddr_t paddr, uint64_t flags) { 41 | size_t pml4_index = (vaddr & ((size_t)0x1FF << 39)) >> 39; 42 | size_t pdpt_index = (vaddr & ((size_t)0x1FF << 30)) >> 30; 43 | size_t pd_index = (vaddr & ((size_t)0x1FF << 21)) >> 21; 44 | size_t pt_index = (vaddr & ((size_t)0x1FF << 12)) >> 12; 45 | 46 | 47 | uintptr_t* pdpt = get_next_level((pagemap_t*)top_level, pml4_index, 1); 48 | uintptr_t* pd = get_next_level(pdpt, pdpt_index, 1); 49 | uintptr_t* pt = get_next_level(pd, pd_index, 1); 50 | pt[pt_index] = paddr | flags; 51 | __tlb_flush_single(vaddr); 52 | } 53 | -------------------------------------------------------------------------------- /sys/src/sched/sched.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | 6 | void sched_init(void) {} 7 | -------------------------------------------------------------------------------- /tools/cross.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ################################################################ 3 | # A script to build a GNU GCC and Binutils cross-compiler 4 | # Based on https://wiki.osdev.org/GCC_Cross-Compiler 5 | # 6 | # Copyright (c) 2022, the Native authors. 7 | # SPDX-License-Identifier: BSD-2-Clause 8 | ################################################################ 9 | 10 | ################################################################ 11 | # Configuration 12 | ################################################################ 13 | 14 | # Exit if there is an error 15 | set -e 16 | 17 | # Target to use 18 | TARGET=x86_64-elf 19 | 20 | # Versions to build 21 | # Always use the latest working version (test before updating) 22 | BUT_VER=2.39 23 | GCC_VER=12.2.0 24 | 25 | # Tar file extension to use 26 | # Always use the one with the smallest file size (check when updating version) 27 | BUT_EXT=xz 28 | GCC_EXT=xz 29 | 30 | # Multicore builds 31 | # Currrently automatic using nproc 32 | CORES=$(($(nproc) + 1)) 33 | LOAD=$(nproc) 34 | 35 | PREFIX="$(pwd)/cross" 36 | export PATH="$PREFIX/bin:$PATH" 37 | 38 | echo "Building $TARGET Binutils $BUT_VER and GCC $GCC_VER..." 39 | echo "Cores: $CORES, load: $LOAD" 40 | 41 | ################################################################ 42 | # Source Tarballs 43 | ################################################################ 44 | 45 | BUT_TARBALL=binutils-$BUT_VER.tar.$BUT_EXT 46 | GCC_TARBALL=gcc-$GCC_VER.tar.$GCC_EXT 47 | 48 | mkdir -p buildcc 49 | cd buildcc 50 | 51 | # Download tarballs 52 | echo "Downloading Binutils tarball..." 53 | if [ ! -f $BUT_TARBALL ]; then 54 | wget https://ftp.gnu.org/gnu/binutils/$BUT_TARBALL 55 | fi 56 | 57 | echo "Downloading GCC tarball..." 58 | if [ ! -f $GCC_TARBALL ]; then 59 | wget https://ftp.gnu.org/gnu/gcc/gcc-$GCC_VER/$GCC_TARBALL 60 | fi 61 | 62 | # Unzip tarballs 63 | printf "%s" "Unzipping Binutils tarball" 64 | tar -xf $BUT_TARBALL --checkpoint=.400 65 | echo "" # Newline :~) 66 | printf "%s" "Unzipping GCC tarball" 67 | tar -xf $GCC_TARBALL --checkpoint=.400 68 | 69 | ################################################################ 70 | # Building 71 | ################################################################ 72 | 73 | echo "Removing old build directories..." 74 | rm -rf buildcc-gcc build-binutils 75 | 76 | # Build binutils 77 | mkdir buildcc-binutils 78 | cd buildcc-binutils 79 | echo "Configuring Binutils..." 80 | ../binutils-$BUT_VER/configure --target=$TARGET --prefix="$PREFIX" --with-sysroot --disable-nls --disable-werror 81 | echo "Building Binutils..." 82 | make -j$CORES -l$LOAD 83 | echo "Installing Binutils..." 84 | make install -j$CORES -l$LOAD 85 | cd .. 86 | 87 | # Build gcc 88 | cd gcc-$GCC_VER 89 | echo "Downloading prerequisites for GCC..." 90 | contrib/download_prerequisites 91 | cd .. 92 | mkdir buildcc-gcc 93 | cd buildcc-gcc 94 | echo "Configuring GCC..." 95 | ../gcc-$GCC_VER/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c --without-headers 96 | echo "Building all-gcc..." 97 | make all-gcc -j$CORES -l$LOAD 98 | echo "Building all-target-libgcc..." 99 | make all-target-libgcc -j$CORES -l$LOAD 100 | echo "Installing GCC..." 101 | make install-gcc -j$CORES -l$LOAD 102 | echo "Installing target-libgcc..." 103 | make install-target-libgcc -j$CORES -l$LOAD 104 | cd ../.. 105 | 106 | echo "Removing build directory..." 107 | rm -rf buildcc 108 | 109 | echo "Build complete, binaries are in $PREFIX/bin" 110 | 111 | ################################################################ 112 | # Basic Testing (just prints info for now) 113 | ################################################################ 114 | 115 | echo "Testing GCC..." 116 | $TARGET-gcc -v 117 | 118 | echo "Testing LD..." 119 | $TARGET-ld -v 120 | 121 | echo "Done!" 122 | --------------------------------------------------------------------------------