├── .gitignore ├── .gitmodules ├── LICENSE.txt ├── README.md ├── drivers ├── libdriver │ ├── bit.hpp │ ├── io.hpp │ └── math.hpp ├── meson.build ├── storage │ ├── ahci │ │ ├── ahci.cpp │ │ ├── ahci.hpp │ │ ├── main.cpp │ │ └── meson.build │ ├── ata │ │ ├── README.md │ │ ├── ata.cpp │ │ ├── ata.hpp │ │ ├── main.cpp │ │ └── meson.build │ ├── meson.build │ └── nvme │ │ ├── include │ │ └── nvme │ │ │ ├── common.hpp │ │ │ ├── io_controller.hpp │ │ │ ├── queue.hpp │ │ │ └── regs.hpp │ │ ├── meson.build │ │ └── source │ │ ├── io_controller.cpp │ │ ├── main.cpp │ │ └── queue.cpp ├── usb │ ├── meson.build │ ├── usb.hpp │ └── xhci │ │ ├── context.hpp │ │ ├── main.cpp │ │ ├── meson.build │ │ ├── trb.hpp │ │ ├── xhci.cpp │ │ └── xhci.hpp └── video │ ├── bga │ ├── bga.cpp │ ├── bga.hpp │ ├── main.cpp │ └── meson.build │ ├── meson.build │ └── vbe │ ├── main.cpp │ ├── meson.build │ ├── real_mode.hpp │ ├── vbe.cpp │ └── vbe.hpp ├── kbus ├── main.cpp └── meson.build ├── kernel ├── build │ └── linker.ld ├── docs │ ├── arch │ │ └── x86_64 │ │ │ └── interrupts.asm.md │ ├── args.md │ ├── compiling.md │ ├── ideas.txt │ ├── memory_layout.md │ └── proc │ │ └── process.cpp.md ├── include │ ├── Sigma │ │ ├── acpi │ │ │ ├── acpi.h │ │ │ ├── fadt.h │ │ │ ├── madt.h │ │ │ └── tables.h │ │ ├── arch │ │ │ └── x86_64 │ │ │ │ ├── amd │ │ │ │ └── svm.hpp │ │ │ │ ├── cpu.h │ │ │ │ ├── drivers │ │ │ │ ├── apic.h │ │ │ │ ├── hpet.h │ │ │ │ ├── pci.h │ │ │ │ ├── pic.h │ │ │ │ ├── serial.h │ │ │ │ └── vga.h │ │ │ │ ├── gdt.h │ │ │ │ ├── idt.h │ │ │ │ ├── intel │ │ │ │ ├── sl_paging.hpp │ │ │ │ └── vt-d.hpp │ │ │ │ ├── io.h │ │ │ │ ├── misc │ │ │ │ ├── misc.h │ │ │ │ └── spinlock.h │ │ │ │ ├── msr.h │ │ │ │ ├── paging.h │ │ │ │ └── tss.h │ │ ├── boot_protocol.h │ │ ├── common.h │ │ ├── config.h.in │ │ ├── generic │ │ │ ├── device.h │ │ │ ├── event.hpp │ │ │ ├── user_handle.hpp │ │ │ └── virt.hpp │ │ ├── misc │ │ │ ├── bitops.h │ │ │ ├── compiler.h │ │ │ ├── cpp_support.h │ │ │ ├── debug.h │ │ │ ├── misc.h │ │ │ └── panic.h │ │ ├── mm │ │ │ ├── alloc.h │ │ │ ├── hmm.h │ │ │ ├── pmm.h │ │ │ └── vmm.h │ │ ├── proc │ │ │ ├── elf.h │ │ │ ├── initrd.h │ │ │ ├── ipc.hpp │ │ │ ├── process.h │ │ │ ├── simd.h │ │ │ └── syscall.h │ │ ├── smp │ │ │ ├── cpu.h │ │ │ ├── ipi.h │ │ │ └── smp.h │ │ └── types │ │ │ ├── bitmap.hpp │ │ │ ├── hash_map.hpp │ │ │ ├── linked_list.h │ │ │ ├── minimal_array.h │ │ │ ├── queue.h │ │ │ └── vector.h │ ├── klibc │ │ ├── stdio.h │ │ ├── stdlib.h │ │ └── string.h │ └── klibcxx │ │ ├── README.md │ │ ├── algorithm.hpp │ │ ├── common.hpp │ │ ├── experimental │ │ └── source_location.hpp │ │ ├── functional.hpp │ │ ├── memory.hpp │ │ ├── mutex.hpp │ │ └── utility.hpp ├── meson.build ├── meson_options.txt ├── source │ ├── acpi │ │ ├── acpi.cpp │ │ ├── laihost.cpp │ │ └── madt.cpp │ ├── arch │ │ └── x86_64 │ │ │ ├── amd │ │ │ ├── svm.cpp │ │ │ └── svm_low.asm │ │ │ ├── cpu.cpp │ │ │ ├── cpu_low.asm │ │ │ ├── drivers │ │ │ ├── apic.cpp │ │ │ ├── hpet.cpp │ │ │ ├── pci.cpp │ │ │ ├── pic.cpp │ │ │ └── vga.cpp │ │ │ ├── gdt.cpp │ │ │ ├── idt.cpp │ │ │ ├── intel │ │ │ ├── sl_paging.cpp │ │ │ └── vt-d.cpp │ │ │ ├── interrupts.asm │ │ │ ├── io.cpp │ │ │ ├── misc │ │ │ ├── misc.cpp │ │ │ └── spinlock.asm │ │ │ ├── msr.cpp │ │ │ └── paging.cpp │ ├── crti.S │ ├── crtn.S │ ├── generic │ │ ├── device.cpp │ │ └── virt.cpp │ ├── kernel_early.asm │ ├── kernel_main.cpp │ ├── klibc │ │ ├── stdio.cpp │ │ ├── stdlib.cpp │ │ └── string.cpp │ ├── misc │ │ ├── cpp_support.cpp │ │ ├── debug.cpp │ │ ├── misc.cpp │ │ └── panic.cpp │ ├── mm │ │ ├── alloc.cpp │ │ ├── hmm.cpp │ │ ├── pmm.cpp │ │ └── vmm.cpp │ ├── proc │ │ ├── elf.cpp │ │ ├── initrd.cpp │ │ ├── ipc.cpp │ │ ├── process.cpp │ │ ├── process_low.asm │ │ ├── simd.cpp │ │ └── syscall.cpp │ └── smp │ │ ├── gs.asm │ │ ├── ipi.cpp │ │ ├── smp.cpp │ │ └── trampoline.S └── subprojects │ └── multiboot_loader │ ├── include │ └── loader │ │ ├── 3rdparty │ │ └── multiboot.h │ │ ├── common.h │ │ ├── multiboot.h │ │ └── protocol.h │ ├── meson.build │ └── source │ ├── common.cpp │ ├── load.asm │ ├── loader_main.cpp │ ├── multiboot.asm │ ├── multiboot.cpp │ └── start_longmode.S ├── libs ├── libkbus │ ├── include │ │ └── kbus │ │ │ └── kbus.hpp │ ├── meson.build │ └── source │ │ └── kbus.cpp └── libsigma │ ├── include │ └── libsigma │ │ ├── sys.h │ │ ├── syscall.h │ │ └── virt.h │ ├── meson.build │ ├── meson_options.txt │ └── source │ ├── common.h │ ├── sys.c │ ├── syscall.c │ └── virt.c ├── protocol ├── build.sh ├── kbus.xml └── zeta.xml └── zeta ├── include └── Zeta │ ├── devfs.h │ ├── singleton.h │ ├── tree.h │ └── vfs.h ├── meson.build └── source ├── main.cpp └── vfs.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/git,c++,linux,visualstudiocode 3 | # Edit at https://www.gitignore.io/?templates=git,c++,linux,visualstudiocode 4 | 5 | ### C++ ### 6 | # Prerequisites 7 | *.d 8 | 9 | # Compiled Object files 10 | *.slo 11 | *.lo 12 | *.o 13 | *.obj 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Compiled Dynamic libraries 20 | *.so 21 | *.dylib 22 | *.dll 23 | 24 | # Fortran module files 25 | *.mod 26 | *.smod 27 | 28 | # Compiled Static libraries 29 | *.lai 30 | *.la 31 | *.a 32 | *.lib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | 39 | ### Git ### 40 | # Created by git for backups. To disable backups in Git: 41 | # $ git config --global mergetool.keepBackup false 42 | *.orig 43 | 44 | # Created by git when using merge tools for conflicts 45 | *.BACKUP.* 46 | *.BASE.* 47 | *.LOCAL.* 48 | *.REMOTE.* 49 | *_BACKUP_*.txt 50 | *_BASE_*.txt 51 | *_LOCAL_*.txt 52 | *_REMOTE_*.txt 53 | 54 | ### Linux ### 55 | *~ 56 | 57 | # temporary files which can be created if a process still has a handle open of a deleted file 58 | .fuse_hidden* 59 | 60 | # KDE directory preferences 61 | .directory 62 | 63 | # Linux trash folder which might appear on any partition or disk 64 | .Trash-* 65 | 66 | # .nfs files are created when an open file is removed but is still being accessed 67 | .nfs* 68 | 69 | ### VisualStudioCode ### 70 | .vscode/* 71 | 72 | ### VisualStudioCode Patch ### 73 | # Ignore all local history of files 74 | .history 75 | 76 | # End of https://www.gitignore.io/api/git,c++,linux,visualstudiocode 77 | *.iso 78 | *.img 79 | *.bin 80 | *.tar 81 | *.xbstrap 82 | 83 | build/ 84 | kernel/build/iso/ 85 | 86 | *.log 87 | 88 | bx_enh_dbg.ini 89 | 90 | kernel/include/protocols/* 91 | 92 | Sigma.srctrlbm 93 | Sigma.srctrldb 94 | Sigma.srctrlprj 95 | 96 | .idea/ 97 | cmake-build-debug -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "subprojects/lai"] 2 | path = kernel/subprojects/lai 3 | url = https://www.github.com/qword-os/lai 4 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2019, Thomas Woertman 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 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sigma :rocket: 2 | Sigma OS is located in this repo 3 | 4 | It is an x86_64 (semi)POSIX (semi)Microkernel but still in early development 5 | 6 | ## How to build 7 | Look in [sigma-os/bootstrap](https://github.com/sigma-os/bootstrap) 8 | 9 | ## Features 10 | - Full x86_64 long mode support 11 | - Support for a lot of x86(\_64) minor features (e.g. SMEP, [SMAP](https://en.wikipedia.org/wiki/Supervisor_Mode_Access_Prevention), PCID and x2APIC) 12 | - ACPI and AML support with [lai](https://www.github.com/qword-os/lai) 13 | - APIC support + LAPIC timer for scheduling IRQs 14 | - PCI / PCI-Express Configuration space enumeration 15 | - SMP + Simple Queue based scheduler 16 | - Dynamically linked userland backed by [mlibc](https://www.github.com/managarm/mlibc) 17 | - Modern disk drivers (AHCI, NVMe) 18 | - Virtualization (AMD-V only for now) 19 | - Protection against malicious drivers with IOMMU (VT-d only for now) 20 | 21 | ## Notes 22 | 23 | - Sigma does try to have as much drivers and things in userspace(PL3) but it doesn't attempt to move the memory manager and process management / scheduler out of the kernel. 24 | 25 | - When running vbox use the `ich9` chipset, if you must use the `piix3` chipset you need to explicitly enable the HPET with this command `VBoxManage modifyvm --hpet on` 26 | -------------------------------------------------------------------------------- /drivers/libdriver/bit.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | constexpr uint32_t bswap32(uint32_t dword) { 9 | return (uint32_t)((dword>>24) & 0xFF) 10 | | ((dword<<8) & 0xFF0000) 11 | | ((dword>>8)&0xFF00) 12 | | ((dword<<24)&0xFF000000); 13 | } 14 | 15 | template 16 | class bitmap { 17 | public: 18 | constexpr bitmap(){ 19 | n_bytes = div_ceil(nBits, 8); 20 | array = std::make_unique(n_bytes); 21 | } 22 | 23 | constexpr void set(uint64_t bit){ 24 | uint64_t index = bit / 8; 25 | uint64_t offset = bit % 8; 26 | 27 | array[index] |= (1ull << offset); 28 | } 29 | 30 | constexpr void clear(uint64_t bit){ 31 | uint64_t index = bit / 8; 32 | uint64_t offset = bit % 8; 33 | 34 | array[index] &= ~(1ull << offset); 35 | } 36 | 37 | constexpr bool test(uint64_t bit){ 38 | uint64_t index = bit / 8; 39 | uint64_t offset = bit % 8; 40 | 41 | bool state = (array[index] & (1ull << offset)) ? true : false; 42 | return state; 43 | } 44 | 45 | constexpr uint64_t get_free_bit(){ 46 | for(size_t i = 0; i < n_bytes; i++){ 47 | if(array[i] != 0xFF){ // Test if this entry is full 48 | for(uint64_t j = 0; j < 8; j++){ 49 | uint64_t bit = 1ull << j; 50 | if(!(array[i] & bit)) 51 | return i * 8 + j; 52 | } 53 | } 54 | } 55 | 56 | return (uint64_t)-1; 57 | } 58 | 59 | private: 60 | size_t n_bytes; 61 | std::unique_ptr array; 62 | }; -------------------------------------------------------------------------------- /drivers/libdriver/io.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | static inline uint8_t inb(uint16_t port){ 6 | uint8_t ret = 0; 7 | asm volatile ("in %1, %0" : "=a"(ret) : "Nd"(port)); 8 | return ret; 9 | } 10 | 11 | static inline void outb(uint16_t port, uint8_t value){ 12 | asm volatile ("out %0, %1" : : "a"(value), "Nd"(port)); 13 | } 14 | 15 | static inline uint16_t inw(uint16_t port){ 16 | uint16_t ret = 0; 17 | asm volatile ("in %1, %0" : "=a"(ret) : "Nd"(port)); 18 | return ret; 19 | } 20 | 21 | static inline void outw(uint16_t port, uint16_t value){ 22 | asm volatile ("out %0, %1" : : "a"(value), "Nd"(port)); 23 | } 24 | 25 | static inline uint32_t ind(uint16_t port){ 26 | uint32_t ret = 0; 27 | asm volatile ("in %1, %0" : "=a"(ret) : "Nd"(port)); 28 | return ret; 29 | } 30 | 31 | static inline void outd(uint16_t port, uint32_t value){ 32 | asm volatile ("out %0, %1" : : "a"(value), "Nd"(port)); 33 | } -------------------------------------------------------------------------------- /drivers/libdriver/math.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | constexpr uint64_t pow2(uint64_t power){ 6 | return 1 << power; 7 | } 8 | 9 | constexpr uint64_t div_ceil(uint64_t val, uint64_t div) { 10 | return (val + div - 1) / div; 11 | } 12 | 13 | constexpr uint64_t pow(uint64_t base, uint64_t pow){ 14 | uint64_t tmp = 1; 15 | for(uint64_t i = 0; i < pow; i++) 16 | tmp *= base; 17 | return tmp; 18 | } -------------------------------------------------------------------------------- /drivers/meson.build: -------------------------------------------------------------------------------- 1 | project('sigma-drivers', 'cpp', version: '0.0.1', default_options : ['cpp_std=c++17']) 2 | 3 | libsigma_dep = dependency('sigma') 4 | default_deps = [libsigma_dep] 5 | 6 | libdriver_include_dir = include_directories('.') 7 | default_include_dirs = [libdriver_include_dir] 8 | 9 | add_project_arguments('-Wall', '-Wextra', '-Wno-unknown-pragmas', '-fstrict-volatile-bitfields', language: 'cpp') 10 | 11 | subdir('storage/') 12 | subdir('video/') 13 | 14 | subdir('usb/') -------------------------------------------------------------------------------- /drivers/storage/ahci/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "ahci.hpp" 8 | 9 | int main(){ 10 | // Disable buffering for stdout and stderr so debug message show up immediately 11 | setvbuf(stdout, NULL, _IONBF, 0); 12 | setvbuf(stderr, NULL, _IONBF, 0); 13 | 14 | auto device_descriptor = devctl(devCtlFindPciClass, 0x1, 0x6, 0x1, 0); 15 | if(device_descriptor == -1){ 16 | std::cout << "ahci: Couldn't find a compatible controller" << std::endl; 17 | return 0; 18 | } 19 | 20 | if(devctl(devCtlClaim, device_descriptor, 0, 0, 0) == -1){ 21 | std::cout << "ahci: Failed to claim controller" << std::endl; 22 | return 0; 23 | } 24 | 25 | libsigma_resource_region_t region = {}; 26 | devctl(devCtlGetResourceRegion, device_descriptor, resourceRegionOriginPciBar, 5, (uint64_t)®ion); 27 | 28 | ahci::controller controller{region.base, region.len}; 29 | while(1) 30 | asm("pause"); 31 | } -------------------------------------------------------------------------------- /drivers/storage/ahci/meson.build: -------------------------------------------------------------------------------- 1 | ahci_sources = files('main.cpp', 'ahci.cpp') 2 | ahci_include_dirs = [default_include_dirs] 3 | ahci_deps = [default_deps] 4 | 5 | executable('ahci', ahci_sources, include_directories: ahci_include_dirs, dependencies: ahci_deps, install: true) -------------------------------------------------------------------------------- /drivers/storage/ata/README.md: -------------------------------------------------------------------------------- 1 | W.I.P. ATA Driver -------------------------------------------------------------------------------- /drivers/storage/ata/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ata.hpp" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(){ 9 | // Disable buffering for stdout and stderr so debug message show up immediately 10 | setvbuf(stdout, NULL, _IONBF, 0); 11 | setvbuf(stderr, NULL, _IONBF, 0); 12 | 13 | std::cerr << "ata: Driver is W.I.P." << std::endl; 14 | 15 | auto device_descriptor = devctl(devCtlFindPciClass, 0x1, 0x1, 0, 0); 16 | if(device_descriptor == -1){ 17 | std::cout << "ata: Couldn't find IDE controller" << std::endl; 18 | return 0; 19 | } 20 | 21 | if(devctl(devCtlClaim, device_descriptor, 0, 0, 0) == -1){ 22 | std::cout << "ata: Failed to claim controller" << std::endl; 23 | } 24 | 25 | libsigma_resource_region_t regions[4] = {}; 26 | devctl(devCtlGetResourceRegion, device_descriptor, resourceRegionOriginPciBar, 0, (uint64_t)®ions[0]); 27 | devctl(devCtlGetResourceRegion, device_descriptor, resourceRegionOriginPciBar, 1, (uint64_t)®ions[1]); 28 | devctl(devCtlGetResourceRegion, device_descriptor, resourceRegionOriginPciBar, 2, (uint64_t)®ions[2]); 29 | devctl(devCtlGetResourceRegion, device_descriptor, resourceRegionOriginPciBar, 3, (uint64_t)®ions[3]); 30 | 31 | std::pair ata1_base = ata::isa_ata1_base; 32 | 33 | if(regions[0].base != 0) 34 | ata1_base.first = regions[0].base; 35 | 36 | if(regions[1].base != 0) 37 | ata1_base.second = regions[1].base; 38 | 39 | std::cout << "ata: Booting controller 1 with region 0x" << std::hex << ata1_base.first << " : 0x" << ata1_base.second << std::endl; 40 | ata::controller ata1{ata1_base}; 41 | std::cout << "ata: Initialized controller 1" << std::endl; 42 | while(1); 43 | } -------------------------------------------------------------------------------- /drivers/storage/ata/meson.build: -------------------------------------------------------------------------------- 1 | ata_sources = files('main.cpp', 'ata.cpp') 2 | ata_include_dirs = [default_include_dirs] 3 | ata_deps = [default_deps] 4 | 5 | executable('ata', ata_sources, include_directories: ata_include_dirs, dependencies: ata_deps, install: true) -------------------------------------------------------------------------------- /drivers/storage/meson.build: -------------------------------------------------------------------------------- 1 | subdir('ata/') 2 | subdir('ahci/') 3 | subdir('nvme/') -------------------------------------------------------------------------------- /drivers/storage/nvme/include/nvme/common.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nvme 6 | { 7 | using cid_t = uint16_t; 8 | using qid_t = uint16_t; 9 | using nsid_t = uint32_t; 10 | } // namespace nvme 11 | -------------------------------------------------------------------------------- /drivers/storage/nvme/include/nvme/io_controller.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace nvme { 13 | class io_controller { 14 | public: 15 | io_controller(libsigma_resource_region_t region); 16 | 17 | enum class shutdown_types { 18 | NormalShutdown, 19 | AbruptShutdown, 20 | }; 21 | 22 | void set_power_state(shutdown_types type); 23 | void reset_subsystem(); 24 | 25 | std::vector read_sector(nsid_t nsid, uint64_t lba); 26 | 27 | private: 28 | bool set_features(uint8_t fid, uint32_t data); 29 | bool register_queue_pair(queue_pair& pair); 30 | bool identify_controller(regs::controller_identify_info* info); 31 | bool identify_namespace(nsid_t nsid, regs::namespace_identify_info* info); 32 | 33 | void print_identify_info(regs::controller_identify_info& info); 34 | 35 | std::vector get_active_namespaces(nsid_t max_nsid); 36 | 37 | bool weighted_round_robin_supported; 38 | 39 | size_t doorbell_stride; 40 | size_t n_queue_entries; 41 | 42 | volatile regs::bar* base; 43 | 44 | queue_pair admin_queue; 45 | queue_pair io_queue; 46 | 47 | std::string path; 48 | 49 | struct ns { 50 | uint64_t n_lbas; 51 | uint64_t sector_size; 52 | std::string path; 53 | }; 54 | 55 | std::unordered_map namespaces; 56 | }; 57 | } -------------------------------------------------------------------------------- /drivers/storage/nvme/include/nvme/queue.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | namespace nvme 12 | { 13 | class queue_pair { 14 | public: 15 | queue_pair() = default; 16 | queue_pair(size_t n_entries, uint16_t* submission_doorbell, uint16_t* completion_doorbell, qid_t qid); 17 | 18 | cid_t send_command(regs::command* cmd); 19 | bool send_and_wait(regs::command* cmd); 20 | 21 | size_t get_n_entries(); 22 | uintptr_t get_submission_phys_base(); 23 | uintptr_t get_completion_phys_base(); 24 | qid_t get_qid(){ 25 | return qid; 26 | } 27 | 28 | private: 29 | size_t n_entries; 30 | qid_t qid; 31 | 32 | static constexpr uint64_t n_commands = pow(2, 16); 33 | bitmap available_cids; 34 | 35 | struct submission_info { 36 | submission_info() = default; 37 | submission_info(size_t n_entries, uint16_t* doorbell); 38 | volatile regs::command* queue; 39 | volatile uint16_t* doorbell; 40 | 41 | uint16_t head, tail; 42 | libsigma_phys_region_t region; 43 | }; 44 | submission_info submission; 45 | 46 | struct completion_info { 47 | completion_info() = default; 48 | completion_info(size_t n_entries, uint16_t* doorbell); 49 | volatile regs::completion* queue; 50 | volatile uint16_t* doorbell; 51 | 52 | uint16_t head, tail; 53 | uint8_t expected_phase; 54 | libsigma_phys_region_t region; 55 | }; 56 | completion_info completion; 57 | }; 58 | } // namespace nvme 59 | -------------------------------------------------------------------------------- /drivers/storage/nvme/meson.build: -------------------------------------------------------------------------------- 1 | nvme_sources = files('source/main.cpp', 'source/io_controller.cpp', 'source/queue.cpp') 2 | nvme_include_dirs = [default_include_dirs, include_directories('include')] 3 | nvme_deps = [default_deps] 4 | 5 | executable('nvme', nvme_sources, include_directories: nvme_include_dirs, dependencies: nvme_deps, install: true) -------------------------------------------------------------------------------- /drivers/storage/nvme/source/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | int main(){ 10 | // Disable buffering for stdout and stderr so debug message show up immediately 11 | setvbuf(stdout, NULL, _IONBF, 0); 12 | setvbuf(stderr, NULL, _IONBF, 0); 13 | 14 | auto device_descriptor = devctl(devCtlFindPciClass, 0x1, 0x8, 0x2, 0); // Only search for I/O Controllers 15 | if(device_descriptor == -1){ 16 | std::cout << "nvme: Couldn't find an I/O controller" << std::endl; 17 | return 0; 18 | } 19 | 20 | if(devctl(devCtlClaim, device_descriptor, 0, 0, 0) == -1){ 21 | std::cout << "nvme: Failed to claim controller" << std::endl; 22 | return 0; 23 | } 24 | 25 | libsigma_resource_region_t region = {}; 26 | devctl(devCtlGetResourceRegion, device_descriptor, resourceRegionOriginPciBar, 0, (uint64_t)®ion); 27 | 28 | nvme::io_controller controller{region}; 29 | while(1) 30 | asm("pause"); 31 | } -------------------------------------------------------------------------------- /drivers/storage/nvme/source/queue.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace nvme; 8 | 9 | queue_pair::submission_info::submission_info(size_t n_entries, uint16_t* doorbell): doorbell{doorbell} { 10 | size_t queue_size = sizeof(regs::command) * n_entries; 11 | 12 | if(libsigma_get_phys_region(queue_size, PROT_READ | PROT_WRITE, MAP_ANON, ®ion)){ 13 | std::cerr << "nvme: Couldn't allocate submission queue\n"; 14 | return; 15 | } 16 | 17 | this->queue = (regs::command*)region.virtual_addr; 18 | 19 | this->head = 0; 20 | this->tail = 0; 21 | } 22 | 23 | queue_pair::completion_info::completion_info(size_t n_entries, uint16_t* doorbell): doorbell{doorbell} { 24 | size_t queue_size = sizeof(regs::completion) * n_entries; 25 | 26 | if(libsigma_get_phys_region(queue_size, PROT_READ | PROT_WRITE, MAP_ANON, ®ion)){ 27 | std::cerr << "nvme: Couldn't allocate completion queue\n"; 28 | return; 29 | } 30 | 31 | this->queue = (regs::completion*)region.virtual_addr; 32 | 33 | this->head = 0; 34 | this->tail = 0; 35 | this->expected_phase = 1; 36 | } 37 | 38 | queue_pair::queue_pair(size_t n_entries, uint16_t* submission_doorbell, uint16_t* completion_doorbell, qid_t qid): n_entries{n_entries}, qid{qid}, available_cids{bitmap{}}, submission{submission_info{n_entries, submission_doorbell}}, completion{completion_info{n_entries, completion_doorbell}}{} 39 | 40 | cid_t queue_pair::send_command(regs::command* cmd){ 41 | cid_t cid = this->available_cids.get_free_bit(); 42 | 43 | cmd->header.cid = cid; 44 | 45 | uint16_t tail = submission.tail; 46 | memcpy((void*)(submission.queue + tail), cmd, 64); 47 | tail++; 48 | 49 | if(tail == n_entries) 50 | tail = 0; // Wrap around if end is reached 51 | 52 | *submission.doorbell = tail; 53 | submission.tail = tail; 54 | 55 | return cid; 56 | } 57 | 58 | bool queue_pair::send_and_wait(regs::command* cmd){ 59 | uint16_t head = completion.head; 60 | 61 | auto cid = send_command(cmd); 62 | 63 | while(true){ 64 | bool phase = completion.queue[completion.head].status.phase; 65 | if(phase == completion.expected_phase) 66 | break; 67 | } 68 | 69 | uint8_t status_code = completion.queue[completion.head].status.code; 70 | bool ret = true; 71 | if(status_code){ 72 | std::cerr << "nvme: Error in completion queue, code: 0x" << std::hex << (uint64_t)(status_code & 0xFF) << std::endl; 73 | ret = false; 74 | } 75 | 76 | head++; 77 | if(head == n_entries){ 78 | head = 0; 79 | completion.expected_phase = !completion.expected_phase; 80 | } 81 | 82 | *completion.doorbell = head; 83 | completion.head = head; 84 | 85 | return ret; 86 | } 87 | 88 | size_t queue_pair::get_n_entries(){ 89 | return this->n_entries; 90 | } 91 | 92 | uintptr_t queue_pair::get_submission_phys_base(){ 93 | return this->submission.region.physical_addr; 94 | } 95 | 96 | uintptr_t queue_pair::get_completion_phys_base(){ 97 | return this->completion.region.physical_addr; 98 | } -------------------------------------------------------------------------------- /drivers/usb/meson.build: -------------------------------------------------------------------------------- 1 | subdir('xhci/') -------------------------------------------------------------------------------- /drivers/usb/usb.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace usb 6 | { 7 | enum { 8 | requestRecipientDevice = 0, 9 | requestRecipientInteface = (1 << 0), 10 | requestRecipientEndpoint = (2 << 0), 11 | requestRecipientOther = (3 << 0), 12 | 13 | requestTypeStandard = 0, 14 | requestTypeClass = (1 << 5), 15 | requestTypeVendor = (2 << 5), 16 | 17 | requestDirectionHostToDevice = 0, 18 | requestDirectionDeviceToHost = (1 << 7), 19 | }; 20 | 21 | enum { 22 | requestGetStatus = 0, 23 | requestClearFeature = 1, 24 | requestSetFeature = 3, 25 | requestSetAddress = 5, 26 | requestGetDescriptor = 6, 27 | requestSetDescriptor = 7, 28 | requestGetConfiguration = 8, 29 | requestSetConfiguration = 9, 30 | requestGetInterface = 10, 31 | requestSetInterface = 11, 32 | requestSynchFrame = 12, 33 | requestSetSel = 48, 34 | requestSetIsochDelay = 49, 35 | }; 36 | 37 | enum { 38 | descriptorTypeDevice = 1, 39 | descriptorTypeConfiguration = 2, 40 | descriptorTypeString = 3, 41 | descriptorTypeInterface = 4, 42 | descriptorTypeEndpoint = 5, 43 | descriptorTypeInterfacePower = 8, 44 | descriptorTypeOtg = 9, 45 | descriptorTypeDebug = 10, 46 | descriptorTypeInterfaceAssociation = 11, 47 | descriptorTypeBos = 15, 48 | descriptorTypeDeviceCapability = 16, 49 | descriptorTypeSuperSpeedUseEndpointCompanion = 48, 50 | }; 51 | 52 | struct [[gnu::packed]] packet { 53 | uint8_t request_type; 54 | uint8_t request; 55 | uint16_t value; 56 | uint16_t index; 57 | uint16_t length; 58 | }; 59 | 60 | struct [[gnu::packed]] device_descriptor { 61 | uint8_t length; 62 | uint8_t descriptor_type; 63 | uint16_t usb_version; 64 | uint8_t device_class; 65 | uint8_t device_sub_class; 66 | uint8_t protocol; 67 | uint8_t max_packet_size; 68 | uint16_t vendor_id; 69 | uint16_t product_id; 70 | uint16_t device_release; 71 | uint8_t manufacturer; 72 | uint8_t product; 73 | uint8_t serial_number; 74 | uint8_t num_configs; 75 | }; 76 | 77 | struct [[gnu::packed]] string_langid_descriptor { 78 | uint8_t length; 79 | uint8_t type; 80 | uint16_t langids[(256 - 2) / 2]; 81 | }; 82 | 83 | struct [[gnu::packed]] string_unicode_descriptor { 84 | uint8_t length; 85 | uint8_t type; 86 | char16_t str[(256 - 2) / 2]; 87 | }; 88 | } // namespace usb 89 | 90 | 91 | -------------------------------------------------------------------------------- /drivers/usb/xhci/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "xhci.hpp" 7 | 8 | int main(){ 9 | // Disable buffering for stdout and stderr so debug message show up immediately 10 | setvbuf(stdout, NULL, _IONBF, 0); 11 | setvbuf(stderr, NULL, _IONBF, 0); 12 | 13 | printf("xhci: Starting xHCI driver\n"); 14 | 15 | auto device_descriptor = devctl(devCtlFindPciClass, 0xC, 0x3, 0x30, 0); 16 | if(device_descriptor == -1){ 17 | printf("xhci: Couldn't find a compatible controller\n"); 18 | return 0; 19 | } 20 | 21 | if(devctl(devCtlClaim, device_descriptor, 0, 0, 0) == -1){ 22 | printf("xhci: Failed to claim controller\n"); 23 | return 0; 24 | } 25 | 26 | 27 | xhci::controller c{device_descriptor}; 28 | 29 | return 0; 30 | } -------------------------------------------------------------------------------- /drivers/usb/xhci/meson.build: -------------------------------------------------------------------------------- 1 | xhci_sources = files('main.cpp', 'xhci.cpp') 2 | xhci_include_dirs = [default_include_dirs] 3 | xhci_deps = [default_deps] 4 | 5 | executable('xhci', xhci_sources, include_directories: xhci_include_dirs, dependencies: xhci_deps, install: true) -------------------------------------------------------------------------------- /drivers/video/bga/bga.cpp: -------------------------------------------------------------------------------- 1 | #include "bga.hpp" 2 | #include 3 | 4 | #include 5 | 6 | void bga::write(uint16_t reg, uint16_t val){ 7 | outw(index, reg); 8 | outw(data, val); 9 | } 10 | 11 | uint16_t bga::read(uint16_t reg){ 12 | outw(index, reg); 13 | return inw(data); 14 | } 15 | 16 | bga::bga(){ 17 | // TODO: Get Index, Data, Lfb and don't assume the defaults 18 | 19 | index = bgaIoIndex; 20 | data = bgaIoData; 21 | lfb = bgaLfbBase; 22 | 23 | uint16_t version = read(bgaIndexId); 24 | 25 | // Check fixed version prefix 26 | if((version & 0xFFF0) != bgaId0) 27 | return; // No BGA controller here 28 | 29 | printf("bga: Detected Controller, version: %d\n", version & 0x000F); 30 | 31 | // Sets bgaIndexXres, bgaIndexYres, bgaIndexBpp to their max values 32 | write(bgaIndexEnable, bgaGetCaps); 33 | 34 | if(read(bgaIndexXres) > bgaMaxXres) 35 | max_x = bgaMaxXres; 36 | else 37 | max_x = read(bgaIndexXres); 38 | 39 | if(read(bgaIndexYres) > bgaMaxYres) 40 | max_y = bgaMaxYres; 41 | else 42 | max_y = read(bgaIndexYres); 43 | 44 | if(read(bgaIndexBpp) > bgaMaxBpp) 45 | max_bpp = bgaMaxBpp; 46 | else 47 | max_bpp = read(bgaIndexBpp); 48 | 49 | printf("\tMax resolution %dx%d at %d bpp\n", max_x, max_y, max_bpp); 50 | 51 | write(bgaIndexEnable, bgaDisabled); 52 | } 53 | 54 | void bga::set_mode(std::pair res, uint16_t bpp){ 55 | if(res.first > max_x || res.second > max_y || bpp > max_bpp){ 56 | printf("bga: Unsupported mode\n"); 57 | return; 58 | } 59 | 60 | write(bgaIndexEnable, bgaDisabled); 61 | write(bgaIndexXres, res.first); 62 | write(bgaIndexYres, res.second); 63 | write(bgaIndexBpp, bpp); 64 | 65 | write(bgaIndexEnable, bgaEnabled | bgaLfbEnabled); 66 | } 67 | 68 | uintptr_t bga::get_lfb_phys(){ 69 | return lfb; 70 | } -------------------------------------------------------------------------------- /drivers/video/bga/bga.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | enum { 7 | bgaTotalVideoMemMb = 16, 8 | bga4BppPlaneShift = 4, 9 | 10 | bgaBankAddress = 0xA0000, 11 | bgaBankSizeKb = 64, 12 | 13 | bgaMaxXres = 2560, 14 | bgaMaxYres = 1600, 15 | bgaMaxBpp = 32, 16 | 17 | bgaIoIndex = 0x1CE, 18 | bgaIoData = 0x1CF, 19 | 20 | bgaIndexId = 0x0, 21 | bgaIndexXres = 0x1, 22 | bgaIndexYres = 0x2, 23 | bgaIndexBpp = 0x3, 24 | bgaIndexEnable = 0x4, 25 | bgaIndexBank = 0x5, 26 | bgaIndexVirtWidth = 0x6, 27 | bgaIndexVirtHeight = 0x7, 28 | bgaIndexXoffset = 0x8, 29 | bgaIndexYoffset = 0x9, 30 | bgaIndexVideoMemory64k = 0xa, 31 | bgaIndexDdc = 0xb, 32 | 33 | bgaId0 = 0xB0C0, 34 | bgaId1 = 0xB0C1, 35 | bgaId2 = 0xB0C2, 36 | bgaId3 = 0xB0C3, 37 | bgaId4 = 0xB0C4, 38 | bgaId5 = 0xB0C5, 39 | 40 | bgaDisabled = 0x0, 41 | bgaEnabled = 0x1, 42 | bgaGetCaps = 0x2, 43 | bga8bitDax = 0x20, 44 | bgaLfbEnabled = 0x40, 45 | bgaNoClearMem = 0x80, 46 | 47 | bgaLfbBase = 0xE0000000 48 | }; 49 | 50 | class bga { 51 | public: 52 | bga(); 53 | 54 | void set_mode(std::pair res, uint16_t bpp); 55 | 56 | uintptr_t get_lfb_phys(); 57 | 58 | private: 59 | void write(uint16_t reg, uint16_t val); 60 | uint16_t read(uint16_t reg); 61 | 62 | uint16_t index, data; 63 | uint32_t lfb; 64 | 65 | uint16_t max_x, max_y, max_bpp; 66 | }; -------------------------------------------------------------------------------- /drivers/video/bga/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "bga.hpp" 6 | 7 | 8 | int main(){ 9 | // Disable buffering for stdout and stderr so debug message show up immediately 10 | setvbuf(stdout, NULL, _IONBF, 0); 11 | setvbuf(stderr, NULL, _IONBF, 0); 12 | 13 | 14 | bga controller{}; 15 | 16 | controller.set_mode({1024, 768}, 32); 17 | 18 | printf("bga: LFB at %p", (void*)(controller.get_lfb_phys())); 19 | 20 | return 0; 21 | } -------------------------------------------------------------------------------- /drivers/video/bga/meson.build: -------------------------------------------------------------------------------- 1 | bga_sources = files('main.cpp', 'bga.cpp') 2 | bga_include_dirs = [default_include_dirs] 3 | bga_deps = [default_deps] 4 | 5 | executable('bga', bga_sources, include_directories: bga_include_dirs, dependencies: bga_deps, install: true) -------------------------------------------------------------------------------- /drivers/video/meson.build: -------------------------------------------------------------------------------- 1 | subdir('vbe/') 2 | subdir('bga/') -------------------------------------------------------------------------------- /drivers/video/vbe/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "vbe.hpp" 5 | 6 | int main(){ 7 | // Disable buffering for stdout and stderr so debug message show up immediately 8 | setvbuf(stdout, NULL, _IONBF, 0); 9 | setvbuf(stderr, NULL, _IONBF, 0); 10 | 11 | rm_cpu cpu{}; 12 | 13 | vbe::init(cpu); 14 | 15 | if(!vbe::edid_supported()) 16 | printf("vbe: EDID unsupported\n"); 17 | 18 | auto edid = vbe::get_edid_block(); 19 | 20 | auto res = vbe::get_display_native_res(edid); 21 | 22 | printf("vbe: Native display res: %dx%d\n", res.first, res.second); 23 | 24 | uint16_t mode = vbe::set_mode(res.first, res.second, 32); 25 | 26 | printf("vbe: mode: %04x set\n", mode); 27 | 28 | auto* info = vbe::get_mode_info(mode); 29 | 30 | printf("vbe: LFB is at 0x%x\n", info->framebuffer); 31 | return 0; 32 | } -------------------------------------------------------------------------------- /drivers/video/vbe/meson.build: -------------------------------------------------------------------------------- 1 | vbe_sources = files('main.cpp', 'vbe.cpp') 2 | vbe_include_dirs = [default_include_dirs] 3 | vbe_deps = [default_deps] 4 | 5 | executable('vbe', vbe_sources, include_directories: vbe_include_dirs, dependencies: vbe_deps, install: true) -------------------------------------------------------------------------------- /drivers/video/vbe/real_mode.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | struct rm_regs { 10 | uint32_t eflags; 11 | uint32_t ebp; 12 | uint32_t edi; 13 | uint32_t esi; 14 | uint32_t edx; 15 | uint32_t ecx; 16 | uint32_t ebx; 17 | uint32_t eax; 18 | }; 19 | 20 | struct rm_cpu { 21 | public: 22 | rm_cpu(){ 23 | vspace = vctl(vCtlCreateVspace, 0, 0, 0, 0); 24 | 25 | vctl(vCtlMapVspacePhys, vspace, 0x0, 0x0, 0xFFFFFFFF); // Map 4GiB of ram into the VM 26 | 27 | auto* ram = libsigma_vm_map(0x8000, NULL, NULL, PROT_READ | PROT_WRITE, MAP_ANON); 28 | 29 | payload = ((uint8_t*)ram + 0x2C00); 30 | 31 | data_section_addr = 0x7d00; 32 | data_section = ((uint8_t*)ram + 0x2D00); 33 | 34 | vctl(vCtlMapVspace, vspace, 0x5000, (uint64_t)ram, 0x8000); 35 | 36 | vcpu = vctl(vCtlCreateVcpu, 0, 0, 0, 0); 37 | } 38 | 39 | void intn(int n, rm_regs& regs){ 40 | /* 41 | int n 42 | vmmcall 43 | */ 44 | 45 | payload[0] = 0xCD; 46 | payload[1] = n; 47 | 48 | payload[2] = 0x0F; 49 | payload[3] = 0x01; 50 | payload[4] = 0xd9; 51 | 52 | vregs cpu_regs{}; 53 | 54 | vctl(vCtlGetRegs, vcpu, (uint64_t)&cpu_regs, 0, 0); 55 | 56 | cpu_regs.rax = regs.eax; 57 | cpu_regs.rbx = regs.ebx; 58 | cpu_regs.rcx = regs.ecx; 59 | cpu_regs.rdx = regs.edx; 60 | cpu_regs.rsi = regs.esi; 61 | cpu_regs.rdi = regs.edi; 62 | 63 | cpu_regs.rflags = regs.eflags; 64 | 65 | cpu_regs.ds.limit = 0xFFFFFFFF; 66 | cpu_regs.es.limit = 0xFFFFFFFF; 67 | cpu_regs.fs.limit = 0xFFFFFFFF; 68 | cpu_regs.gs.limit = 0xFFFFFFFF; 69 | cpu_regs.ss.limit = 0xFFFFFFFF; 70 | 71 | cpu_regs.cs.selector = 0; 72 | cpu_regs.cs.base = 0; 73 | cpu_regs.rip = 0x7C00; 74 | 75 | cpu_regs.rsp = 0x7C00; 76 | 77 | vctl(vCtlSetRegs, vcpu, (uint64_t)&cpu_regs, 0, 0); 78 | 79 | // Setup state, now run 80 | 81 | vexit exit = {}; 82 | while(1){ 83 | vctl(vCtlRunVcpu, vcpu, (uint64_t)&exit, 0, 0); 84 | 85 | /*printf("Exit reason: %lx\nOpcode: ", exit.reason); 86 | 87 | for(int i = 0; i < exit.opcode_length; i++) 88 | printf("0x%02X ", exit.opcode[i]); 89 | 90 | printf("\n");*/ 91 | 92 | if(exit.reason == vCtlExitReasonInterrupt){ 93 | printf("Interrupt: vector: %02x\n", exit.interrupt_number); 94 | break; 95 | } else if(exit.reason == vCtlExitReasonPortRead){ 96 | switch(exit.opcode[0]){ 97 | default: 98 | printf("Unknown PIO IN opcode: %x\n", exit.opcode[0]); 99 | while(1) 100 | asm("pause"); 101 | } 102 | } else if(exit.reason == vCtlExitReasonPortWrite){ 103 | switch(exit.opcode[0]){ 104 | default: 105 | printf("Unknown PIO OUT opcode: %x\n", exit.opcode[0]); 106 | while(1) 107 | asm("pause"); 108 | } 109 | } else if(exit.reason == vCtlExitReasonHypercall) 110 | break; 111 | } 112 | 113 | vctl(vCtlGetRegs, vcpu, (uint64_t)&cpu_regs, 0, 0); 114 | 115 | regs.eax = cpu_regs.rax; 116 | regs.ebx = cpu_regs.rbx; 117 | regs.ecx = cpu_regs.rcx; 118 | regs.edx = cpu_regs.rdx; 119 | regs.esi = cpu_regs.rsi; 120 | regs.edi = cpu_regs.rdi; 121 | 122 | regs.eflags = cpu_regs.rflags; 123 | } 124 | uint8_t* data_section = nullptr; 125 | uint32_t data_section_addr = 0; 126 | 127 | private: 128 | 129 | uint64_t vspace, vcpu; 130 | 131 | uint8_t* payload; 132 | }; -------------------------------------------------------------------------------- /drivers/video/vbe/vbe.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "real_mode.hpp" 4 | 5 | #include 6 | 7 | namespace vbe 8 | { 9 | struct [[gnu::packed]] vbe_far_ptr { 10 | uint16_t off; 11 | uint16_t seg; 12 | 13 | uint32_t phys() { return (seg << 4) + off; } 14 | }; 15 | 16 | struct [[gnu::packed]] vbe_info_block { 17 | char sig[4]; 18 | uint8_t minor_ver; 19 | uint8_t major_ver; 20 | vbe_far_ptr oem; 21 | uint32_t cap; 22 | vbe_far_ptr mode_info; 23 | uint16_t total_mem; 24 | uint16_t software_revision; 25 | vbe_far_ptr vendor_string; 26 | vbe_far_ptr product_name; 27 | vbe_far_ptr product_revision; 28 | uint8_t reserved[222]; 29 | uint8_t oem_data[256]; 30 | }; 31 | 32 | struct [[gnu::packed]] vbe_mode_info_block { 33 | uint16_t attr; 34 | uint8_t window_a; 35 | uint8_t window_b; 36 | uint16_t granularity; 37 | uint16_t window_size; 38 | uint16_t seg_a, seg_b; 39 | uint32_t win_func_ptr; 40 | uint16_t pitch, width, height; 41 | uint8_t w_char, y_char; 42 | uint8_t planes, bpp, banks, mmodel, bank_size, image_pages, reserved, red_mask, red_pos, green_mask, green_pos, blue_mask, blue_pos, reserved_mask, reserved_pos, colour_attr; 43 | uint32_t framebuffer; 44 | uint32_t off_screen_mem_off; 45 | uint16_t off_screen_mem_size; 46 | uint8_t reserved_0[206]; 47 | }; 48 | 49 | struct [[gnu::packed]] edid_block { 50 | uint8_t fixed_header[8]; 51 | uint16_t manufacturer_id; 52 | uint16_t manufacturer_product_code; 53 | uint32_t serial_number; 54 | uint8_t week_of_manufacture; 55 | uint8_t year_of_manufacture; 56 | uint8_t major_rev; 57 | uint8_t minor_rev; 58 | uint8_t video_input_param_bitmap; 59 | uint8_t horizontal_screen_size; 60 | uint8_t vertical_screen_size; 61 | uint8_t display_gamma; 62 | struct { 63 | uint8_t continous_timings : 1; 64 | uint8_t prefered_timing_mode : 1; 65 | uint8_t sRGB_colour_space : 1; 66 | uint8_t colour_type : 2; 67 | uint8_t dpms_active_off : 1; 68 | uint8_t dpms_suspend : 1; 69 | uint8_t dpms_standby : 1; 70 | } features; 71 | uint8_t rg_lsb; 72 | uint8_t bw_lsb; 73 | uint8_t red_msb; 74 | uint8_t red_msb_8; 75 | uint16_t green_msb_8; 76 | uint16_t blue_msb_8; 77 | uint16_t white_msb_8; 78 | uint8_t established_timing_bitmap[3]; 79 | struct { 80 | uint8_t x_res; 81 | struct { 82 | uint8_t vertical_freq : 6; 83 | uint8_t aspect_ratio : 2; 84 | }; 85 | } standard_timing_info[8]; 86 | struct { 87 | uint8_t data[18]; 88 | } detailed_timing_info[4]; 89 | uint8_t n_extensions; 90 | uint8_t checksum; 91 | }; 92 | static_assert(sizeof(edid_block) == 128); 93 | 94 | 95 | bool init(rm_cpu& vcpu); 96 | 97 | vbe_mode_info_block* get_mode_info(uint16_t mode); 98 | uint16_t set_mode(uint16_t width, uint16_t height, uint8_t bpp); 99 | 100 | bool edid_supported(); 101 | edid_block get_edid_block(); 102 | 103 | std::pair get_display_native_res(edid_block& edid); 104 | } // namespace vbe 105 | -------------------------------------------------------------------------------- /kbus/meson.build: -------------------------------------------------------------------------------- 1 | project('kbus', 'cpp', version: '0.0.1', default_options : ['cpp_std=c++17']) 2 | 3 | add_project_arguments('-Wall', '-Wextra', '-pedantic', '-Wno-unknown-pragmas', language: 'cpp') 4 | 5 | executable('kbus', 'main.cpp', dependencies: dependency('sigma'), install: true) -------------------------------------------------------------------------------- /kernel/build/linker.ld: -------------------------------------------------------------------------------- 1 | KERNEL_PBASE = 0x0000000000100000; 2 | KERNEL_VBASE = 0xffffffff80000000; 3 | 4 | ENTRY(_loader_start) 5 | 6 | SECTIONS { 7 | . = KERNEL_VBASE + KERNEL_PBASE; 8 | 9 | _kernel_start = .; 10 | .boot : AT(ADDR(.boot) - KERNEL_VBASE) { 11 | *(.loader_header*) 12 | } 13 | 14 | . = ALIGN(0x1000); 15 | 16 | .text : AT(ADDR(.text) - KERNEL_VBASE) { 17 | *(.text*) 18 | 19 | *(.init_start) 20 | *(.init) 21 | *(.init_end) 22 | 23 | *(.fini_start) 24 | *(.fini) 25 | *(.fini_end) 26 | } 27 | 28 | . = ALIGN(0x1000); 29 | 30 | .ctors : AT(ADDR(.ctors) - KERNEL_VBASE) { 31 | KEEP (*crtbegin.o(.ctors)) 32 | KEEP (*crtbegin?.o(.ctors)) 33 | KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) 34 | KEEP (*(SORT(.ctors.*))) 35 | KEEP (*(.ctors)) 36 | } 37 | .dtors : AT(ADDR(.dtors) - KERNEL_VBASE) 38 | { 39 | KEEP (*crtbegin.o(.dtors)) 40 | KEEP (*crtbegin?.o(.dtors)) 41 | KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) 42 | KEEP (*(SORT(.dtors.*))) 43 | KEEP (*(.dtors)) 44 | } 45 | 46 | . = ALIGN(0x1000); 47 | 48 | .rodata : AT(ADDR(.rodata) - KERNEL_VBASE) { 49 | *(.rodata*) 50 | 51 | KEEP(*(.init_array)) 52 | KEEP(*(.fini_array)) 53 | } 54 | 55 | . = ALIGN(0x1000); 56 | 57 | .data : AT(ADDR(.data) - KERNEL_VBASE) { 58 | *(.data*) 59 | 60 | *(.eh_frame) 61 | *(.eh_frame_hdr) 62 | } 63 | 64 | .bss : AT(ADDR(.bss) - KERNEL_VBASE) { 65 | *(.bss*) 66 | 67 | *(.COMMON*) 68 | } 69 | 70 | _kernel_end = .; 71 | } -------------------------------------------------------------------------------- /kernel/docs/arch/x86_64/interrupts.asm.md: -------------------------------------------------------------------------------- 1 | ISR stubs are created using the ISR_NOERROR and ISR_ERROR macros 2 | 3 | - ISR_ERROR is for the exceptions that the CPU pushes an error code on the stack for 4 | - ISR_NOERROR is for the exceptions that the CPU doesn't push an error on the stack for *and* Normal interrupts, IRQ and anything other 5 | - It pushes a dummy error code for a consistent stack 6 | 7 | 8 | 9 | ISR 255 is *always* reserved for APIC Spurious interrupts, *even* if for some reason the APIC driver fails 10 | - Therefore the only thing it does is *immediately* 11 | ``` 12 | iretq 13 | ``` 14 | 15 | ISR 250 to 254 are *always* reserved for IPIs, *even* if there are no APs 16 | ISR 249 is *always* a syscall handler, even if the syscall or sysenter instructions are enabled 17 | ISR 248 is the APIC timer handler -------------------------------------------------------------------------------- /kernel/docs/args.md: -------------------------------------------------------------------------------- 1 | The user can pass args to the kernel via grub.cfg 2 | The syntax is currently very simple and quite fragile 3 | There are 2 things you can do 4 | - Define a bool with the key + space, for example `acpi_trace ` 5 | - Defne a string with the key + '=' + value + space, for example `dsdt_override=/boot/dsdt.bin` 6 | 7 | ## OS Features 8 | - `debug` takes a bool containing the type of way debug info should be sent, current legal values are `serial` to send them over rs232 and `vga` to send them via the normal VGA text mode. 9 | - `serial` is default 10 | 11 | ## ACPI Features 12 | - `dsdt_override` which should be a string with the path to the file to read the dsdt from on initrd 13 | - `acpi_trace_op` is a bool that enables tracing of AML opcodes 14 | - `acpi_trace_ns` is a bool that enables tracing of AML namespace 15 | - `acpi_trace_io` is a bool that enables tracing of AML io 16 | 17 | ## CPU Feature control 18 | All of these features are bools 19 | ### Features enabled by default 20 | - `noumip` unconditionally disables initialization of UMIP (User Mode Instruction Prevention) 21 | - `nopcid` will disable pcid, even if it can be enabled 22 | - `noinvpcid` will disable the `invpcid` instruction, note that this will not stop pcid from working without it 23 | - `npsmep` will disable SMEP (Supervisor Mode Execution Prevention) 24 | - `nosmap` will disable SMAP (Supervisor Mode Access Prevention) 25 | - `notme` TME currently is an untested feature, so people are advised to turn it off with this flag, it won't disable it if it has been enabled by BIOS / FW, however it will stop Sigma from enabling it 26 | - `nox2apic` Since Sigma doesn't support Intel VT-d IRQ redirection, it is currently impossible to route IRQs to cpus with an APIC id above 256, if an error pops up about this, pass this option to disable the x2apic 27 | 28 | ### Features disabled by default 29 | - `tsd` will enable the TSD bit in cr4 which disallows the `rdtsc` instruction in userland, this can make speculative exploits harder to pull off, however many applications use this instruction for valid purposes so it is disabled by default -------------------------------------------------------------------------------- /kernel/docs/compiling.md: -------------------------------------------------------------------------------- 1 | # Meson Options 2 | Sigma has a few options that disable or enable features at compile time, these should be passed to the meson configure command 3 | This is not a definitive list, that is `meson_options.txt` 4 | 5 | - `sigma_compile_ubsan` enables UBSan support 6 | 7 | # Internal Defines 8 | Sigma uses a few defines for enabling certain features at compile time, so they don't take up space when they're not used. 9 | 10 | These should not be used manually but only serve as a helpful list of what they do 11 | 12 | - `SIGMA_UBSAN` Compiles in UBSan support -------------------------------------------------------------------------------- /kernel/docs/ideas.txt: -------------------------------------------------------------------------------- 1 | VMM: add callback for page fault on certain address for stack expansion 2 | -------------------------------------------------------------------------------- /kernel/docs/memory_layout.md: -------------------------------------------------------------------------------- 1 | Kernel Physical to Virtual mapping = 0xFFFF800000000000 - 0xFFFFFFFF80000000 2 | Kernel Code / Data = 0xFFFFFFFF80000000 - 0xFFFFFFFFD0000000 3 | Kernel Heap = 0xFFFFFFFFD0000000 - 0xFFFFFFFFFFFFFFFF -------------------------------------------------------------------------------- /kernel/docs/proc/process.cpp.md: -------------------------------------------------------------------------------- 1 | - Thread Privilege levels 2 | - KERNEL 3 | - This is *only* used for kernel threads and not useable for any other threads, it runs in ring 0 and gives *full* hardware access 4 | - DRIVER 5 | - This is the level used for drivers, it runs in ring 3 and gives limited hardware access 6 | - APPLICATION 7 | - This is the level used for normal application, it runs in ring 3 and gives *no* hardware access -------------------------------------------------------------------------------- /kernel/include/Sigma/acpi/acpi.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_ACPI 2 | #define SIGMA_KERNEL_ACPI 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include 19 | 20 | namespace acpi 21 | { 22 | struct table { 23 | acpi::sdt_header header; 24 | uint8_t data[]; 25 | }; 26 | 27 | void init(); 28 | void init_ec(); 29 | void init_sci(acpi::madt& madt); 30 | 31 | acpi::table* get_table(const char* signature); 32 | acpi::table* get_table(const char* signature, uint64_t index); 33 | 34 | uint16_t get_arch_boot_flags(); 35 | } // namespace acpi 36 | 37 | 38 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/acpi/madt.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_ACPI_MADT 2 | #define SIGMA_KERNEL_ACPI_MADT 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace acpi 13 | { 14 | constexpr const char* madt_signature = "APIC"; 15 | 16 | struct PACKED_ATTRIBUTE madt_header 17 | { 18 | acpi::sdt_header header; 19 | uint32_t lapic_addr; 20 | uint32_t flags; 21 | }; // Table of entries next 22 | 23 | constexpr uint8_t flags_pc_at_compatibility = 0; // Has old PIC 24 | 25 | constexpr uint8_t type_lapic = 0; 26 | constexpr uint8_t type_ioapic = 1; 27 | constexpr uint8_t type_interrupt_source_override = 2; 28 | constexpr uint8_t type_nmi_source = 3; 29 | constexpr uint8_t type_lapic_address_override = 5; 30 | constexpr uint8_t type_x2apic = 9; 31 | 32 | struct PACKED_ATTRIBUTE madt_lapic 33 | { 34 | uint8_t type; // 0 35 | uint8_t length; // 8 36 | uint8_t acpi_uid; 37 | uint8_t apic_id; 38 | uint32_t flags; 39 | }; 40 | static_assert(sizeof(madt_lapic) == 8); 41 | 42 | constexpr uint32_t madt_lapic_flags_enabled = 0; 43 | constexpr uint32_t madt_lapic_flags_online_capable = 1; 44 | 45 | struct PACKED_ATTRIBUTE madt_ioapic 46 | { 47 | uint8_t type; // 1 48 | uint8_t length; // 12 49 | uint8_t apic_id; 50 | uint8_t reserved; 51 | uint32_t ioapic_addr; 52 | uint32_t gsi_base; 53 | }; 54 | static_assert(sizeof(madt_ioapic) == 12); 55 | 56 | struct PACKED_ATTRIBUTE madt_gsi_override { 57 | uint8_t type; // 2 58 | uint8_t length; // 10 59 | uint8_t bus; // 0, ISA 60 | uint8_t source; 61 | uint32_t gsi; 62 | uint16_t flags; 63 | }; 64 | static_assert(sizeof(madt_gsi_override) == 10); 65 | 66 | struct PACKED_ATTRIBUTE madt_lapic_override { 67 | uint8_t type; // 5; 68 | uint8_t length; // 12 69 | uint16_t reserved; 70 | uint64_t address; 71 | }; 72 | static_assert(sizeof(madt_lapic_override) == 12); 73 | 74 | struct PACKED_ATTRIBUTE madt_nmi_source{ 75 | uint8_t type; // 8 76 | uint8_t length; // 8; 77 | uint16_t flags; 78 | uint32_t gsi; 79 | }; 80 | static_assert(sizeof(madt_nmi_source) == 8); 81 | 82 | 83 | struct PACKED_ATTRIBUTE madt_x2apic { 84 | uint8_t type; // 9 85 | uint8_t length; // 16 86 | uint16_t reserved; 87 | uint32_t x2apic_id; 88 | uint32_t flags; 89 | uint32_t acpi_uid; 90 | }; 91 | static_assert(sizeof(madt_x2apic) == 16); 92 | 93 | 94 | class madt { 95 | public: 96 | madt(); 97 | 98 | void parse(); 99 | 100 | types::linked_list& get_cpus(); 101 | types::linked_list>& get_ioapics(); 102 | types::linked_list& get_interrupt_overrides(); 103 | uint64_t get_lapic_address(); 104 | bool supports_legacy_pic(){ 105 | return this->legacy_pic; 106 | } 107 | 108 | bool found_table(){ 109 | return this->table != nullptr; 110 | } 111 | 112 | private: 113 | void parse_lapic(uint8_t* item); 114 | void parse_x2apic(uint8_t* item); 115 | void parse_ioapic(uint8_t* item); 116 | void parse_iso(uint8_t* item); 117 | void parse_lapic_address_override(uint8_t* item); 118 | 119 | bool legacy_pic; 120 | uint64_t lapic_addr; 121 | types::linked_list cpus; 122 | types::linked_list> ioapics; 123 | types::linked_list isos; 124 | madt_header* table; 125 | }; 126 | 127 | 128 | } // namespace acpi 129 | 130 | 131 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/acpi/tables.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_ACPI_TABLES 2 | #define SIGMA_KERNEL_ACPI_TABLES 3 | 4 | #include 5 | 6 | namespace acpi 7 | { 8 | struct PACKED_ATTRIBUTE rsdp { 9 | char signature[8]; 10 | uint8_t checksum; 11 | char oem_id[6]; 12 | uint8_t revision; 13 | uint32_t rsdt_address; 14 | }; 15 | 16 | constexpr const char* rsdp_signature = "RSD PTR"; 17 | 18 | struct PACKED_ATTRIBUTE xsdp { 19 | char signature[8]; 20 | uint8_t checksum; 21 | char oem_id[6]; 22 | uint8_t revision; 23 | uint32_t rsdt_address; 24 | uint32_t length; 25 | uint64_t xsdt_address; 26 | uint8_t extended_checksum; 27 | uint8_t reserved[3]; 28 | }; 29 | 30 | struct PACKED_ATTRIBUTE sdt_header 31 | { 32 | char signature[4]; 33 | uint32_t length; 34 | uint8_t revision; 35 | uint8_t checksum; 36 | char oem_id[6]; 37 | char oem_tableid[8]; 38 | uint32_t oem_revision; 39 | uint32_t creator_id; 40 | uint32_t creator_revision; 41 | }; 42 | 43 | struct PACKED_ATTRIBUTE rsdt { 44 | acpi::sdt_header header; 45 | uint32_t tables[]; 46 | }; 47 | 48 | struct PACKED_ATTRIBUTE xsdt { 49 | acpi::sdt_header header; 50 | uint64_t tables[]; 51 | }; 52 | 53 | struct PACKED_ATTRIBUTE generic_address_structure { 54 | uint8_t id; 55 | uint8_t bit_width; 56 | uint8_t bit_offset; 57 | uint8_t access_size; 58 | uint64_t address; 59 | }; 60 | 61 | constexpr uint8_t generic_address_structure_id_system_memory = 0; 62 | constexpr uint8_t generic_address_structure_id_system_io = 1; 63 | constexpr uint8_t generic_address_structure_id_pci_configuration = 2; 64 | constexpr uint8_t generic_address_structure_id_embedded_controller = 3; 65 | constexpr uint8_t generic_address_structure_id_smbus = 4; 66 | constexpr uint8_t generic_address_structure_id_system_cmos = 5; 67 | constexpr uint8_t generic_address_structure_id_pci_bar_target = 6; 68 | constexpr uint8_t generic_address_structure_id_ipmi = 7; 69 | constexpr uint8_t generic_address_structure_id_general_pupose_io = 8; 70 | constexpr uint8_t generic_address_structure_id_generic_serial_bus = 9; 71 | constexpr uint8_t generic_address_structure_id_pcc = 10; 72 | constexpr uint8_t generic_address_structure_id_functional_fixed_hardware = 0x7F; 73 | 74 | constexpr uint8_t generic_address_structure_access_size_undefined = 0; 75 | constexpr uint8_t generic_address_structure_access_size_byte = 1; // 1 byte 76 | constexpr uint8_t generic_address_structure_access_size_word = 2; // 2 bytes 77 | constexpr uint8_t generic_address_structure_access_size_dword = 3; // 4 bytes 78 | constexpr uint8_t generic_address_structure_access_size_qword = 4; // 8 bytes 79 | 80 | constexpr const char* dsdt_signature = "DSDT"; 81 | } // namespace acpi 82 | 83 | 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /kernel/include/Sigma/arch/x86_64/drivers/hpet.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_X86_64_HPET 2 | #define SIGMA_KERNEL_X86_64_HPET 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace x86_64::hpet 11 | { 12 | struct PACKED_ATTRIBUTE table { 13 | acpi::sdt_header header; 14 | uint32_t event_timer_block_id; 15 | acpi::generic_address_structure base_addr_low; 16 | uint8_t hpet_number; 17 | uint16_t main_counter_minimum_periodic_clock_tick; 18 | uint8_t page_protection; 19 | }; 20 | 21 | constexpr const char* hpet_pnp_id = "PNP0103"; 22 | 23 | constexpr uint64_t general_capabilities_and_id_reg = 0x0; 24 | constexpr uint64_t general_configuration_reg = 0x10; 25 | constexpr uint64_t general_interrupt_status_reg = 0x20; 26 | constexpr uint64_t main_counter_reg = 0xF0; 27 | 28 | #define hpet_timer_configuration_and_capabilities_reg(n) (0x100 + (0x20 * (n))) 29 | #define hpet_timer_comparator_value_reg(n) (0x108 + (0x20 * (n))) 30 | #define hpet_timer_fsb_interrupt_routing_reg(n) (0x110 + (0x20 * (n))) 31 | 32 | constexpr uint64_t femto_per_nano = 1000000; 33 | constexpr uint64_t femto_per_micro = femto_per_nano * 1000; 34 | constexpr uint64_t femto_per_milli = femto_per_micro * 1000; 35 | 36 | void init_hpet(); 37 | 38 | void poll_sleep(uint64_t ms); 39 | 40 | enum class hpet_timer_types {ONE_SHOT, PERIODIC}; 41 | 42 | bool create_timer(uint8_t comparator, x86_64::hpet::hpet_timer_types type, uint8_t vector, uint64_t ms); 43 | } // namespace x86_64::hpet 44 | 45 | 46 | 47 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/arch/x86_64/drivers/pic.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_PIC 2 | #define SIGMA_KERNEL_PIC 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace x86_64::pic 9 | { 10 | constexpr uint8_t pic1_cmd_port = 0x20; 11 | constexpr uint8_t pic1_data_port = 0x21; 12 | constexpr uint8_t pic2_cmd_port = 0xA0; 13 | constexpr uint8_t pic2_data_port = 0xA1; 14 | 15 | constexpr uint8_t eoi_cmd = 0x20; 16 | 17 | constexpr uint8_t read_irr = 0xa; 18 | constexpr uint8_t read_isr = 0xb; 19 | 20 | constexpr uint8_t icw1_icw4 = 0x1; 21 | constexpr uint8_t icw1_single = 0x2; 22 | constexpr uint8_t icw1_interval4 = 0x4; 23 | constexpr uint8_t icw1_level = 0x8; 24 | constexpr uint8_t icw1_init = 0x10; 25 | 26 | 27 | constexpr uint8_t icw4_8086 = 0x1; 28 | constexpr uint8_t icw4_auto = 0x2; 29 | constexpr uint8_t icw4_buf_slave = 0x8; 30 | constexpr uint8_t icw4_buf_master = 0xC; 31 | constexpr uint8_t icw1_sfnm = 0x10; 32 | 33 | constexpr uint8_t bios_default_pic1_vector = 0x8; 34 | constexpr uint8_t bios_default_pic2_vector = 0x70; 35 | 36 | 37 | void set_base_vector(uint8_t base); 38 | 39 | void remap(uint8_t pic1_base, uint8_t pic2_base); 40 | 41 | void disable(); 42 | 43 | void enable(); 44 | 45 | void send_eoi(); 46 | 47 | } // x86_64::pic 48 | 49 | 50 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/arch/x86_64/drivers/serial.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_SERIAL 2 | #define SIGMA_KERNEL_SERIAL 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace x86_64::serial 10 | { 11 | constexpr uint16_t com1_base = 0x3F8; 12 | constexpr uint16_t com2_base = 0x2F8; 13 | 14 | constexpr uint8_t interrupt_enable = 1; 15 | 16 | constexpr uint8_t line_control = 3; 17 | 18 | constexpr uint8_t modem_control = 4; 19 | constexpr uint8_t line_status = 5; 20 | 21 | constexpr uint8_t line_control_dlab = 7; 22 | 23 | 24 | class writer { 25 | public: 26 | explicit writer(uint16_t base): base(base), mutex(x86_64::spinlock::mutex()){ 27 | x86_64::io::outb(this->base + x86_64::serial::line_control, 0x03); // Configure port 28 | x86_64::io::outb(this->base + x86_64::serial::interrupt_enable, 0); // Disable interrupts 29 | 30 | this->configure_baud_rate(3); 31 | } 32 | 33 | void print_char(const char c){ 34 | while((x86_64::io::inb(this->base + x86_64::serial::line_status) & 0x20) == 0); 35 | x86_64::io::outb(this->base, c); 36 | } 37 | 38 | char get_char(){ 39 | while((x86_64::io::inb(this->base + x86_64::serial::line_status) & 0x1) == 0); 40 | return x86_64::io::inb(this->base); 41 | } 42 | 43 | 44 | void nprint(const char* str, size_t n){ 45 | std::lock_guard guard{this->mutex}; 46 | 47 | for(size_t i = 0; i < n; i++){ 48 | uint8_t c = str[i]; 49 | 50 | this->print_char(c); 51 | } 52 | } 53 | 54 | 55 | private: 56 | 57 | void configure_baud_rate(uint16_t divisor){ 58 | uint8_t cmd = x86_64::io::inb(this->base + x86_64::serial::line_control); 59 | bitops::bit_set(cmd, x86_64::serial::line_control_dlab); 60 | x86_64::io::outb(this->base + x86_64::serial::line_control, cmd); 61 | 62 | x86_64::io::outb(this->base, (divisor >> 8) & 0xFF); 63 | x86_64::io::outb(this->base, divisor & 0xFF); 64 | 65 | cmd = x86_64::io::inb(this->base + x86_64::serial::line_control); 66 | bitops::bit_clear(cmd, x86_64::serial::line_control_dlab); 67 | x86_64::io::outb(this->base + x86_64::serial::line_control, cmd); 68 | } 69 | uint16_t base; 70 | x86_64::spinlock::mutex mutex; 71 | }; 72 | } // x86_64::serial 73 | 74 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/arch/x86_64/drivers/vga.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_ARCH_X86_64_VGA 2 | #define SIGMA_ARCH_X86_64_VGA 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | namespace x86_64::vga 15 | { 16 | enum class text_colour : uint8_t {black = 0, blue = 1, green = 2, cyan = 3, red = 4, magenta = 5, brown = 7, light_gray = 7, dark_gray = 8, light_blue = 9, light_green = 10, light_cyan = 11, light_red = 12, pink = 13, yellow = 14, white = 15}; 17 | 18 | struct PACKED_ATTRIBUTE text_entry_t 19 | { 20 | text_entry_t(uint8_t ascii, text_colour foreground, text_colour background): ascii(ascii), \ 21 | colour((misc::as_integer(background) << 4) | misc::as_integer(foreground)) { } 22 | uint8_t ascii; 23 | uint8_t colour; 24 | }; 25 | 26 | constexpr uint64_t mmio = (0xb8000 + KERNEL_VBASE); 27 | 28 | constexpr uint8_t terminal_width = 80; 29 | constexpr uint8_t terminal_height = 25; 30 | 31 | constexpr uint16_t vga_hardware_cursor_command_port = 0x3D4; 32 | constexpr uint16_t vga_hardware_cursor_data_port = 0x3D5; 33 | 34 | void write_entry(text_entry_t character, uint8_t x, uint8_t y); 35 | 36 | class writer { 37 | public: 38 | writer(): x(0), y(0), foreground(vga::text_colour::white), background(vga::text_colour::black), \ 39 | mutex(x86_64::spinlock::mutex()) { } 40 | 41 | void print(const char* str); 42 | void print(const char* str, size_t n); 43 | void print_char(const char c); 44 | 45 | void set_foreground(vga::text_colour colour); 46 | void set_background(vga::text_colour colour); 47 | 48 | void set_cursor(uint8_t x, uint8_t y); 49 | 50 | void set_cursor_to_hw(); 51 | 52 | int8_t x, y; 53 | vga::text_colour foreground, background; 54 | 55 | private: 56 | x86_64::spinlock::mutex mutex; 57 | 58 | void scroll(); 59 | 60 | void enable_hardware_cursor(); 61 | std::pair get_hardware_cursor(); 62 | void disable_hardware_cursor(); 63 | void update_hardware_cursor(); 64 | }; 65 | } // x86_64::vga 66 | 67 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/arch/x86_64/gdt.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_ARCH_X86_64_GDT 2 | #define SIGMA_ARCH_X86_64_GDT 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | namespace x86_64::gdt 12 | { 13 | struct PACKED_ATTRIBUTE entry { 14 | explicit entry(uint64_t ent): ent(ent) {} 15 | entry() = default; 16 | 17 | uint64_t ent; 18 | }; 19 | 20 | struct PACKED_ATTRIBUTE pointer { 21 | void update_gdtr(){ 22 | asm("lgdt %0" : : "m"(*this) : "memory"); 23 | } 24 | uint16_t size; 25 | uint64_t pointer; 26 | }; 27 | 28 | 29 | 30 | constexpr uint64_t entry_read_write_bit = (1ULL << 41); 31 | constexpr uint64_t entry_conforming_bit = (1ULL << 42); 32 | constexpr uint64_t entry_executable_bit = (1ULL << 43); 33 | constexpr uint64_t entry_descriptor_type_bit = (1ULL << 44); 34 | constexpr uint64_t entry_privilege = (1ULL << 45); 35 | constexpr uint64_t entry_present_bit = (1ULL << 47); 36 | constexpr uint64_t entry_64bit_code_bit = (1ULL << 53); 37 | constexpr uint64_t entry_32bit_bit = (1ULL << 54); 38 | 39 | constexpr uint64_t max_entries = 10; // Maximum usable GDT entries 40 | 41 | constexpr uint64_t hardware_max_entries = 255; 42 | 43 | static_assert(max_entries < hardware_max_entries); 44 | 45 | class gdt { 46 | public: 47 | gdt(); 48 | 49 | void init(); 50 | 51 | uint64_t add_entry(uint64_t flags); 52 | uint64_t add_tss(x86_64::tss::table& tss); 53 | uint64_t get_offset_by_index(uint64_t index); 54 | x86_64::gdt::entry& get_entry_by_offset(uint64_t offset){ 55 | return entries[offset / 8]; 56 | } 57 | 58 | void update_pointer(){ 59 | this->pointer.update_gdtr(); 60 | } 61 | private: 62 | x86_64::gdt::entry entries[x86_64::gdt::max_entries]; 63 | x86_64::gdt::pointer pointer; 64 | uint64_t entry_index; 65 | 66 | }; 67 | 68 | constexpr uint16_t kernel_data_selector = 0x0; 69 | constexpr uint16_t kernel_code_selector = 0x08; // Manually update this 70 | 71 | constexpr uint16_t user_data_selector = 0x18; 72 | constexpr uint16_t user_code_selector = 0x10; // Manually update this 73 | } // x86_64::gdt 74 | 75 | 76 | 77 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/arch/x86_64/idt.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_IDT 2 | #define SIGMA_KERNEL_IDT 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | 13 | namespace x86_64::idt 14 | { 15 | constexpr uint8_t idt_entry_options_ist_index = 0; 16 | constexpr uint8_t idt_entry_options_gate = 8; 17 | constexpr uint8_t idt_entry_options_dpl = 13; 18 | constexpr uint8_t idt_entry_option_present = 15; 19 | 20 | 21 | class PACKED_ATTRIBUTE idt_entry { 22 | public: 23 | idt_entry() = default; 24 | idt_entry(void* function, uint16_t selector, bool present, uint8_t ist_number); 25 | idt_entry(void* function, uint16_t selector, bool present, uint8_t ist_number, uint8_t dpl); 26 | uint16_t pointer_low; 27 | uint16_t gdt_sel; 28 | uint16_t options; 29 | uint16_t pointer_mid; 30 | uint32_t pointer_high; 31 | uint32_t reserved; 32 | }; 33 | 34 | 35 | 36 | constexpr uint16_t idt_max_entries = 256; 37 | 38 | struct PACKED_ATTRIBUTE idt_table { 39 | public: 40 | idt_table(){ 41 | for(auto& e : entries){ 42 | e = x86_64::idt::idt_entry(nullptr, x86_64::gdt::kernel_code_selector, false, 0); 43 | } 44 | } 45 | 46 | void set_entry(uint16_t n, void* function, uint16_t selector, uint8_t ist_index){ 47 | this->entries[n] = x86_64::idt::idt_entry(function, selector, true, ist_index); 48 | } 49 | 50 | void set_entry(uint16_t n, void* function, uint16_t selector, uint8_t ist_index, uint8_t dpl){ 51 | this->entries[n] = x86_64::idt::idt_entry(function, selector, true, ist_index, dpl); 52 | } 53 | 54 | idt_entry entries[idt_max_entries]; 55 | }; 56 | 57 | struct PACKED_ATTRIBUTE idt_pointer { 58 | void store(){ 59 | asm("lidt %0" : : "m"(*this) : "memory"); 60 | } 61 | volatile uint16_t size; 62 | volatile uint64_t base; 63 | }; 64 | 65 | struct PACKED_ATTRIBUTE idt_registers { 66 | uint64_t ds; 67 | uint64_t r15, r14, r13, r12, r11, r10, r9, r8, rdi, rsi, rbp, useless, rbx, rdx, rcx, rax; 68 | uint64_t int_number, error_code; 69 | uint64_t rip, cs, rflags, rsp, ss; 70 | }; 71 | 72 | constexpr uint8_t normal_ist_index = 0; 73 | constexpr uint8_t double_fault_ist_index = 1; 74 | constexpr uint8_t page_fault_ist_index = 2; 75 | constexpr uint8_t nmi_ist_index = 3; 76 | constexpr uint8_t preemption_ist_index = 4; 77 | 78 | uint8_t get_free_vector(); 79 | 80 | struct handler { 81 | using idt_function = void (*)(idt_registers*, void*); 82 | uint16_t vector; 83 | idt_function callback; 84 | void* userptr = nullptr; 85 | bool is_irq = false, should_iret = false; 86 | }; 87 | 88 | void init(); 89 | void load(); 90 | void register_interrupt_handler(handler h); 91 | void register_irq_status(uint16_t n, bool is_irq); 92 | void register_generic_handlers(); 93 | } // x86_64::idt 94 | 95 | 96 | #endif // !SIGMA_KERNEL_IDT 97 | -------------------------------------------------------------------------------- /kernel/include/Sigma/arch/x86_64/intel/sl_paging.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_ARCH_X86_64_SL_PAGING_H 2 | #define SIGMA_ARCH_X86_64_SL_PAGING_H 3 | 4 | #include 5 | 6 | namespace x86_64::sl_paging 7 | { 8 | union PACKED_ATTRIBUTE sl_pmle { 9 | struct { 10 | uint64_t r : 1; 11 | uint64_t w : 1; 12 | uint64_t x : 1; 13 | 14 | uint64_t reserved : 5; 15 | uint64_t accessed : 1; 16 | uint64_t reserved_0 : 3; 17 | uint64_t addr : 40; 18 | uint64_t reserved_1 : 12; 19 | }; 20 | uint64_t raw; 21 | }; 22 | static_assert(sizeof(sl_pmle) == 8); 23 | 24 | struct PACKED_ATTRIBUTE sl_pml { 25 | sl_pmle entries[512]; 26 | 27 | sl_pmle& operator[](int i){ 28 | return entries[i]; 29 | } 30 | }; 31 | static_assert(sizeof(sl_pml) == 0x1000); 32 | 33 | union PACKED_ATTRIBUTE sl_pml1e { 34 | struct { 35 | uint64_t r : 1; 36 | uint64_t w : 1; 37 | uint64_t x : 1; 38 | 39 | uint64_t extended_mem_type : 3; 40 | uint64_t ignore_pat : 1; 41 | uint64_t reserved : 1; 42 | uint64_t accessed : 1; 43 | uint64_t dirty : 1; 44 | uint64_t reserved_0 : 1; 45 | uint64_t snoop : 1; 46 | uint64_t frame : 40; 47 | uint64_t reserved_1 : 10; 48 | uint64_t transient_mapping : 1; 49 | uint64_t reserved_2 : 1; 50 | }; 51 | uint64_t raw; 52 | }; 53 | 54 | static_assert(sizeof(sl_pml1e) == 8); 55 | 56 | struct PACKED_ATTRIBUTE sl_pml1 { 57 | sl_pml1e entries[512]; 58 | 59 | sl_pml1e& operator[](int i){ 60 | return entries[i]; 61 | } 62 | }; 63 | static_assert(sizeof(sl_pml1) == 0x1000); 64 | 65 | enum { 66 | mapSlPageRead = (1 << 0), 67 | mapSlPageWrite = (1 << 1), 68 | mapSlPageExecute = (1 << 2), 69 | }; 70 | 71 | class context { 72 | public: 73 | context(uint8_t level); 74 | ~context(); 75 | 76 | void map(uint64_t pa, uint64_t iova, uint64_t flags); 77 | 78 | uint64_t get_ptr(); 79 | 80 | private: 81 | uint8_t level; 82 | uint64_t phys_root; 83 | }; 84 | } // namespace x86_64::sl_paging 85 | 86 | 87 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/arch/x86_64/io.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_ARCH_X86_64_IO 2 | #define SIGMA_ARCH_X86_64_IO 3 | 4 | #include 5 | 6 | namespace x86_64::io 7 | { 8 | uint8_t inb(uint16_t port); 9 | void outb(uint16_t port, uint8_t value); 10 | 11 | uint16_t inw(uint16_t port); 12 | void outw(uint16_t port, uint16_t value); 13 | 14 | uint32_t ind(uint16_t port); 15 | void outd(uint16_t port, uint32_t value); 16 | } // x86_64::io 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /kernel/include/Sigma/arch/x86_64/misc/misc.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_ARCH_X86_64_CPUID 2 | #define SIGMA_ARCH_X86_64_CPUID 3 | 4 | #include 5 | #include 6 | 7 | namespace x86_64 8 | { 9 | bool cpuid(uint32_t leaf, uint32_t& eax, uint32_t& ebx, uint32_t& ecx, uint32_t& edx); 10 | bool cpuid(uint32_t leaf, uint32_t subleaf, uint32_t& eax, uint32_t& ebx, uint32_t& ecx, uint32_t& edx); 11 | uint64_t read_tsc(); 12 | 13 | C_LINKAGE uint64_t read_xcr(uint32_t xcr); 14 | C_LINKAGE void write_xcr(uint32_t xcr, uint64_t value); 15 | } // namespace x86_64 16 | 17 | 18 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/arch/x86_64/misc/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_SPINLOCK 2 | #define SIGMA_KERNEL_SPINLOCK 3 | 4 | #include 5 | 6 | namespace x86_64::spinlock { 7 | C_LINKAGE void acquire(uint16_t* lock); 8 | C_LINKAGE void release(uint16_t* lock); 9 | C_LINKAGE bool try_acquire(uint16_t* lock); 10 | 11 | struct mutex { 12 | constexpr mutex() noexcept : _lock(0) {} 13 | 14 | void lock(){ 15 | x86_64::spinlock::acquire(&this->_lock); 16 | } 17 | 18 | void unlock(){ 19 | x86_64::spinlock::release(&this->_lock); 20 | } 21 | 22 | bool try_lock(){ 23 | return x86_64::spinlock::try_acquire(&this->_lock); 24 | } 25 | 26 | private: 27 | uint16_t _lock; 28 | }; 29 | 30 | struct irq_lock { 31 | constexpr irq_lock() noexcept: _count{0} {} 32 | 33 | irq_lock(const irq_lock &) = delete; 34 | irq_lock &operator= (const irq_lock &) = delete; 35 | 36 | void lock(MAYBE_UNUSED_ATTRIBUTE KLIBCXX_NAMESPACE_NAME::experimental::source_location src = KLIBCXX_NAMESPACE_NAME::experimental::source_location::current()){ 37 | auto c = _count.load(std::memory_order_acquire); 38 | if(c == 0){ 39 | uint64_t rflags = 0; 40 | asm("pushf; pop %0" : "=r"(rflags)); 41 | 42 | if(rflags & (1 << 9)){ 43 | asm volatile("cli" : : : "memory"); 44 | _count.store(old_irq_flag | 1, std::memory_order_relaxed); 45 | } else { 46 | _count.store(1, std::memory_order_relaxed); 47 | } 48 | } else { 49 | ASSERT(c & ~old_irq_flag); 50 | _count.store(c + 1, std::memory_order_release); 51 | } 52 | } 53 | 54 | void unlock(){ 55 | auto c = _count.load(std::memory_order_relaxed); 56 | ASSERT(c & ~old_irq_flag); 57 | if((c & ~old_irq_flag) == 1){ 58 | _count.store(0, std::memory_order_release); 59 | if(c & old_irq_flag) 60 | asm volatile ("sti" : : : "memory"); 61 | } else { 62 | _count.store(c - 1, std::memory_order_release); 63 | } 64 | } 65 | 66 | private: 67 | std::atomic _count; 68 | 69 | constexpr static uint64_t old_irq_flag = (1ull << 63); 70 | }; 71 | } 72 | 73 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/arch/x86_64/msr.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_X86_64_MSR 2 | #define SIGMA_KERNEL_X86_64_MSR 3 | 4 | #include 5 | 6 | namespace x86_64::msr 7 | { 8 | constexpr uint32_t ia32_pat = 0x277; 9 | constexpr uint32_t ia32_tme_capability = 0x981; 10 | constexpr uint32_t ia32_tme_activate = 0x982; 11 | constexpr uint32_t ia32_tme_exclude_mask = 0x983; 12 | constexpr uint32_t ia32_tme_exclude_base = 0x984; 13 | constexpr uint32_t ia32_efer = 0xC0000080; 14 | constexpr uint32_t apic_base = 0x0000001b; 15 | constexpr uint32_t fs_base = 0xC0000100; 16 | constexpr uint32_t gs_base = 0xC0000101; 17 | constexpr uint32_t kernelgs_base = 0xC0000102; 18 | 19 | uint64_t read(uint32_t msr); 20 | void write(uint32_t msr, uint64_t val); 21 | } // x86_64::msr 22 | 23 | 24 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/arch/x86_64/tss.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_TSS 2 | #define SIGMA_KERNEL_TSS 3 | 4 | #include 5 | #include 6 | 7 | namespace x86_64::tss 8 | { 9 | constexpr uint8_t ist_n_entries = 7; 10 | 11 | struct PACKED_ATTRIBUTE table { 12 | public: 13 | void init(){ 14 | //TODO: only allocate needed stacks 15 | this->ist_stack1 = ((uintptr_t)mm::pmm::alloc_block() + mm::pmm::block_size + KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE); 16 | this->ist_stack2 = ((uintptr_t)mm::pmm::alloc_block() + mm::pmm::block_size + KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE); 17 | this->ist_stack3 = ((uintptr_t)mm::pmm::alloc_block() + mm::pmm::block_size + KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE); 18 | this->ist_stack4 = ((uintptr_t)mm::pmm::alloc_block() + mm::pmm::block_size + KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE); 19 | this->ist_stack5 = ((uintptr_t)mm::pmm::alloc_block() + mm::pmm::block_size + KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE); 20 | this->ist_stack6 = ((uintptr_t)mm::pmm::alloc_block() + mm::pmm::block_size + KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE); 21 | this->ist_stack7 = ((uintptr_t)mm::pmm::alloc_block() + mm::pmm::block_size + KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE); 22 | 23 | this->reserved = 0; 24 | this->reserved_1 = 0; 25 | this->reserved_2 = 0; 26 | this->reserved_3 = 0; 27 | this->reserved_4 = 0; 28 | 29 | this->rsp0 = 0; 30 | this->rsp1 = 0; 31 | this->rsp2 = 0; 32 | 33 | this->io_bitmap_offset = 0; 34 | } 35 | 36 | void deinit(){ 37 | mm::pmm::free_block(reinterpret_cast(this->ist_stack1 - mm::pmm::block_size - KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE)); 38 | mm::pmm::free_block(reinterpret_cast(this->ist_stack2 - mm::pmm::block_size - KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE)); 39 | mm::pmm::free_block(reinterpret_cast(this->ist_stack3 - mm::pmm::block_size - KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE)); 40 | mm::pmm::free_block(reinterpret_cast(this->ist_stack4 - mm::pmm::block_size - KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE)); 41 | mm::pmm::free_block(reinterpret_cast(this->ist_stack5 - mm::pmm::block_size - KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE)); 42 | mm::pmm::free_block(reinterpret_cast(this->ist_stack6 - mm::pmm::block_size - KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE)); 43 | mm::pmm::free_block(reinterpret_cast(this->ist_stack7 - mm::pmm::block_size - KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE)); 44 | } 45 | 46 | void load(uint16_t gdt_offset){ 47 | asm volatile("ltr %0" : : "r"(gdt_offset) : "memory"); 48 | } 49 | 50 | 51 | uint32_t reserved; 52 | uint64_t rsp0; 53 | uint64_t rsp1; 54 | uint64_t rsp2; 55 | 56 | 57 | uint32_t reserved_1; 58 | uint32_t reserved_2; 59 | 60 | uint64_t ist_stack1; 61 | uint64_t ist_stack2; 62 | uint64_t ist_stack3; 63 | uint64_t ist_stack4; 64 | uint64_t ist_stack5; 65 | uint64_t ist_stack6; 66 | uint64_t ist_stack7; 67 | 68 | uint64_t reserved_3; 69 | uint16_t reserved_4; 70 | uint16_t io_bitmap_offset; 71 | }; 72 | } // x86_64::tss 73 | 74 | 75 | 76 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/boot_protocol.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_BOOT_PROTOCOL 2 | #define SIGMA_KERNEL_BOOT_PROTOCOL 3 | 4 | #include 5 | 6 | namespace boot 7 | { 8 | struct boot_protocol { 9 | uint64_t acpi_pointer; 10 | uint64_t memsize; 11 | uint64_t mmap; 12 | uint64_t reserve_start; // Area to reserve 13 | uint64_t reserve_length; // Area to reserve 14 | uint64_t kernel_elf_sections; 15 | uint64_t kernel_n_elf_sections; 16 | uint64_t kernel_initrd_ptr; 17 | uint64_t kernel_initrd_size; 18 | char* cmdline; 19 | }; 20 | } // namespace loader 21 | 22 | 23 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/common.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_COMMON 2 | #define SIGMA_KERNEL_COMMON 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using std::uint8_t; 10 | using std::uint16_t; 11 | using std::uint32_t; 12 | using std::uint64_t; 13 | 14 | using std::int8_t; 15 | using std::int16_t; 16 | using std::int32_t; 17 | using std::int64_t; 18 | 19 | using std::uintptr_t; 20 | using std::size_t; 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | 27 | 28 | #define PANIC(message) do { misc::panic::panic_m(message, SIGMA_FUNCTION_NAME, std::experimental::source_location::current()); } while(0); 29 | 30 | #define ASSERT(condition) do { \ 31 | if(!(condition)){ \ 32 | PANIC("Assertion Failed, condition: " #condition); \ 33 | } \ 34 | } while(0); 35 | 36 | #include 37 | 38 | 39 | // Things to log debug 40 | #define DEBUG 41 | //#define LOG_SYSCALLS 42 | 43 | 44 | // General defines 45 | #define KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE 0xffff800000000000 46 | #define KERNEL_VBASE 0xffffffff80000000 47 | #define KERNEL_PBASE 0x0000000000100000 48 | 49 | #define C_LINKAGE extern "C" 50 | 51 | #define FUNCTION_CALL_ONCE() do { \ 52 | static bool called = false; \ 53 | if(!called) called = true; \ 54 | else PANIC("Tried to reenter call-once function"); \ 55 | } while(0); 56 | 57 | 58 | #define ARCH_X86_64 // TODO: Actually separate archs 59 | //#define ARCH_ARM 60 | 61 | #define ALIGN_DOWN(n, a) (((uint64_t)n) & ~((a) - 1ul)) 62 | #define ALIGN_UP(n, a) ALIGN_DOWN(((uint64_t)n) + (a) - 1ul, (a)) 63 | 64 | using tid_t = uint64_t; 65 | 66 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/config.h.in: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_CONFIG 2 | #define SIGMA_CONFIG 3 | 4 | #define VERSION_STR "@version@" 5 | 6 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/generic/device.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_GENERIC_DEVICE_H 2 | #define SIGMA_GENERIC_DEVICE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace generic::device { 11 | struct device { 12 | const char* name; 13 | misc::uuid id; 14 | 15 | struct { 16 | uint64_t acpi : 1; 17 | uint64_t pci : 1; 18 | } contact; 19 | 20 | struct { 21 | lai_nsnode_t* node; 22 | lai_api_error_t eval(lai_variable_t& var){ 23 | LAI_CLEANUP_STATE lai_state_t state; 24 | lai_init_state(&state); 25 | return lai_eval(&var, node, &state); 26 | } 27 | } acpi_contact; 28 | 29 | struct { 30 | x86_64::pci::device* device; 31 | } pci_contact; 32 | 33 | struct resource_region { 34 | enum { 35 | typeMmio = 0, 36 | typeIo, 37 | 38 | typeInvalid = -1 39 | }; 40 | 41 | enum { 42 | originPciBar, 43 | }; 44 | uint8_t type; 45 | uint64_t origin; 46 | uint64_t base; 47 | uint64_t len; 48 | }; 49 | 50 | size_t index; 51 | tid_t driver; 52 | 53 | 54 | void add_acpi_node(lai_nsnode_t* node){ 55 | contact.acpi = 1; 56 | acpi_contact.node = node; 57 | } 58 | 59 | void add_pci_device(x86_64::pci::device* device){ 60 | contact.pci = 1; 61 | pci_contact.device = device; 62 | } 63 | }; 64 | 65 | using device_descriptor = uint64_t; 66 | 67 | types::vector& get_device_list(); 68 | void init(); 69 | void print_list(); 70 | void add_pci_device(x86_64::pci::device* dev); 71 | 72 | constexpr uint64_t devctl_cmd_nop = 0; 73 | constexpr uint64_t devctl_cmd_claim = 1; 74 | constexpr uint64_t devctl_cmd_find_pci = 2; 75 | constexpr uint64_t devctl_cmd_find_pci_class = 3; 76 | constexpr uint64_t devctl_cmd_get_resource_region = 4; 77 | constexpr uint64_t devctl_cmd_enable_irq = 5; 78 | constexpr uint64_t devctl_cmd_wait_on_irq = 6; 79 | constexpr uint64_t devctl_cmd_read_pci = 7; 80 | constexpr uint64_t devctl_cmd_write_pci = 8; 81 | 82 | uint64_t devctl(uint64_t cmd, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, x86_64::idt::idt_registers* regs); 83 | } 84 | 85 | 86 | 87 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/generic/event.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_GENERIC_EVENT_H 2 | #define SIGMA_GENERIC_EVENT_H 3 | 4 | #include 5 | #include 6 | 7 | namespace generic 8 | { 9 | class event { 10 | public: 11 | event(): count{0} {} 12 | 13 | void trigger(){ 14 | count.fetch_add(1); 15 | } 16 | 17 | void untrigger(){ 18 | if(count) 19 | count.fetch_sub(1); 20 | } 21 | 22 | bool has_triggered(){ 23 | uint64_t val = 0; 24 | if(count.compare_exchange_strong(val, 0)) 25 | return false; 26 | 27 | count.fetch_sub(1); 28 | return true; 29 | } 30 | 31 | private: 32 | std::atomic count; 33 | }; 34 | } // namespace generic 35 | 36 | 37 | 38 | 39 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/generic/user_handle.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_GENERIC_USER_HANDLE_H 2 | #define SIGMA_GENERIC_USER_HANDLE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | 13 | namespace generic::handles 14 | { 15 | enum class handle_type {vCpu, vSpace, irq, ipcRing}; 16 | 17 | struct handle { 18 | explicit handle(handle_type type): type{type} {} 19 | handle_type type; 20 | 21 | virtual ~handle() {} 22 | }; 23 | 24 | struct vcpu_handle : public handle { 25 | explicit vcpu_handle(generic::virt::vspace* space): handle{handle_type::vCpu}, cpu{space} {} 26 | 27 | static constexpr handle_type default_type = handle_type::vCpu; 28 | 29 | generic::virt::vcpu cpu; 30 | }; 31 | 32 | struct vspace_handle : public handle { 33 | explicit vspace_handle(): handle{handle_type::vSpace}, space{} {} 34 | 35 | static constexpr handle_type default_type = handle_type::vSpace; 36 | 37 | generic::virt::vspace space; 38 | }; 39 | 40 | struct irq_handle : public handle { 41 | explicit irq_handle(uint8_t vector): handle{handle_type::irq}, vector{vector}, event{} {} 42 | 43 | static constexpr handle_type default_type = handle_type::irq; 44 | 45 | uint8_t vector; 46 | generic::event event; 47 | }; 48 | 49 | struct ipc_ring_handle : public handle { 50 | explicit ipc_ring_handle(proc::ipc::ring* ring): handle{handle_type::ipcRing}, ring{ring} {} 51 | 52 | static constexpr handle_type default_type = handle_type::ipcRing; 53 | 54 | proc::ipc::ring* ring; 55 | }; 56 | 57 | class handle_catalogue { 58 | public: 59 | handle_catalogue& operator=(handle_catalogue&& other){ 60 | this->id_gen = std::move(other.id_gen); 61 | this->catalogue = std::move(other.catalogue); 62 | 63 | return *this; 64 | } 65 | 66 | NODISCARD_ATTRIBUTE 67 | uint64_t push(handles::handle* handle){ 68 | auto id = id_gen.id(); 69 | catalogue.push_back(id, handle); 70 | 71 | return id; 72 | } 73 | 74 | template 75 | T* get(uint64_t id){ 76 | auto* handle = catalogue[id]; 77 | if(!handle) 78 | return nullptr; 79 | 80 | ASSERT(handle->type == T::default_type); 81 | return static_cast(handle); 82 | } 83 | 84 | private: 85 | misc::id_generator id_gen; 86 | types::hash_map> catalogue; 87 | }; 88 | } // namespace handles 89 | 90 | 91 | 92 | 93 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/generic/virt.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_GENERIC_VIRT_H 2 | #define SIGMA_GENERIC_VIRT_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace generic::virt { 11 | enum { 12 | vCtlExitReasonHlt = 0, 13 | vCtlExitReasonRdtsc, 14 | vCtlExitReasonPortRead, 15 | vCtlExitReasonPortWrite, 16 | vCtlExitReasonMsrRead, 17 | vCtlExitReasonMsrWrite, 18 | vCtlExitReasonSRegRead, 19 | vCtlExitReasonSRegWrite, 20 | vCtlExitReasonNestedPageFault, 21 | vCtlExitReasonHypercall, 22 | vCtlExitReasonInterrupt, 23 | 24 | vCtlExitReasonInvalidInternalState = -1 25 | }; 26 | 27 | enum { 28 | vCtlExitRegNumberCr0, 29 | vCtlExitRegNumberCr1, 30 | vCtlExitRegNumberCr2, 31 | vCtlExitRegNumberCr3, 32 | vCtlExitRegNumberCr4, 33 | vCtlExitRegNumberCr5, 34 | vCtlExitRegNumberCr6, 35 | vCtlExitRegNumberCr7, 36 | vCtlExitRegNumberCr8, 37 | vCtlExitRegNumberCr9, 38 | vCtlExitRegNumberCr10, 39 | vCtlExitRegNumberCr11, 40 | vCtlExitRegNumberCr12, 41 | vCtlExitRegNumberCr13, 42 | vCtlExitRegNumberCr14, 43 | vCtlExitRegNumberCr15, 44 | vCtlExitRegNumberGdtr, 45 | vCtlExitRegNumberIdtr, 46 | vCtlExitRegNumberLdtr, 47 | vCtlExitRegNumberTr, 48 | }; 49 | 50 | struct vexit { 51 | uint64_t reason; 52 | uint8_t opcode[15]; 53 | uint8_t opcode_length; 54 | 55 | uint8_t interrupt_number; 56 | 57 | union { 58 | struct { 59 | uint16_t port; 60 | uint8_t width; 61 | bool repeated; 62 | bool string; 63 | } port; 64 | struct { 65 | uint32_t number; 66 | uint64_t value; 67 | } msr; 68 | struct { 69 | uint8_t reg_number; 70 | uint64_t value; 71 | } sreg; 72 | struct { 73 | uint64_t phys_addr; 74 | uint64_t value; 75 | uint8_t len; 76 | bool write; 77 | } npf; 78 | }; 79 | }; 80 | 81 | struct vregs { 82 | uint64_t rax, rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15; 83 | uint64_t rsp, rbp, rip, rflags; 84 | 85 | uint64_t cr0, cr2, cr3, cr4, cr8; 86 | uint64_t efer; 87 | 88 | struct selector { 89 | uint16_t selector; 90 | uint16_t attrib; 91 | uint32_t limit; 92 | uint64_t base; 93 | }; 94 | 95 | struct dtable { 96 | uint64_t base; 97 | uint16_t limit; 98 | }; 99 | 100 | selector cs, ds, ss, es, fs, gs; 101 | selector ldtr, tr; 102 | dtable gdtr, idtr; 103 | }; 104 | 105 | enum { 106 | vCtlCreateVcpu = 0, 107 | vCtlRunVcpu, 108 | vCtlGetRegs, 109 | vCtlSetRegs, 110 | vCtlCreateVspace, 111 | vCtlMapVspace, 112 | vCtlMapVspacePhys 113 | }; 114 | 115 | uint64_t vctl(uint64_t cmd, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4); 116 | 117 | 118 | enum class virt_types {Svm, None}; 119 | struct vspace { 120 | vspace(); 121 | ~vspace(); 122 | 123 | void map(uint64_t guest_phys, uint64_t host_phys); 124 | 125 | virt_types type; 126 | void* ptr; 127 | }; 128 | 129 | struct vcpu { 130 | vcpu(vspace* space); 131 | ~vcpu(); 132 | 133 | void run(generic::virt::vexit* vexit); 134 | void get_regs(vregs* regs); 135 | void set_regs(vregs* regs); 136 | 137 | virt_types type; 138 | void* ptr; 139 | }; 140 | } 141 | 142 | #endif 143 | -------------------------------------------------------------------------------- /kernel/include/Sigma/misc/bitops.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_BITOPS 2 | #define SIGMA_KERNEL_BITOPS 3 | 4 | #include 5 | 6 | template 7 | class bitops { 8 | public: 9 | static constexpr bool bit_set(T* item, uint64_t bit){ 10 | T set = *item & (1ULL << bit); 11 | *item |= (1ULL << bit); 12 | return !(set == 0); 13 | } 14 | 15 | static constexpr bool bit_clear(T* item, uint64_t bit){ 16 | T set = *item & (1ULL << bit); 17 | *item &= ~(1ULL << bit); 18 | return !(set == 0); 19 | } 20 | 21 | static constexpr bool bit_test(T* item, uint64_t bit){ 22 | T set = *item & (1ULL << bit); 23 | return !(set == 0); 24 | } 25 | 26 | 27 | static constexpr bool bit_set(T& item, uint64_t bit){ 28 | T set = item & (1ULL << bit); 29 | item |= (1ULL << bit); 30 | return !(set == 0); 31 | } 32 | 33 | static constexpr bool bit_clear(T& item, uint64_t bit){ 34 | T set = item & (1ULL << bit); 35 | item &= ~(1ULL << bit); 36 | return !(set == 0); 37 | } 38 | 39 | static constexpr bool bit_test(T& item, uint64_t bit){ 40 | T set = item & (1ULL << bit); 41 | return !(set == 0); 42 | } 43 | }; 44 | 45 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/misc/compiler.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_COMPILER 2 | #define SIGMA_KERNEL_COMPILER 3 | 4 | #if __cpp_attributes 5 | 6 | #if __has_cpp_attribute(maybe_unused) 7 | #define MAYBE_UNUSED_ATTRIBUTE [[maybe_unused]] 8 | #else 9 | #define MAYBE_UNUSED_ATTRIBUTE 10 | #endif 11 | 12 | #if __has_cpp_attribute(nodiscard) 13 | #define NODISCARD_ATTRIBUTE [[nodiscard]] 14 | #else 15 | #define NODISCARD_ATTRIBUTE 16 | #endif 17 | 18 | #if __has_cpp_attribute(noreturn) 19 | #define NORETURN_ATTRIBUTE [[noreturn]] 20 | #else 21 | #define NORETURN_ATTRIBUTE 22 | #endif 23 | 24 | #if __has_cpp_attribute(fallthrough) 25 | #define FALLTHROUGH_ATTRIBUTE [[fallthrough]] 26 | #else 27 | #define FALLTHROUGH_ATTRIBUTE 28 | #endif 29 | 30 | // Compiler specific attributes 31 | #ifdef __GNUC__ 32 | #define PACKED_ATTRIBUTE [[gnu::packed]] 33 | #define NOINLINE_ATTRIBUTE [[gnu::noinline]] 34 | #define ALWAYSINLINE_ATTRIBUTE [[gnu::always_inline]] 35 | #else 36 | #error "Unknown compiler" 37 | #endif 38 | 39 | 40 | #else 41 | // At least try to use compiler legacy attributes, since there aren't any standardised ones 42 | #ifdef __GNUC__ 43 | #define MAYBE_UNUSED_ATTRIBUTE __attribute__((unused)) 44 | #define NODISCARD_ATTRIBUTE // Doesn't seem to exist 45 | #define NORETURN_ATTRIBUTE __attribute__((noreturn)) 46 | #define FALLTHROUGH_ATTRIBUTE __attribute__((fallthrough)) 47 | 48 | #define PACKED_ATTRIBUTE __attribute__((packed)) 49 | #define NOINLINE_ATTRIBUTE __attribute__((noinline)) 50 | #define ALWAYSINLINE_ATTRIBUTE __attribute__((always_inline)) 51 | #else 52 | #error "Unknown compiler" 53 | #endif 54 | 55 | #endif 56 | 57 | #if defined(__GNUC__) || defined(__clang__) // both clang and gcc support __PRETTY_FUNCTION__ 58 | #define SIGMA_FUNCTION_NAME __PRETTY_FUNCTION__ 59 | #elif defined(_MSC_VER) // Check for MSVC 60 | #undef SIGMA_FUNCTION_NAME 61 | #define SIGMA_FUNCTION_NAME __FUNCSIG__ 62 | #else // If noone supports it just use __func__ i guess 63 | #define SIGMA_FUNCTION_NAME __func__ 64 | #endif 65 | 66 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/misc/cpp_support.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace __cxxabiv1 8 | { 9 | __extension__ typedef uint16_t __guard; 10 | 11 | extern "C" int __cxa_guard_acquire(__guard *); 12 | extern "C" void __cxa_guard_release(__guard *); 13 | extern "C" void __cxa_guard_abort(__guard *); 14 | } 15 | 16 | 17 | void* operator new(size_t size); 18 | void* operator new[](size_t size); 19 | void operator delete(void* p); 20 | void operator delete[](void* p); 21 | void operator delete(void* p, long unsigned int size); 22 | void operator delete[](void* p, long unsigned int size); -------------------------------------------------------------------------------- /kernel/include/Sigma/misc/misc.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_MISC 2 | #define SIGMA_MISC 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace misc 10 | { 11 | struct uuid { 12 | std::byte data[16]; 13 | }; 14 | 15 | class id_generator { 16 | public: 17 | constexpr id_generator(): next_id{0} {} 18 | 19 | uint64_t id(){ 20 | return next_id++; 21 | } 22 | 23 | private: 24 | uint64_t next_id; 25 | }; 26 | 27 | template 28 | class lazy_initializer { 29 | public: 30 | template 31 | void init(Args&&... args){ 32 | if(this->_initialized) return; 33 | new (&_storage) T(std::forward(args)...); 34 | this->_initialized = true; 35 | } 36 | 37 | void deinit(){ 38 | _initialized = false; 39 | } 40 | 41 | explicit operator bool(){ 42 | return this->_initialized; 43 | } 44 | 45 | T* operator ->(){ 46 | return get(); 47 | } 48 | 49 | T& operator *(){ 50 | return *get(); 51 | } 52 | 53 | T* get(){ 54 | if(_initialized){ 55 | return reinterpret_cast(&_storage); 56 | } 57 | PANIC("Tried to access uninitialized lazy variable"); 58 | return nullptr; // Unreachable? 59 | } 60 | 61 | bool is_initialized(){ 62 | return _initialized; 63 | } 64 | 65 | private: 66 | bool _initialized = false; 67 | std::aligned_storage_t _storage; 68 | }; 69 | 70 | namespace kernel_args { 71 | void init(char* str); 72 | 73 | bool get_bool(const char* key); 74 | const char* get_str(const char* key); 75 | } 76 | 77 | template 78 | constexpr auto as_integer(Enumeration const value) -> typename std::underlying_type::type 79 | { 80 | return static_cast::type>(value); 81 | } 82 | 83 | constexpr uint64_t div_ceil(uint64_t val, uint64_t div) { 84 | return (val + div - 1) / div; 85 | } 86 | 87 | constexpr bool is_canonical(uint64_t addr){ 88 | return ((addr <= 0x00007fffffffffff) || ((addr >= 0xffff800000000000) && (addr <= 0xffffffffffffffff))); 89 | } 90 | 91 | constexpr uint64_t pow(uint64_t base, uint64_t pow){ 92 | uint64_t tmp = 1; 93 | for(uint64_t i = 0; i < pow; i++) tmp *= base; 94 | return tmp; 95 | } 96 | 97 | constexpr size_t min(size_t a, size_t b){ 98 | return (a < b) ? a : b; 99 | } 100 | 101 | constexpr uint64_t compile_time_prng(uint64_t r, uint64_t seed, uint64_t iterations){ 102 | /* 103 | * Xn = rXn-1(1 - Xn-1) 104 | * is chaotic for most values of r 105 | * See: https://en.wikipedia.org/wiki/Logistic_map 106 | * https://www.youtube.com/watch?v=ovJcsL7vyrk 107 | */ 108 | 109 | auto iterate = [](uint64_t r, uint64_t x) -> uint64_t { return r * x * (1 - x); }; 110 | 111 | uint64_t x = seed; 112 | 113 | for(uint64_t i = 0; i < iterations; i++) 114 | x = iterate(r, x); 115 | 116 | return x; 117 | } 118 | } // namespace misc 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /kernel/include/Sigma/misc/panic.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_PANIC 2 | #define SIGMA_KERNEL_PANIC 3 | 4 | #include 5 | #include 6 | 7 | namespace misc::panic { 8 | NORETURN_ATTRIBUTE 9 | void panic_m(const char* message, const char* function_override, std::experimental::source_location loc); 10 | 11 | NORETURN_ATTRIBUTE 12 | void panic_m(const char* message, std::experimental::source_location loc); 13 | } 14 | 15 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/mm/alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_ALLOC 2 | #define SIGMA_KERNEL_ALLOC 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // Simple heap allocator 10 | namespace alloc 11 | { 12 | constexpr uint16_t magic_low = 0xBEEF; 13 | constexpr uint16_t magic_high = 0xC0DE; 14 | 15 | struct alignas(64) header { 16 | uint16_t magic_low; 17 | struct header* next; 18 | size_t size; 19 | bool is_free; 20 | uint16_t magic_high; 21 | bool check_magic(){ 22 | return (this->magic_low == alloc::magic_low) && (this->magic_high == alloc::magic_high); 23 | } 24 | 25 | void set_magic(){ 26 | this->magic_low = alloc::magic_low; 27 | this->magic_high = alloc::magic_high; 28 | } 29 | }; 30 | 31 | void init(); 32 | void* alloc(size_t size); 33 | void* alloc_a(size_t size, uint64_t align); 34 | void* realloc(void* ptr, size_t size); 35 | void free(void* ptr); 36 | bool check_for_corruption(bool print_info); 37 | } // namespace alloc 38 | 39 | 40 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/mm/hmm.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_MM_HEAP 2 | #define SIGMA_KERNEL_MM_HEAP 3 | 4 | #include 5 | #include 6 | 7 | namespace mm::hmm 8 | { 9 | void init(); 10 | void* kmalloc(size_t size); 11 | void* kmalloc_a(size_t size, uint64_t align); 12 | void kfree(void* ptr); 13 | void* realloc(void* ptr, size_t size); 14 | } // mm::hmm 15 | 16 | 17 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/mm/pmm.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_MM_PMM 2 | #define SIGMA_KERNEL_MM_PMM 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // PMM should be fully global between ALL CPU's and threads and everything 12 | namespace mm::pmm 13 | { 14 | constexpr uint64_t block_size = 0x1000; 15 | 16 | void init(boot::boot_protocol* boot_protocol); 17 | void print_stack(); 18 | 19 | void* alloc_block(); 20 | void* alloc_n_blocks(size_t n); 21 | void free_block(void* block); 22 | } // mm::pmm 23 | 24 | 25 | 26 | 27 | 28 | 29 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/mm/vmm.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_MM_VMM 2 | #define SIGMA_KERNEL_MM_VMM 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace mm::vmm 10 | { 11 | class kernel_vmm { 12 | public: 13 | static x86_64::paging::context& get_instance(){ 14 | return _instance(); 15 | } 16 | 17 | kernel_vmm(kernel_vmm const&) = delete; 18 | void operator =(kernel_vmm const&) = delete; 19 | 20 | private: 21 | 22 | static x86_64::paging::context& _instance(); 23 | 24 | kernel_vmm() = default; 25 | }; 26 | } // mm::vmm 27 | 28 | 29 | 30 | 31 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/proc/initrd.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_INITRD 2 | #define SIGMA_KERNEL_INITRD 3 | 4 | #include 5 | #include 6 | 7 | namespace proc::initrd 8 | { 9 | struct tar_header{ 10 | char filename[100]; 11 | char mode[8]; 12 | char uid[8]; 13 | char gid[8]; 14 | char size[12]; 15 | char mtime[12]; 16 | char chksum[8]; 17 | char typeflag; 18 | }; 19 | 20 | // Initrd is a simple TAR archive 21 | void init(uint64_t address, uint64_t size); 22 | bool read_file(const char* file_name, uint8_t* buf, uint64_t offset, uint64_t size); 23 | size_t get_size(const char* file_name); 24 | } // namespace proc::initrd 25 | 26 | 27 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/proc/ipc.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_PROC_IPC_QUEUE_H 2 | #define SIGMA_PROC_IPC_QUEUE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | namespace proc::ipc 11 | { 12 | class queue { 13 | public: 14 | queue(tid_t sender, tid_t receiver); 15 | 16 | bool send(std::byte* data, size_t size); 17 | bool receive(std::byte* data); 18 | size_t get_top_message_size(); 19 | size_t get_n_messages(); 20 | 21 | generic::event _receive_event; 22 | 23 | private: 24 | struct message { 25 | #ifdef DEBUG 26 | uint16_t magic_low; 27 | #endif 28 | size_t size; 29 | std::byte* data; 30 | #ifdef DEBUG 31 | uint16_t magic_high; 32 | #endif 33 | }; 34 | 35 | types::queue _queue; 36 | tid_t _sender, _receiver; 37 | std::mutex _lock; 38 | }; 39 | 40 | class ring { 41 | public: 42 | ring(tid_t a, tid_t b): a{a}, b{b}, _a_queue{b, a}, _b_queue{a, b} {} 43 | ~ring() {} 44 | 45 | bool send(std::byte* data, size_t size); 46 | bool receive(std::byte* data); 47 | size_t get_n_messages(); 48 | size_t get_top_message_size(); 49 | generic::event& get_receive_event(); 50 | std::pair get_recipients(); 51 | 52 | 53 | private: 54 | tid_t a, b; 55 | queue _a_queue, _b_queue; 56 | }; 57 | 58 | size_t get_message_size(uint64_t ring); 59 | size_t get_n_messages(uint64_t ring); 60 | bool send(uint64_t ring, std::byte* data, size_t size); 61 | bool receive(uint64_t ring, std::byte* data); 62 | generic::event& get_receive_event(uint64_t ring); 63 | std::pair get_recipients(uint64_t ring); 64 | } // namespace proc::ipc 65 | 66 | 67 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/proc/simd.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_PROC_SIMD 2 | #define SIGMA_PROC_SIMD 3 | 4 | #include 5 | 6 | // Forward declaration 7 | namespace proc::process 8 | { 9 | struct thread; 10 | } // namespace proc::process 11 | 12 | 13 | namespace proc::simd 14 | { 15 | struct PACKED_ATTRIBUTE fxsave_area { 16 | uint16_t fcw; 17 | uint16_t fsw; 18 | uint8_t ftw; 19 | uint8_t reserved; 20 | uint16_t fop; 21 | uint64_t fip; 22 | uint64_t fdp; 23 | uint32_t mxcsr; 24 | uint32_t mxcsr_mask; 25 | 26 | struct PACKED_ATTRIBUTE mm_entry { 27 | uint64_t low; 28 | uint16_t high; 29 | uint32_t res; 30 | uint16_t res_0; 31 | }; 32 | static_assert(sizeof(mm_entry) == 16); 33 | mm_entry mm[8]; 34 | 35 | struct PACKED_ATTRIBUTE xmm_entry { 36 | uint64_t low; 37 | uint64_t high; 38 | }; 39 | static_assert(sizeof(xmm_entry) == 16); 40 | xmm_entry xmm[16]; 41 | uint8_t reserved_0[48]; 42 | uint8_t available[48]; 43 | }; 44 | static_assert(sizeof(fxsave_area) == 512); 45 | 46 | struct simd_state { 47 | simd_state(): data{nullptr} { init(); } 48 | void init(); 49 | void deinit(); 50 | 51 | simd_state(const simd_state&) = delete; 52 | simd_state(simd_state&&) = delete; 53 | simd_state& operator=(const simd_state& state); 54 | simd_state& operator=(simd_state&&) = delete; 55 | 56 | void save(); 57 | void restore(); 58 | private: 59 | 60 | uint8_t* data; 61 | }; 62 | 63 | void init(); 64 | } // namespace proc::simd 65 | 66 | 67 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/proc/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_PROC_SYSCALL 2 | #define SIGMA_KERNEL_PROC_SYSCALL 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | namespace proc::syscall 11 | { 12 | constexpr uint32_t star_msr = 0xC0000081; 13 | constexpr uint32_t lstar_msr = 0xC0000082; 14 | constexpr uint32_t cstar_msr = 0xC0000083; 15 | constexpr uint32_t sfmask_msr = 0xC0000084; 16 | 17 | 18 | constexpr uint8_t syscall_isr_number = 249; 19 | 20 | void init_syscall(); 21 | 22 | void serve_kernel_vfs(uint64_t ring); 23 | } // namespace proc::syscall 24 | 25 | 26 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/smp/cpu.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_SMP_CPU 2 | #define SIGMA_KERNEL_SMP_CPU 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace smp::cpu 13 | { 14 | struct entry; 15 | 16 | C_LINKAGE smp::cpu::entry* get_current_cpu(); 17 | 18 | struct entry { 19 | public: 20 | entry(): self_ptr((uint64_t)this), lapic_id{0}, gdt{}, tss{}, tss_gdt_offset{0}, features{.raw = 0} {} 21 | 22 | uint64_t self_ptr; 23 | 24 | x86_64::apic::lapic lapic; 25 | uint32_t lapic_id; 26 | 27 | x86_64::gdt::gdt gdt; 28 | x86_64::tss::table tss; 29 | uint16_t tss_gdt_offset; 30 | 31 | x86_64::paging::pcid_cpu_context pcid_context; 32 | 33 | x86_64::spinlock::irq_lock irq_lock; 34 | 35 | misc::lazy_initializer idle_stack; 36 | misc::lazy_initializer kstack; 37 | 38 | union { 39 | struct { 40 | uint64_t pcid : 1; 41 | uint64_t invpcid : 1; 42 | uint64_t smap : 1; 43 | uint64_t svm : 1; 44 | uint64_t x2apic : 1; 45 | uint64_t vt_d : 1; 46 | }; 47 | uint64_t raw; 48 | } features; 49 | 50 | void set_gs(){ 51 | this->self_ptr = (uint64_t)this; 52 | 53 | x86_64::msr::write(x86_64::msr::gs_base, (uint64_t)&self_ptr); 54 | x86_64::msr::write(x86_64::msr::kernelgs_base, 0); 55 | } 56 | }; 57 | } // smp::cpu 58 | 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /kernel/include/Sigma/smp/ipi.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_SMP_IPI 2 | #define SIGMA_KERNEL_SMP_IPI 3 | 4 | #include 5 | #include 6 | 7 | namespace smp 8 | { 9 | namespace ipi 10 | { 11 | constexpr uint8_t ping_ipi_vector = 250; 12 | constexpr uint8_t shootdown_ipi_vector = 251; 13 | 14 | void send_shootdown(uint64_t address, uint64_t length); 15 | void send_ping(uint32_t apic_id); 16 | void send_ping(); 17 | 18 | void init_ipi(); 19 | } // namespace ipi 20 | } // namespace spm 21 | 22 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/smp/smp.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_SMP_SMP 2 | #define SIGMA_KERNEL_SMP_SMP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace smp 14 | { 15 | struct cpu_entry { 16 | uint32_t lapic_id; 17 | bool x2apic; 18 | bool bsp; 19 | }; 20 | 21 | C_LINKAGE uint64_t trampoline_start; 22 | C_LINKAGE uint64_t trampoline_end; 23 | C_LINKAGE uint8_t trampoline_booted; 24 | C_LINKAGE uint64_t trampoline_stack; 25 | C_LINKAGE uint64_t trampoline_paging; 26 | 27 | constexpr uint64_t smp_trampoline_base = 0x1000; 28 | 29 | class multiprocessing { 30 | public: 31 | multiprocessing(types::linked_list& cpus); 32 | 33 | void boot_aps(); 34 | 35 | private: 36 | void boot_cpu(cpu_entry& e); 37 | void boot_apic(smp::cpu_entry& cpu); 38 | 39 | types::linked_list& cpus; 40 | }; 41 | } // smp 42 | 43 | 44 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/types/bitmap.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_TYPES_BITMAP_H 2 | #define SIGMA_TYPES_BITMAP_H 3 | 4 | #include 5 | 6 | namespace types 7 | { 8 | class bitmap { 9 | public: 10 | bitmap() = default; 11 | bitmap(size_t n_bits){ 12 | n_bytes = misc::div_ceil(n_bits, 8); 13 | array = new uint8_t[n_bytes]{}; 14 | } 15 | 16 | bitmap(const bitmap&) = delete; 17 | bitmap& operator=(const bitmap& other){ 18 | this->n_bytes = other.n_bytes; 19 | this->array = new uint8_t[other.n_bytes]; 20 | memcpy(this->array, other.array, other.n_bytes); 21 | return *this; 22 | } 23 | 24 | ~bitmap(){ 25 | delete[] array; 26 | } 27 | 28 | void set(uint64_t bit){ 29 | uint64_t index = bit / 8; 30 | uint64_t offset = bit % 8; 31 | 32 | array[index] |= (1ull << offset); 33 | } 34 | 35 | void clear(uint64_t bit){ 36 | uint64_t index = bit / 8; 37 | uint64_t offset = bit % 8; 38 | 39 | array[index] &= ~(1ull << offset); 40 | } 41 | 42 | bool test(uint64_t bit){ 43 | uint64_t index = bit / 8; 44 | uint64_t offset = bit % 8; 45 | 46 | bool state = (array[index] & (1ull << offset)) ? true : false; 47 | return state; 48 | } 49 | 50 | uint64_t get_free_bit(){ 51 | for(size_t i = 0; i < n_bytes; i++){ 52 | if(array[i] != 0xFF){ // Test if this entry is full 53 | for(uint64_t j = 0; j < 8; j++){ 54 | uint64_t bit = 1ull << j; 55 | if(!(array[i] & bit)) 56 | return i * 8 + j; 57 | } 58 | } 59 | } 60 | 61 | return (uint64_t)-1; 62 | } 63 | 64 | private: 65 | size_t n_bytes; 66 | uint8_t* array; 67 | }; 68 | } // namespace types 69 | 70 | 71 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/types/hash_map.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_TYPES_HASH_MAP_H 2 | #define SIGMA_TYPES_HASH_MAP_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace types 10 | { 11 | template 12 | struct nop_hasher { 13 | using hash_result = T; 14 | 15 | hash_result operator()(T item){ 16 | return item; 17 | } 18 | }; 19 | 20 | // TODO: Seriously, this is the best hash_map you can think of, just, make something doable, not this monstrosity 21 | template 22 | class hash_map { 23 | public: 24 | hash_map() = default; 25 | hash_map(hash_map&& other){ 26 | this->list = std::move(other.list); 27 | this->hasher = std::move(other.hasher); 28 | } 29 | 30 | hash_map& operator=(hash_map&& other){ 31 | this->list = std::move(other.list); 32 | this->hasher = std::move(other.hasher); 33 | 34 | return *this; 35 | } 36 | 37 | void push_back(Key key, Value value){ 38 | auto hash = this->hasher(key); 39 | 40 | this->list.push_back({hash, value}); 41 | } 42 | 43 | Value& operator[](Key key){ 44 | auto hash = this->hasher(key); 45 | 46 | for(auto& entry : list) 47 | if(entry.first == hash) 48 | return entry.second; 49 | 50 | PANIC("Hash not in map"); 51 | while(1) 52 | ; 53 | } 54 | 55 | private: 56 | using entry = std::pair; 57 | 58 | types::linked_list list; 59 | 60 | Hasher hasher; 61 | }; 62 | } // namespace types 63 | 64 | 65 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/types/minimal_array.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_TYPES_MINIMAL_ARRAY 2 | #define SIGMA_TYPES_MINIMAL_ARRAY 3 | 4 | #include 5 | #include 6 | 7 | namespace types 8 | { 9 | // Array that holds NStaticElements statically and dynamically allocates more if needed 10 | template 11 | class minimal_array 12 | { 13 | public: 14 | constexpr minimal_array() noexcept : current_index(0) {} 15 | 16 | NODISCARD_ATTRIBUTE 17 | T& at(int index){ 18 | if(index < NStaticElements) 19 | return static_elements[index]; 20 | else { 21 | if(!dynamic_elements) 22 | dynamic_elements.init(); 23 | return dynamic_elements->operator[](index - NStaticElements); 24 | } 25 | } 26 | 27 | size_t length(){ 28 | return current_index; 29 | } 30 | 31 | NODISCARD_ATTRIBUTE 32 | T& empty_entry(){ 33 | if(current_index < NStaticElements) 34 | return static_elements[current_index++]; 35 | else { 36 | if(!dynamic_elements) 37 | dynamic_elements.init(); 38 | 39 | auto& ret = *dynamic_elements->empty_entry(); 40 | current_index++; 41 | return ret; 42 | } 43 | } 44 | private: 45 | size_t current_index; 46 | T static_elements[NStaticElements]; 47 | misc::lazy_initializer> dynamic_elements; 48 | }; 49 | 50 | } // namespace types 51 | 52 | 53 | 54 | #endif -------------------------------------------------------------------------------- /kernel/include/Sigma/types/queue.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_TYPES_QUEUE_H 2 | #define SIGMA_TYPES_QUEUE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace types 11 | { 12 | template 13 | class queue 14 | { 15 | public: 16 | constexpr queue() noexcept : _lock{}, _length{0}, _offset{0}, _array{nullptr} {} 17 | ~queue(){ 18 | std::lock_guard irq_guard{smp::cpu::get_current_cpu()->irq_lock}; 19 | std::lock_guard guard{this->_lock}; 20 | if(_array){ 21 | for(size_t i = 0; i < this->_offset; i++) 22 | _array[i].~T(); 23 | free(_array); 24 | } 25 | } 26 | 27 | queue(const queue&) = delete; 28 | queue& operator=(const queue& other) = delete; 29 | 30 | void push(T item){ 31 | std::lock_guard irq_guard{smp::cpu::get_current_cpu()->irq_lock}; 32 | std::lock_guard guard{this->_lock}; 33 | 34 | ensure_capacity(_offset + 1); 35 | new (&_array[_offset]) T{item}; 36 | _offset++; 37 | } 38 | 39 | T pop(){ 40 | std::lock_guard irq_guard{smp::cpu::get_current_cpu()->irq_lock}; 41 | std::lock_guard guard{this->_lock}; 42 | if(_offset == 0) 43 | PANIC("Tried to pop from queue with 0 elements"); 44 | 45 | _offset--; 46 | T ret = std::move(_array[_offset]); 47 | _array[_offset].~T(); 48 | return ret; 49 | } 50 | 51 | T& back(){ 52 | std::lock_guard irq_guard{smp::cpu::get_current_cpu()->irq_lock}; 53 | std::lock_guard guard{this->_lock}; 54 | if(_offset == 0) 55 | PANIC("Tried to get back of queue with 0 elements"); 56 | 57 | return _array[_offset - 1]; 58 | } 59 | 60 | size_t length(){ 61 | std::lock_guard irq_guard{smp::cpu::get_current_cpu()->irq_lock}; 62 | std::lock_guard guard{this->_lock}; 63 | return _offset; 64 | } 65 | private: 66 | void ensure_capacity(size_t c){ 67 | if(c <= _length) 68 | return; 69 | 70 | size_t new_len = _length + c + 16; 71 | T* new_data = (T*)malloc(sizeof(T) * new_len); 72 | for(size_t i = 0; i < _length; i++) 73 | new (&new_data[i]) T{std::move(_array[i])}; 74 | 75 | for(size_t i = 0; i < _offset; i++) 76 | _array[i].~T(); 77 | free(_array); 78 | 79 | _array = new_data; 80 | _length = new_len; 81 | } 82 | 83 | std::mutex _lock; 84 | size_t _length; 85 | size_t _offset; 86 | T* _array; 87 | }; 88 | } // namespace types 89 | 90 | 91 | 92 | #endif // !SIGMA_TYPES_QUEUE_H -------------------------------------------------------------------------------- /kernel/include/Sigma/types/vector.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KERNEL_TYPES_VECTOR 2 | #define SIGMA_KERNEL_TYPES_VECTOR 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace types 9 | { 10 | template 11 | class vector { 12 | public: 13 | using iterator = T*; 14 | using const_iterator = const T*; 15 | 16 | vector(): _length{16}, _offset{0} { 17 | _data = new (malloc(sizeof(T) * _length)) T; 18 | } 19 | 20 | ~vector(){ 21 | for(auto&& entry : *this) 22 | entry.~T(); 23 | free(static_cast(this->_data)); 24 | } 25 | 26 | vector(const vector& b) { 27 | ensure_capacity(b._offset); 28 | for(size_t i = 0; i < b._offset; i++) 29 | new (&_data[i]) T{b._data[i]}; 30 | _offset = b._offset; 31 | } 32 | 33 | friend void swap(vector& a, vector& b){ 34 | using std::swap; 35 | swap(a._length, b._length); 36 | swap(a._offset, b._offset); 37 | swap(a._data, b._data); 38 | } 39 | 40 | vector& operator=(vector& other) { 41 | swap(*this, other); 42 | return *this; 43 | } 44 | 45 | 46 | void resize(size_t size){ 47 | ensure_capacity(size + 1); 48 | if(size < _offset){ 49 | for(size_t i = size; i < _offset; i++) 50 | _data[i].~T(); 51 | } else { 52 | for(size_t i = _offset; i < size; i++) 53 | new (&_data[i]) T{}; 54 | } 55 | 56 | _offset = size; 57 | } 58 | 59 | void push_back(T value){ 60 | ensure_capacity(_offset + 1); 61 | _data[_offset++] = value; 62 | } 63 | 64 | NODISCARD_ATTRIBUTE 65 | T* empty_entry() { 66 | ensure_capacity(_offset + 1); 67 | return new (&_data[_offset++]) T(); 68 | } 69 | 70 | NODISCARD_ATTRIBUTE 71 | T& operator[](size_t index) { 72 | if(index >= _offset) 73 | PANIC("Tried to access vector out of bounds"); 74 | 75 | return _data[index]; 76 | } 77 | 78 | T* data(){ 79 | return this->_data; 80 | } 81 | 82 | size_t size(){ 83 | return _offset; 84 | } 85 | 86 | NODISCARD_ATTRIBUTE 87 | iterator begin() { 88 | return _data; 89 | } 90 | 91 | NODISCARD_ATTRIBUTE 92 | iterator end() { 93 | return _data + _offset; 94 | } 95 | 96 | NODISCARD_ATTRIBUTE 97 | T& back(){ 98 | return *(_data + _offset - 1); 99 | } 100 | 101 | NODISCARD_ATTRIBUTE 102 | const_iterator begin() const { 103 | return _data; 104 | } 105 | 106 | NODISCARD_ATTRIBUTE 107 | const_iterator end() const { 108 | return _data + _offset; 109 | } 110 | 111 | NODISCARD_ATTRIBUTE 112 | T& back() const { 113 | return *(_data + _offset - 1); 114 | } 115 | 116 | 117 | private: 118 | void ensure_capacity(size_t c){ 119 | if(c <= _length) 120 | return; 121 | 122 | size_t new_len = _length + c + 16; 123 | T* new_data = (T*)malloc(sizeof(T) * new_len); 124 | for(size_t i = 0; i < _length; i++) 125 | new (&new_data[i]) T{std::move(_data[i])}; 126 | 127 | for(size_t i = 0; i < _offset; i++) 128 | _data[i].~T(); 129 | free(_data); 130 | 131 | _data = new_data; 132 | _length = new_len; 133 | } 134 | 135 | size_t _length; 136 | size_t _offset; 137 | T* _data; 138 | }; 139 | } // namespace types 140 | 141 | 142 | #endif -------------------------------------------------------------------------------- /kernel/include/klibc/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KLIBC_STDIO 2 | #define SIGMA_KLIBC_STDIO 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define EOF (-1) 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | int printf(const char* format, ...); 15 | int putchar(int c); 16 | int puts(const char* s); 17 | 18 | int debug_printf(const char* format, ...); 19 | 20 | #ifdef __cplusplus 21 | } 22 | #endif 23 | 24 | #endif -------------------------------------------------------------------------------- /kernel/include/klibc/stdlib.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KLIBC_STDLIB 2 | #define SIGMA_KLIBC_STDLIB 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | 11 | char* itoa(int64_t value, char* str, int base); 12 | __attribute__((__noreturn__)) void abort(void); 13 | void htoa(int64_t n, char* str); 14 | 15 | void *malloc(size_t size); 16 | void *realloc(void* ptr, size_t size); 17 | void free(void* ptr); 18 | 19 | 20 | #ifdef __cplusplus 21 | } 22 | #endif 23 | 24 | 25 | #endif -------------------------------------------------------------------------------- /kernel/include/klibc/string.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KLIBC_STRING 2 | #define SIGMA_KLIBC_STRING 3 | 4 | #include 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | size_t strlen(const char* s); 12 | char *strcpy(char *dest, const char *src); 13 | int strcmp(const char s1[], const char s2[]); 14 | void* memset(void* s, int c, size_t n); 15 | 16 | int memcmp(const void* s1, const void* s2, size_t n); 17 | void* memcpy(void* dest, const void* src, size_t n); 18 | void* memmove(void* dstptr, const void* srcptr, size_t size); 19 | 20 | void* memset_aligned_4k(void* dest, int c); 21 | void* memcpy_aligned_4k(void* dest, void* src); 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif 26 | 27 | 28 | #endif -------------------------------------------------------------------------------- /kernel/include/klibcxx/README.md: -------------------------------------------------------------------------------- 1 | Yes, a lot of headers are provided by freestanding libstdc++ 2 | 3 | However, a ton aren't, or aren't yet. So i provide them myself here. 4 | Also it's quite fun to implement them myself -------------------------------------------------------------------------------- /kernel/include/klibcxx/algorithm.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KLIBCXX_ALGORITHM 2 | #define SIGMA_KLIBCXX_ALGORITHM 3 | 4 | #include 5 | #include 6 | 7 | namespace KLIBCXX_NAMESPACE_NAME { 8 | template 9 | constexpr UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f){ 10 | for(auto it = first; it != last; ++it) 11 | f(*it); 12 | 13 | return std::move(f); 14 | } 15 | 16 | template 17 | constexpr InputIt find_if(InputIt first, InputIt last, UnaryPredicate p){ 18 | for(auto it = first; it != last; ++it) 19 | if(p(*it)) 20 | return it; 21 | 22 | return last; 23 | } 24 | } 25 | 26 | #endif // !SIGMA_KLIBCXX_ALGORITHM -------------------------------------------------------------------------------- /kernel/include/klibcxx/common.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KLIBCXX_COMMON 2 | #define SIGMA_KLIBCXX_COMMON 3 | 4 | #define KLIBCXX_NAMESPACE_NAME std 5 | 6 | #define KLIBCXX_NATIVE_MUTEX_INCLUDE 7 | #define KLIBCXX_NATIVE_MUTEX_TYPE x86_64::spinlock::mutex 8 | 9 | #endif // !SIGMA_KLIBCXX_COMMON -------------------------------------------------------------------------------- /kernel/include/klibcxx/experimental/source_location.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KLIBCXX_SOURCE_LOCATION 2 | #define SIGMA_KLIBCXX_SOURCE_LOCATION 3 | 4 | #include 5 | #include 6 | 7 | namespace KLIBCXX_NAMESPACE_NAME::experimental { 8 | struct source_location { 9 | public: 10 | constexpr source_location() noexcept : _line(0), _column(0), _file_name("Unknown"), _function_name("Unknown") {} 11 | source_location(const source_location& other) = default; 12 | source_location(source_location&& other) = default; 13 | 14 | // Defined per compiler 15 | #ifdef __GNUC__ 16 | static constexpr source_location current(const char* __file = __builtin_FILE(), 17 | const char* __func = __builtin_FUNCTION(), 18 | uint_least32_t __line = __builtin_LINE(), 19 | uint_least32_t __col = 0) noexcept { 20 | source_location loc{}; 21 | loc._file_name = __file; 22 | loc._function_name = __func; 23 | loc._line = __line; 24 | loc._column = __col; 25 | return loc; 26 | } 27 | #else 28 | #error "Compiling with unknown compiler"; 29 | #endif 30 | 31 | constexpr std::uint_least32_t line() const noexcept { 32 | return _line; 33 | } 34 | 35 | constexpr std::uint_least32_t column() const noexcept { 36 | return _column; 37 | } 38 | 39 | constexpr const char* file_name() const noexcept { 40 | return _file_name; 41 | } 42 | 43 | constexpr const char* function_name() const noexcept { 44 | return _function_name; 45 | } 46 | 47 | private: 48 | std::uint_least32_t _line, _column; 49 | const char* _file_name; 50 | const char* _function_name; 51 | }; 52 | } 53 | 54 | #endif // !SIGMA_KLIBCXX_SOURCE_LOCATION 55 | -------------------------------------------------------------------------------- /kernel/include/klibcxx/functional.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KLIBCXX_FUNCTIONAL 2 | #define SIGMA_KLIBCXX_FUNCTIONAL 3 | 4 | #include 5 | #include 6 | 7 | namespace KLIBCXX_NAMESPACE_NAME 8 | { 9 | template 10 | struct less; 11 | 12 | template 13 | struct less { 14 | constexpr bool operator()(const T& lhs, const T& rhs) const { 15 | return lhs < rhs; 16 | } 17 | }; 18 | 19 | template<> 20 | struct less { 21 | template 22 | constexpr auto operator()(T&& lhs, U&& rhs) const noexcept(noexcept(std::forward(lhs) < std::forward(rhs))) 23 | -> decltype(std::forward(lhs) < std::forward(rhs)) { 24 | return std::forward(lhs) < std::forward(rhs); 25 | } 26 | }; 27 | } // namespace KLIBCXX_NAMESPACE_NAME 28 | 29 | 30 | #endif // !SIGMA_KLIBCXX_FUNCTIONAL -------------------------------------------------------------------------------- /kernel/include/klibcxx/mutex.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_KLIBCXX_MUTEX 2 | #define SIGMA_KLIBCXX_MUTEX 3 | 4 | #include 5 | 6 | #include KLIBCXX_NATIVE_MUTEX_INCLUDE 7 | 8 | namespace KLIBCXX_NAMESPACE_NAME { 9 | class mutex { 10 | public: 11 | constexpr mutex() noexcept : handle{} {} 12 | 13 | ~mutex() = default; 14 | 15 | mutex(const mutex&) = delete; 16 | mutex& operator =(const mutex&) = delete; 17 | 18 | void lock(){ 19 | handle.lock(); 20 | } 21 | 22 | bool try_lock(){ 23 | return handle.try_lock(); 24 | } 25 | 26 | void unlock(){ 27 | handle.unlock(); 28 | } 29 | 30 | using native_handle_type = KLIBCXX_NATIVE_MUTEX_TYPE; 31 | native_handle_type& native_handle(){ 32 | return handle; 33 | } 34 | 35 | private: 36 | native_handle_type handle; 37 | }; 38 | 39 | 40 | template 41 | class lock_guard { 42 | public: 43 | using mutex_type = Mutex; 44 | explicit lock_guard(mutex_type& m): _mutex(m){ 45 | _mutex.lock(); 46 | } 47 | 48 | ~lock_guard(){ 49 | _mutex.unlock(); 50 | } 51 | 52 | lock_guard& operator=(const lock_guard&) = delete; 53 | lock_guard(const lock_guard&) = delete; 54 | 55 | private: 56 | mutex_type& _mutex; 57 | }; 58 | } 59 | 60 | #endif // !SIGMA_KLIBCXX_MUTEX -------------------------------------------------------------------------------- /kernel/meson_options.txt: -------------------------------------------------------------------------------- 1 | option('sigma_compile_ubsan', type: 'boolean', value: false) -------------------------------------------------------------------------------- /kernel/source/acpi/laihost.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | C_LINKAGE { 12 | 13 | void *laihost_malloc(size_t sz){ 14 | if(sz == 0) sz = 1; // Just in case 15 | return malloc(sz); 16 | } 17 | 18 | void *laihost_realloc(void *ptr, size_t size){ 19 | return realloc(ptr, size); 20 | } 21 | 22 | void laihost_free(void *ptr){ 23 | free(ptr); 24 | } 25 | 26 | void laihost_log(int level, const char *msg){ 27 | switch (level) { 28 | case LAI_DEBUG_LOG: 29 | debug_printf("[LAI]: Debug: %s\n", msg); 30 | break; 31 | case LAI_WARN_LOG: 32 | printf("[LAI]: Warning: %s\n", msg); 33 | debug_printf("[LAI] Warning: %s\n", msg); 34 | break; 35 | default: 36 | debug_printf("[LAI]: Unknown : %s\n", msg); 37 | break; 38 | } 39 | } 40 | 41 | void laihost_panic(const char* msg){ 42 | PANIC(msg); 43 | } 44 | 45 | void *laihost_scan(const char* signature, size_t index){ 46 | return static_cast(acpi::get_table(signature, index)); 47 | } 48 | 49 | void *laihost_map(size_t addr, size_t bytes){ 50 | uint64_t n_pages = misc::div_ceil(bytes, mm::pmm::block_size); // Ceil it to make sure we have all bytes allocated in case (bytes & 0xFFF) != 0 51 | 52 | for(size_t i = 0; i < n_pages; i++){ 53 | uint64_t offset = (i * mm::pmm::block_size); 54 | mm::vmm::kernel_vmm::get_instance().map_page((addr + offset), (addr + offset + KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE), map_page_flags_present | map_page_flags_writable | map_page_flags_no_execute | map_page_flags_global); 55 | } 56 | 57 | return reinterpret_cast(addr + KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE); 58 | } 59 | 60 | void laihost_unmap(void* addr, size_t bytes){ 61 | debug_printf("[LAI]: Ignoring laihost_unmap(%x, %x)\n", addr, bytes); 62 | } 63 | 64 | void laihost_outb(uint16_t port, uint8_t val){ x86_64::io::outb(port, val); } 65 | void laihost_outw(uint16_t port, uint16_t val){ x86_64::io::outw(port, val); } 66 | void laihost_outd(uint16_t port, uint32_t val){ x86_64::io::outd(port, val); } 67 | 68 | uint8_t laihost_inb(uint16_t port){ return x86_64::io::inb(port); } 69 | uint16_t laihost_inw(uint16_t port){ return x86_64::io::inw(port); } 70 | uint32_t laihost_ind(uint16_t port){ return x86_64::io::ind(port); } 71 | 72 | void laihost_pci_writeb(uint16_t seg, uint8_t bus, uint8_t device, uint8_t function, uint16_t offset , uint8_t value){ 73 | x86_64::pci::write(seg, bus, device, function, offset, value, 1); 74 | } 75 | 76 | uint8_t laihost_pci_readb(uint16_t seg, uint8_t bus, uint8_t device, uint8_t function, uint16_t offset){ 77 | return x86_64::pci::read(seg, bus, device, function, offset, 1); 78 | } 79 | 80 | void laihost_pci_writew(uint16_t seg, uint8_t bus, uint8_t device, uint8_t function, uint16_t offset , uint16_t value){ 81 | x86_64::pci::write(seg, bus, device, function, offset, value, 2); 82 | } 83 | 84 | uint16_t laihost_pci_readw(uint16_t seg, uint8_t bus, uint8_t device, uint8_t function, uint16_t offset){ 85 | return x86_64::pci::read(seg, bus, device, function, offset, 2); 86 | } 87 | 88 | void laihost_pci_writed(uint16_t seg, uint8_t bus, uint8_t device, uint8_t function, uint16_t offset , uint32_t value){ 89 | x86_64::pci::write(seg, bus, device, function, offset, value, 4); 90 | } 91 | 92 | uint32_t laihost_pci_readd(uint16_t seg, uint8_t bus, uint8_t device, uint8_t function, uint16_t offset){ 93 | return x86_64::pci::read(seg, bus, device, function, offset, 4); 94 | } 95 | 96 | void laihost_sleep(uint64_t ms){ 97 | x86_64::hpet::poll_sleep(ms); 98 | } 99 | 100 | } -------------------------------------------------------------------------------- /kernel/source/arch/x86_64/amd/svm_low.asm: -------------------------------------------------------------------------------- 1 | [bits 64] 2 | 3 | section .text 4 | 5 | global _vmrun 6 | _vmrun: 7 | push rax 8 | push rbx 9 | push rcx 10 | push rdx 11 | push rdi 12 | push rbp 13 | push r8 14 | push r9 15 | push r10 16 | push r11 17 | push r12 18 | push r13 19 | push r14 20 | push r15 21 | push rsi 22 | 23 | ; Restore guest GPR state 24 | mov rbx, qword [rdi + 0x0] 25 | mov rcx, qword [rdi + 0x8] 26 | mov rdx, qword [rdi + 0x10] 27 | mov rsi, qword [rdi + 0x18] 28 | mov rbp, qword [rdi + 0x28] 29 | mov r8, qword [rdi + 0x30] 30 | mov r9, qword [rdi + 0x38] 31 | mov r10, qword [rdi + 0x40] 32 | mov r11, qword [rdi + 0x48] 33 | mov r12, qword [rdi + 0x50] 34 | mov r13, qword [rdi + 0x58] 35 | mov r14, qword [rdi + 0x60] 36 | mov r15, qword [rdi + 0x68] 37 | 38 | push rdi 39 | mov rdi, qword [rdi + 0x20] 40 | 41 | mov rax, qword [rsp + 8] ; Move VMCB into rax 42 | vmload 43 | vmrun 44 | vmsave 45 | 46 | push rdi 47 | mov rdi, qword [rsp + 0x8] ; Restore RDI from stack 48 | 49 | mov qword [rdi + 0x0], rbx 50 | mov qword [rdi + 0x8], rcx 51 | mov qword [rdi + 0x10], rdx 52 | mov qword [rdi + 0x18], rsi 53 | mov qword [rdi + 0x28], rbp 54 | mov qword [rdi + 0x30], r8 55 | mov qword [rdi + 0x38], r9 56 | mov qword [rdi + 0x40], r10 57 | mov qword [rdi + 0x48], r11 58 | mov qword [rdi + 0x50], r12 59 | mov qword [rdi + 0x58], r13 60 | mov qword [rdi + 0x60], r14 61 | mov qword [rdi + 0x68], r15 62 | 63 | pop r8 64 | pop r9 65 | mov qword [r9 + 0x20], r8 66 | 67 | pop rsi 68 | pop r15 69 | pop r14 70 | pop r13 71 | pop r12 72 | pop r11 73 | pop r10 74 | pop r9 75 | pop r8 76 | pop rbp 77 | pop rdi 78 | pop rdx 79 | pop rcx 80 | pop rbx 81 | pop rax 82 | 83 | ret -------------------------------------------------------------------------------- /kernel/source/arch/x86_64/cpu_low.asm: -------------------------------------------------------------------------------- 1 | [bits 64] 2 | section .text 3 | 4 | global emulate_invpcid 5 | emulate_invpcid: 6 | push rax 7 | push rdx 8 | 9 | mov rdx, rsi ; Set kernel pml4 10 | and rdx, ~0xFFF 11 | or rdx, rdi ; PCID to invalidate 12 | btc rdx, 63 ; Actually invalidate 13 | 14 | mov rax, cr3 15 | 16 | pushf 17 | cli ; Don't get interrupted 18 | mov cr3, rdx ; Invalidate PCID 19 | mov cr3, rax ; Restore cr3 20 | popf 21 | 22 | pop rdx 23 | pop rax 24 | ret 25 | 26 | global read_xcr 27 | read_xcr: 28 | push rcx 29 | push rdx 30 | 31 | xor rax, rax 32 | xor rdx, rdx 33 | 34 | mov rcx, rdi 35 | xgetbv 36 | 37 | shl rdx, 32 38 | or rax, rdx 39 | 40 | pop rdx 41 | pop rcx 42 | ret 43 | 44 | global write_xcr 45 | write_xcr: 46 | push rax 47 | push rcx 48 | push rdx 49 | push r8 50 | 51 | mov rcx, rdi 52 | 53 | mov r8, rsi 54 | xor rax, rax 55 | mov rax, r8 ; Set low 32bits of 2nd argument into eax 56 | 57 | shr r8, 32 58 | xor rdx, rdx 59 | mov rdx, r8 ; Set high 32bits of 2nd argument into eax 60 | 61 | xsetbv 62 | 63 | pop r8 64 | pop rdx 65 | pop rcx 66 | pop rax 67 | ret -------------------------------------------------------------------------------- /kernel/source/arch/x86_64/drivers/pic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static uint8_t pic1_int_base; 4 | static uint8_t pic2_int_base; 5 | 6 | static uint16_t get_irq_reg(uint8_t ocw3){ 7 | x86_64::io::outb(x86_64::pic::pic1_cmd_port, ocw3); 8 | x86_64::io::outb(x86_64::pic::pic2_cmd_port, ocw3); 9 | 10 | return (x86_64::io::inb(x86_64::pic::pic2_cmd_port) << 8) | (x86_64::io::inb(x86_64::pic::pic1_cmd_port)); 11 | } 12 | 13 | static uint16_t get_isr(){ 14 | return get_irq_reg(x86_64::pic::read_isr); 15 | } 16 | 17 | void x86_64::pic::remap(uint8_t pic1_base, uint8_t pic2_base){ 18 | uint8_t pic1_mask = x86_64::io::inb(x86_64::pic::pic1_data_port); // Save masks 19 | uint8_t pic2_mask = x86_64::io::inb(x86_64::pic::pic2_data_port); 20 | 21 | x86_64::io::outb(x86_64::pic::pic1_cmd_port, (x86_64::pic::icw1_init | x86_64::pic::icw1_icw4)); // Start init sequence, in cascade mode 22 | x86_64::io::outb(x86_64::pic::pic2_cmd_port, (x86_64::pic::icw1_init | x86_64::pic::icw1_icw4)); 23 | 24 | x86_64::io::outb(x86_64::pic::pic1_data_port, pic1_base); // ISR vector 25 | x86_64::io::outb(x86_64::pic::pic2_data_port, pic2_base); 26 | 27 | x86_64::io::outb(x86_64::pic::pic1_data_port, 4); // Tell master that there is a slave at IRQ2 28 | x86_64::io::outb(x86_64::pic::pic2_data_port, 2); // Tell slave its cascade identity 29 | 30 | x86_64::io::outb(x86_64::pic::pic1_data_port, x86_64::pic::icw4_8086); // Set them in 8086 mode 31 | x86_64::io::outb(x86_64::pic::pic2_data_port, x86_64::pic::icw4_8086); 32 | 33 | x86_64::io::outb(x86_64::pic::pic1_data_port, pic1_mask); // Restore masks 34 | x86_64::io::outb(x86_64::pic::pic2_data_port, pic2_mask); 35 | 36 | pic1_int_base = pic1_base; 37 | pic2_int_base = pic2_base; 38 | } 39 | 40 | void x86_64::pic::send_eoi(){ 41 | uint16_t isr = get_isr(); 42 | 43 | if(isr == 0) return; // PIC1 Spurious or no interrupt at all 44 | if(bitops::bit_test(isr, 2) && ((isr >> 8) & 0xFF) == 0){ 45 | x86_64::io::outb(x86_64::pic::pic1_cmd_port, x86_64::pic::eoi_cmd); //PIC2 Spurious 46 | return; 47 | } 48 | 49 | if(bitops::bit_test(isr, 2)) x86_64::io::outb(x86_64::pic::pic2_cmd_port, x86_64::pic::eoi_cmd); //PIC2 EOI 50 | x86_64::io::outb(x86_64::pic::pic1_cmd_port, x86_64::pic::eoi_cmd); //PIC1 EOI 51 | } 52 | 53 | void x86_64::pic::set_base_vector(uint8_t base){ 54 | remap(base, (base + 8)); 55 | } 56 | 57 | void x86_64::pic::disable() { 58 | x86_64::io::outb(x86_64::pic::pic1_data_port, 0xFF); // Mask all interrupts as to "disable" it 59 | x86_64::io::outb(x86_64::pic::pic2_data_port, 0xFF); 60 | } 61 | 62 | void x86_64::pic::enable() { 63 | x86_64::io::outb(x86_64::pic::pic1_data_port, 0x0); // Unmask all interrupts to enable it 64 | x86_64::io::outb(x86_64::pic::pic2_data_port, 0x0); 65 | } 66 | -------------------------------------------------------------------------------- /kernel/source/arch/x86_64/gdt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | x86_64::gdt::gdt::gdt(): pointer(x86_64::gdt::pointer()){ 4 | memset(this->entries, 0, (sizeof(x86_64::gdt::entry) * x86_64::gdt::max_entries)); 5 | this->entry_index = 0; 6 | } 7 | 8 | C_LINKAGE void flush_gdt(); 9 | 10 | void x86_64::gdt::gdt::init(){ 11 | this->add_entry(0); // Null Entry 12 | this->add_entry(x86_64::gdt::entry_executable_bit | x86_64::gdt::entry_descriptor_type_bit | x86_64::gdt::entry_present_bit | x86_64::gdt::entry_64bit_code_bit); // Kernel Code 13 | this->add_entry(x86_64::gdt::entry_executable_bit | x86_64::gdt::entry_descriptor_type_bit | x86_64::gdt::entry_present_bit | x86_64::gdt::entry_64bit_code_bit | ((1ull << 45) | (1ull << 46))); // User Code 14 | this->add_entry(x86_64::gdt::entry_read_write_bit | x86_64::gdt::entry_descriptor_type_bit | x86_64::gdt::entry_present_bit | ((1ull << 45) | (1ull << 46))); // User Code 15 | 16 | this->pointer.pointer = (uint64_t)&this->entries; 17 | this->pointer.size = (sizeof(x86_64::gdt::entry) * x86_64::gdt::max_entries) - 1; 18 | this->update_pointer(); 19 | flush_gdt(); 20 | } 21 | 22 | uint64_t x86_64::gdt::gdt::add_entry(uint64_t flags){ 23 | this->entries[this->entry_index++] = x86_64::gdt::entry(flags); 24 | return this->get_offset_by_index((this->entry_index - 1)); 25 | } 26 | 27 | uint64_t x86_64::gdt::gdt::add_tss(x86_64::tss::table& tss){ 28 | uint64_t tss_address = reinterpret_cast(&tss); 29 | 30 | uint32_t tss_size = (sizeof(x86_64::tss::table) - 1); 31 | //uint32_t tss_entry_type = 0x8900; 32 | 33 | uint32_t ent1_low = (tss_size & 0xFFFF) | ((tss_address & 0xFFFF) << 16); 34 | uint32_t ent1_high = ((tss_address >> 16) & 0xFF) | ((1ULL << 8) | (1ULL << 11) | (1ULL << 15)) | (tss_size & 0x000F0000) | (tss_address & 0xFF000000); 35 | 36 | uint32_t ent2_low = (tss_address >> 32); 37 | uint32_t ent2_high = 0; 38 | 39 | uint64_t ent1 = (ent1_low | ((uint64_t)ent1_high << 32)); 40 | uint64_t ent2 = (ent2_low | ((uint64_t)ent2_high << 32)); 41 | 42 | 43 | uint64_t offset = this->entry_index; 44 | this->entries[offset] = x86_64::gdt::entry(ent1); 45 | this->entries[offset + 1] = x86_64::gdt::entry(ent2); 46 | this->entry_index += 2; 47 | 48 | return this->get_offset_by_index(offset); 49 | } 50 | 51 | uint64_t x86_64::gdt::gdt::get_offset_by_index(uint64_t index){ 52 | return index * sizeof(x86_64::gdt::entry); 53 | } -------------------------------------------------------------------------------- /kernel/source/arch/x86_64/intel/sl_paging.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static std::pair create_table(){ 5 | uint64_t phys = (uint64_t)mm::pmm::alloc_block(); 6 | uint64_t virt = phys + KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE; 7 | mm::vmm::kernel_vmm::get_instance().map_page(phys, virt, map_page_flags_present | map_page_flags_writable | map_page_flags_no_execute); 8 | memset_aligned_4k((void*)virt, 0); 9 | 10 | return {phys, virt}; 11 | } 12 | 13 | static void delete_table(uint64_t phys){ 14 | mm::pmm::free_block((void*)phys); 15 | } 16 | 17 | x86_64::sl_paging::context::context(uint8_t level): level{level} { 18 | ASSERT(level <= 5 && level >= 3); 19 | const auto [phys, _] = create_table(); 20 | 21 | this->phys_root = phys; 22 | } 23 | 24 | static void clean_tables(uint64_t phys, uint8_t level){ 25 | auto virt = phys + KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE; 26 | auto& pml = *(x86_64::sl_paging::sl_pml*)virt; 27 | if(level >= 3){ 28 | for(size_t i = 0; i < 512; i++) 29 | if(pml[i].r) 30 | clean_tables(pml[i].addr << 12, level - 1); 31 | } else { 32 | for(size_t i = 0; i < 512; i++) 33 | if(pml[i].r) 34 | delete_table(pml[i].addr << 12); 35 | } 36 | delete_table(phys); 37 | } 38 | 39 | x86_64::sl_paging::context::~context(){ 40 | clean_tables(this->phys_root, this->level); 41 | } 42 | 43 | void x86_64::sl_paging::context::map(uint64_t pa, uint64_t iova, uint64_t flags){ 44 | uint64_t pml5_i = (iova >> 48) & 0x1FF; 45 | uint64_t pml4_i = (iova >> 39) & 0x1FF; 46 | uint64_t pml3_i = (iova >> 30) & 0x1FF; 47 | uint64_t pml2_i = (iova >> 21) & 0x1FF; 48 | uint64_t pml1_i = (iova >> 12) & 0x1FF; 49 | 50 | auto get_level_or_create = [](sl_pml* previous, uint64_t index) -> sl_pml* { 51 | auto& entry = (*previous)[index]; 52 | if(!entry.r){ 53 | const auto [phys, _] = create_table(); 54 | entry.addr = (phys >> 12); 55 | entry.r = 1; 56 | entry.w = 1; 57 | } 58 | 59 | return (sl_pml*)((entry.addr << 12) + KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE); 60 | }; 61 | 62 | auto* current = (sl_pml*)(this->phys_root + KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE); 63 | if(level >= 5) 64 | current = get_level_or_create(current, pml5_i); 65 | if(level >= 4) 66 | current = get_level_or_create(current, pml4_i); 67 | current = get_level_or_create(current, pml3_i); 68 | current = get_level_or_create(current, pml2_i); 69 | 70 | auto& pml1 = *(sl_pml1*)current; 71 | auto& pml1_e = pml1[pml1_i]; 72 | 73 | pml1_e.r = (flags & mapSlPageRead) ? 1 : 0; 74 | pml1_e.w = (flags & mapSlPageWrite) ? 1 : 0; 75 | pml1_e.x = (flags & mapSlPageExecute) ? 1 : 0; 76 | pml1_e.frame = (pa >> 12); 77 | } 78 | 79 | uint64_t x86_64::sl_paging::context::get_ptr(){ 80 | return this->phys_root; 81 | } -------------------------------------------------------------------------------- /kernel/source/arch/x86_64/io.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | uint8_t x86_64::io::inb(uint16_t port){ 4 | uint8_t ret; 5 | asm volatile ("in %1, %0" : "=a"(ret) : "Nd"(port)); 6 | return ret; 7 | } 8 | 9 | void x86_64::io::outb(uint16_t port, uint8_t value){ 10 | asm volatile ("out %0, %1" : : "a"(value), "Nd"(port)); 11 | } 12 | 13 | uint16_t x86_64::io::inw(uint16_t port){ 14 | uint16_t ret; 15 | asm volatile ("in %1, %0" : "=a"(ret) : "Nd"(port)); 16 | return ret; 17 | } 18 | 19 | void x86_64::io::outw(uint16_t port, uint16_t value){ 20 | asm volatile ("out %0, %1" : : "a"(value), "Nd"(port)); 21 | } 22 | 23 | uint32_t x86_64::io::ind(uint16_t port){ 24 | uint32_t ret; 25 | asm volatile ("in %1, %0" : "=a"(ret) : "Nd"(port)); 26 | return ret; 27 | } 28 | 29 | void x86_64::io::outd(uint16_t port, uint32_t value){ 30 | asm volatile ("out %0, %1" : : "a"(value), "Nd"(port)); 31 | } -------------------------------------------------------------------------------- /kernel/source/arch/x86_64/misc/misc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | bool x86_64::cpuid(uint32_t leaf, uint32_t& eax, uint32_t& ebx, uint32_t& c, uint32_t& d){ 7 | return __get_cpuid(leaf, &eax, &ebx, &c, &d); 8 | } 9 | 10 | bool x86_64::cpuid(uint32_t leaf, uint32_t subleaf, uint32_t& eax, uint32_t& ebx, uint32_t& c, uint32_t& d){ 11 | return __get_cpuid_count(leaf, subleaf, &eax, &ebx, &c, &d); 12 | } 13 | 14 | uint64_t x86_64::read_tsc(){ 15 | uint64_t tsc_low = 0; 16 | uint64_t tsc_high = 0; 17 | asm ("rdtsc" : "=a"(tsc_low), "=d"(tsc_high)); 18 | return (tsc_low | (tsc_high << 32)); 19 | } -------------------------------------------------------------------------------- /kernel/source/arch/x86_64/misc/spinlock.asm: -------------------------------------------------------------------------------- 1 | bits 64 2 | 3 | section .text 4 | 5 | global acquire 6 | acquire: 7 | push rbp 8 | mov rbp, rsp 9 | 10 | lock bts word [rdi], 0 11 | jnc .acquired 12 | 13 | .retry: 14 | pause 15 | 16 | bt word [rdi], 0 17 | jc .retry 18 | 19 | lock bts word [rdi], 0 20 | jc .retry 21 | 22 | .acquired: 23 | mov rsp, rbp 24 | pop rbp 25 | ret 26 | 27 | global release 28 | release: 29 | push rbp 30 | mov rbp, rsp 31 | 32 | lock btr word [rdi], 0 33 | 34 | mov rsp, rbp 35 | pop rbp 36 | ret 37 | 38 | global try_acquire 39 | try_acquire: 40 | push rbp 41 | mov rbp, rsp 42 | 43 | mov rax, 1 44 | 45 | lock bts word [rdi], 0 46 | jnc .success 47 | 48 | mov rax, 0 49 | .success: 50 | mov rsp, rbp 51 | pop rbp 52 | ret -------------------------------------------------------------------------------- /kernel/source/arch/x86_64/msr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | uint64_t x86_64::msr::read(uint32_t msr){ 4 | uint64_t val_low = 0; 5 | uint64_t val_high = 0; 6 | asm ("rdmsr" : "=a"(val_low), "=d"(val_high) : "c"(msr)); 7 | return (val_low | (val_high << 32)); 8 | } 9 | 10 | void x86_64::msr::write(uint32_t msr, uint64_t val){ 11 | uint32_t val_low = (val & 0xFFFFFFFF); 12 | uint32_t val_high = ((val >> 32) & 0xFFFFFFFF); 13 | asm("wrmsr" : : "a"(val_low), "d"(val_high), "c"(msr)); 14 | } -------------------------------------------------------------------------------- /kernel/source/crti.S: -------------------------------------------------------------------------------- 1 | .section .init_start 2 | .global _init 3 | .type _init, @function 4 | _init: 5 | push %rbp 6 | movq %rsp, %rbp 7 | 8 | .section .fini_start 9 | .global _fini 10 | .type _fini, @function 11 | _fini: 12 | push %rbp 13 | movq %rsp, %rbp 14 | -------------------------------------------------------------------------------- /kernel/source/crtn.S: -------------------------------------------------------------------------------- 1 | .section .init_end 2 | popq %rbp 3 | ret 4 | 5 | .section .fini_end 6 | popq %rbp 7 | ret 8 | -------------------------------------------------------------------------------- /kernel/source/kernel_early.asm: -------------------------------------------------------------------------------- 1 | [bits 64] 2 | 3 | section .text 4 | 5 | initialize_sse: 6 | mov eax, 1 7 | cpuid 8 | bt edx, 25 9 | jnc .no_sse 10 | 11 | mov rax, cr0 12 | btr eax, 2 13 | bts eax, 1 14 | mov cr0, rax 15 | 16 | mov rax, cr4 17 | bts eax, 9 18 | bts eax, 10 19 | mov cr4, rax 20 | 21 | ret 22 | 23 | .no_sse: 24 | ret 25 | 26 | initialize_osxsave: 27 | mov eax, 1 28 | cpuid 29 | bt ecx, 26 30 | jnc .no_osxsave 31 | 32 | mov rax, cr4 33 | bts rax, 18 ; Set OSXSAVE bit for access to xgetbv and xsetbv and possibly xsave, xsaveopt and xrestor 34 | mov cr4, rax 35 | 36 | ret 37 | 38 | .no_osxsave: 39 | ret 40 | 41 | initialize_efer: 42 | mov ecx, 0xC0000080 ; IA32_EFER 43 | rdmsr 44 | bts eax, 0 ; Set SCE for the syscall and sysret instructions 45 | bts eax, 11 ; Set NXE for No-Execute-Support 46 | ; LME and thus LMA are already set by the bootloader 47 | wrmsr 48 | 49 | ret 50 | 51 | initialize_cr0: 52 | mov rax, cr0 53 | bts rax, 16 ; Set Write Protect bit so the CPU will enfore the Writable paging bit in kernel mode 54 | mov cr0, rax 55 | 56 | ret 57 | 58 | initialize_cr4: 59 | xor rax, rax 60 | mov eax, 1 61 | cpuid 62 | bt edx, 13 63 | jnc .no_pge 64 | 65 | mov rax, cr4 66 | bts rax, 7 ; Set Page Global Enable 67 | mov cr4, rax 68 | 69 | .no_pge: 70 | ret 71 | 72 | global _kernel_early 73 | _kernel_early: 74 | cld 75 | cli 76 | 77 | mov rsp, bsp_stack_top 78 | and rsp, ~8 ; Make sure rsp + 8 is 16 byte aligned as mandated by the SysV ABI 79 | mov rbp, 0 ; Set to zero to provide stack trace stop 80 | 81 | call initialize_sse 82 | call initialize_osxsave 83 | call initialize_efer 84 | call initialize_cr0 85 | call initialize_cr4 86 | 87 | extern _init 88 | call _init 89 | 90 | extern kernel_main 91 | call kernel_main 92 | 93 | extern _fini 94 | call _fini 95 | 96 | cli 97 | 98 | hlt 99 | 100 | global _smp_kernel_early 101 | _smp_kernel_early: 102 | cli 103 | cld 104 | 105 | mov rax, qword [trampoline_paging] 106 | mov cr3, rax 107 | 108 | mov rsp, qword [trampoline_stack] 109 | and rsp, ~0xF ; Align stack for ABI requirements 110 | mov rbp, 0 ; Set to zero to provide stack trace stop 111 | 112 | mov byte [trampoline_booted], 1 113 | 114 | call initialize_sse 115 | call initialize_osxsave 116 | call initialize_efer 117 | call initialize_cr0 118 | call initialize_cr4 119 | 120 | extern smp_kernel_main 121 | call smp_kernel_main 122 | 123 | cli 124 | hlt 125 | 126 | 127 | section .data 128 | 129 | global trampoline_stack 130 | trampoline_stack: dq 0 131 | global trampoline_paging 132 | trampoline_paging: dq 0 133 | global trampoline_booted 134 | trampoline_booted: db 0 135 | 136 | section .bss 137 | 138 | align 16 139 | bsp_stack_bottom: 140 | resb 0x8000 141 | bsp_stack_top: -------------------------------------------------------------------------------- /kernel/source/klibc/stdlib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | char* itoa(int64_t value, char* str, int base){ 8 | char* rc, *ptr, *low; 9 | 10 | if(base < 2 || base > 36){ 11 | *str = '\0'; 12 | return str; 13 | } 14 | 15 | rc = ptr = str; 16 | 17 | if(value < 0 && base == 10) *ptr++ = '-'; 18 | 19 | low = ptr; 20 | 21 | do 22 | { 23 | *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + value % base]; 24 | value /= base; 25 | } while (value); 26 | 27 | *ptr-- = '\0'; 28 | 29 | while(low < ptr){ 30 | char tmp = *low; 31 | *low++ = *ptr; 32 | *ptr-- = tmp; 33 | } 34 | return rc; 35 | } 36 | 37 | void htoa(int64_t n, char* str){ 38 | *str++ = '0'; 39 | *str++ = 'x'; 40 | 41 | int8_t zeros = 0; 42 | int64_t tmp; 43 | for(int i = 60; i > 0; i -= 4){ 44 | tmp = (n >> i) & 0xF; 45 | if(tmp == 0 && zeros == 0) continue; 46 | 47 | zeros -= 1; 48 | 49 | if(tmp >= 0xA) *str++ = (tmp - 0xA + 'a'); 50 | else *str++ = (tmp + '0'); 51 | } 52 | 53 | tmp = n & 0xF; 54 | 55 | if(tmp >= 0xA) *str++ = (tmp - 0xA + 'a'); 56 | else *str++ = (tmp + '0'); 57 | } 58 | 59 | void abort(void){ 60 | printf("Kernel panic, abort\n"); 61 | asm("cli; hlt"); 62 | __builtin_unreachable(); 63 | } 64 | 65 | NODISCARD_ATTRIBUTE 66 | void *malloc(size_t size){ 67 | return mm::hmm::kmalloc(size); 68 | } 69 | 70 | NODISCARD_ATTRIBUTE 71 | void *realloc(void* ptr, size_t size){ 72 | return mm::hmm::realloc(ptr, size); 73 | } 74 | 75 | void free(void* ptr){ 76 | mm::hmm::kfree(ptr); 77 | } -------------------------------------------------------------------------------- /kernel/source/klibc/string.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | size_t strlen(const char* s){ 4 | size_t len = 0; 5 | while(s[len]) len++; 6 | return len; 7 | } 8 | 9 | char *strcpy(char *dest, const char *src) { 10 | //while(*src) 11 | // *(dest++) = *(src++); 12 | //*dest = 0; 13 | //return dest; 14 | return (char*)memcpy((void*)dest, (void*)src, strlen(src) + 1); 15 | } 16 | 17 | void* memset(void* s, int c, size_t n){ 18 | uint8_t* buf = (uint8_t*)s; 19 | 20 | for(size_t i = 0; i < n; i++) buf[i] = (uint8_t)c; 21 | 22 | return s; 23 | //asm("rep stosb" : : "a"(c), "D"((uint64_t)s), "c"(n) : "memory"); 24 | //return s; 25 | } 26 | 27 | int memcmp(const void* s1, const void* s2, size_t n){ 28 | const uint8_t* a = (const uint8_t*)s1; 29 | const uint8_t* b = (const uint8_t*)s2; 30 | 31 | for(size_t i = 0; i < n; i++){ 32 | if(a[i] < b[i]) return -1; 33 | else if(b[i] < a[i]) return 1; 34 | } 35 | 36 | return 0; 37 | } 38 | 39 | void* memcpy(void* dest, const void* src, size_t n){ 40 | uint8_t* destination = (uint8_t*)dest; 41 | uint8_t* source = (uint8_t*)src; 42 | 43 | for(size_t i = 0; i < n; i++) destination[i] = source[i]; 44 | 45 | return dest; 46 | //asm("rep movsb" : : "S"((uint64_t)src), "D"((uint64_t)dest), "c"(n) : "memory"); 47 | //return dest; 48 | } 49 | 50 | void* memmove(void* dstptr, const void* srcptr, size_t size) { 51 | unsigned char* dst = (unsigned char*) dstptr; 52 | const unsigned char* src = (const unsigned char*) srcptr; 53 | if (dst < src) { 54 | for (size_t i = 0; i < size; i++) 55 | dst[i] = src[i]; 56 | } else { 57 | for (size_t i = size; i != 0; i--) 58 | dst[i-1] = src[i-1]; 59 | } 60 | return dstptr; 61 | } 62 | 63 | int strcmp(const char s1[], const char s2[]) { 64 | for (; *s1 == *s2 && *s1; s1++, s2++) 65 | ; 66 | return *(unsigned char *)s1 - *(unsigned char *)s2; 67 | } 68 | 69 | void* memset_aligned_4k(void* dest, int c){ 70 | //asm("rep stosl" : : "a"(c), "D"((uint64_t)dest), "c"(1024) : "memory"); 71 | memset(dest, c, 0x1000); 72 | return dest; 73 | } 74 | 75 | void* memcpy_aligned_4k(void* dest, void* src){ 76 | //asm("rep movsd" : : "S"((uint64_t)src), "D"((uint64_t)dest), "c"(1024) : "memory"); 77 | memcpy(dest, src, 0x1000); 78 | return dest; 79 | } -------------------------------------------------------------------------------- /kernel/source/misc/cpp_support.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" void __cxa_pure_virtual(){ 5 | printf("__cxa_pure_virtual() called"); 6 | asm("cli; hlt"); 7 | } 8 | 9 | // This function is intended to register a global destructor handle to be called on exit() 10 | // However this is a kernel, and if it tries to exit via exit() or whatever something is seriously wrong 11 | // So we can safely ignore it 12 | // Something something https://wiki.osdev.org/C%2B%2B#Global_objects 13 | extern "C" int __cxa_atexit(void (*func) (void *), void * arg, void * dso_handle){ 14 | (void)(func); 15 | (void)(arg); 16 | (void)(dso_handle); 17 | return 1; 18 | } 19 | 20 | extern "C" int __cxxabiv1::__cxa_guard_acquire(__guard *g){ 21 | x86_64::spinlock::acquire(reinterpret_cast(g)); 22 | return *reinterpret_cast(g); 23 | } 24 | 25 | extern "C" void __cxxabiv1::__cxa_guard_release(__guard *g){ 26 | x86_64::spinlock::release(reinterpret_cast(g)); 27 | } 28 | 29 | extern "C" void __cxxabiv1::__cxa_guard_abort(__guard *g){ 30 | PANIC("__cxa_guard_abort was called\n"); 31 | (void)(g); 32 | asm("cli; hlt"); 33 | } 34 | 35 | void* operator new(size_t size){ 36 | return malloc(size); 37 | } 38 | 39 | void* operator new[](size_t size){ 40 | return malloc(size); 41 | } 42 | 43 | void operator delete(void* p){ 44 | free(p); 45 | } 46 | 47 | void operator delete[](void* p){ 48 | free(p); 49 | } 50 | 51 | void operator delete(void* p, long unsigned int size){ 52 | (void)(size); 53 | free(p); 54 | } 55 | 56 | void operator delete[](void* p, long unsigned int size){ 57 | (void)(size); 58 | free(p); 59 | } -------------------------------------------------------------------------------- /kernel/source/misc/misc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | char* str_int; 8 | uint64_t n_pairs; 9 | 10 | void misc::kernel_args::init(char* str){ 11 | n_pairs = 0; 12 | size_t len = strlen(str); 13 | for(uint64_t i = 0; i < len; i++){ 14 | if(str[i] == ' ' || str[i] == '\0'){ 15 | str[i] = '\0'; 16 | n_pairs++; 17 | } 18 | } 19 | 20 | if(len != 0) n_pairs++; // Add last one if not empty 21 | 22 | str_int = str; 23 | } 24 | 25 | bool misc::kernel_args::get_bool(const char* key){ 26 | char* current = str_int; 27 | for(uint64_t i = 0; i < n_pairs; i++){ 28 | if(memcmp(static_cast(current), static_cast(key), misc::min(strlen(current), strlen(key))) == 0) 29 | return true; 30 | 31 | current += strlen(current) + 1; 32 | } 33 | return false; 34 | } 35 | 36 | const char* misc::kernel_args::get_str(const char* key){ 37 | char* current = str_int; 38 | for(uint64_t i = 0; i < n_pairs; i++){ 39 | if(memcmp(static_cast(current), static_cast(key), misc::min(strlen(current), strlen(key))) == 0) 40 | return current + strlen(key) + 1; // Skip key + equal sign 41 | 42 | current += strlen(current) + 1; 43 | } 44 | return nullptr; 45 | } -------------------------------------------------------------------------------- /kernel/source/misc/panic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | NORETURN_ATTRIBUTE 7 | void misc::panic::panic_m(const char* message, std::experimental::source_location loc){ 8 | printf("KERNEL PANIC in file: %s in function %s on line: %d: %s\n", loc.file_name(), loc.function_name(), loc.line(), message); 9 | debug::trace_stack(); 10 | abort(); 11 | } 12 | 13 | NORETURN_ATTRIBUTE 14 | void misc::panic::panic_m(const char* message, const char* function_override, std::experimental::source_location loc){ 15 | printf("KERNEL PANIC in file: %s in function %s on line: %d: %s\n", loc.file_name(), function_override, loc.line(), message); 16 | debug::trace_stack(); 17 | abort(); 18 | } -------------------------------------------------------------------------------- /kernel/source/mm/hmm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void mm::hmm::init(){ 4 | alloc::init(); 5 | } 6 | 7 | NODISCARD_ATTRIBUTE 8 | void* mm::hmm::kmalloc(size_t size){ 9 | return alloc::alloc(size); 10 | } 11 | 12 | NODISCARD_ATTRIBUTE 13 | void* mm::hmm::kmalloc_a(size_t size, uint64_t align){ 14 | return alloc::alloc_a(size, align); 15 | } 16 | 17 | void mm::hmm::kfree(void* ptr){ 18 | alloc::free(ptr); 19 | } 20 | 21 | NODISCARD_ATTRIBUTE 22 | void* mm::hmm::realloc(void* ptr, size_t size){ 23 | return alloc::realloc(ptr, size); 24 | } -------------------------------------------------------------------------------- /kernel/source/mm/vmm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | misc::lazy_initializer instance; 4 | 5 | x86_64::paging::context& mm::vmm::kernel_vmm::_instance(){ 6 | if(!instance){ 7 | instance.init(); 8 | instance->init(); 9 | } 10 | 11 | return *instance; 12 | } -------------------------------------------------------------------------------- /kernel/source/proc/initrd.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static misc::lazy_initializer> headers; 8 | 9 | static uint64_t get_header_number(const char* in){ 10 | size_t size = 0; 11 | uint64_t count = 1; 12 | 13 | for(uint64_t j = 11; j > 0; j--, count *= 8){ 14 | size += ((in[j - 1] - '0') * count); 15 | } 16 | 17 | return size; 18 | } 19 | 20 | static std::mutex initrd_lock{}; 21 | 22 | void proc::initrd::init(uint64_t address, uint64_t size){ 23 | std::lock_guard lock{initrd_lock}; 24 | 25 | headers.init(); 26 | for(uint64_t i = 0; i < size; i++){ 27 | auto* header = reinterpret_cast(address); 28 | 29 | if(header->filename[0] == '\0') break; // Invalid header 30 | uint64_t entry_size = get_header_number(header->size); 31 | 32 | headers->push_back(header); 33 | 34 | address += ((entry_size / 512) + 1) * 512; 35 | if(entry_size % 512) address += 512; 36 | } 37 | } 38 | 39 | bool proc::initrd::read_file(const char* file_name, uint8_t* buf, uint64_t offset, uint64_t size){ 40 | if((size + offset) > proc::initrd::get_size(file_name) + 1) 41 | return false; // Yeah lol no, that would be a bit *too* easy wouldn't it 42 | 43 | std::lock_guard lock{initrd_lock}; 44 | for(auto* header : *headers){ 45 | if(strcmp(header->filename, file_name) == 0){ 46 | // Found it 47 | void* data = static_cast(static_cast(static_cast(header)) + 512 + offset); 48 | 49 | memcpy(static_cast(buf), data, size); 50 | 51 | return true; 52 | } 53 | } 54 | return false; 55 | } 56 | 57 | size_t proc::initrd::get_size(const char* file_name){ 58 | std::lock_guard lock{initrd_lock}; 59 | for(auto* header : *headers){ 60 | if(strcmp(header->filename, file_name) == 0){ 61 | return get_header_number(header->size); 62 | } 63 | } 64 | 65 | return 0; 66 | } -------------------------------------------------------------------------------- /kernel/source/proc/process_low.asm: -------------------------------------------------------------------------------- 1 | [bits 64] 2 | 3 | section .text 4 | 5 | global proc_idle 6 | proc_idle: 7 | mov rsp, rdi ; Switch stacks 8 | 9 | sti 10 | idle_loop: 11 | hlt ; Wait for next interrupt 12 | 13 | jmp idle_loop 14 | 15 | global xsave_int 16 | xsave_int: 17 | push rax 18 | push rdx 19 | 20 | xor rax, rax 21 | xor rdx, rdx 22 | mov eax, 0xFFFFFFFF ; Set the Requested Feature BitMap (RFBM) to enable all functions enabled in xcr0 23 | mov edx, 0xFFFFFFFF 24 | 25 | xsave [rdi] 26 | 27 | pop rdx 28 | pop rax 29 | ret 30 | 31 | global xrstor_int 32 | xrstor_int: 33 | push rax 34 | push rdx 35 | 36 | xor rax, rax 37 | xor rdx, rdx 38 | mov eax, 0xFFFFFFFF ; Set the Requested Feature BitMap (RFBM) to enable all functions enabled in xcr0 39 | mov edx, 0xFFFFFFFF 40 | 41 | xrstor [rdi] 42 | 43 | pop rdx 44 | pop rdx 45 | ret 46 | ;global syscall_entry 47 | ;syscall_entry: 48 | ; TODO 49 | ; sysret -------------------------------------------------------------------------------- /kernel/source/proc/simd.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | C_LINKAGE void xsave_int(uint8_t* state); 8 | C_LINKAGE void xrstor_int(uint8_t* state); 9 | 10 | using save_func = void (*)(uint8_t* state); 11 | using restore_func = void (*)(uint8_t* state); 12 | 13 | static save_func global_save; 14 | static restore_func global_restore; 15 | 16 | static uint8_t* default_state = nullptr; 17 | static uint64_t save_size = 0; 18 | static uint64_t save_align = 0; 19 | 20 | void proc::simd::simd_state::init(){ 21 | if(!data){ 22 | data = static_cast(mm::hmm::kmalloc_a(save_size, save_align)); 23 | if(!data) 24 | PANIC("Couldn't allocate data for simd_state"); 25 | 26 | #ifdef DEBUG 27 | if(((uint64_t)data % save_align) != 0) 28 | PANIC("mm::hmm::kmalloc_a didn't allocate sufficiently aligned pointer"); 29 | #endif 30 | } 31 | 32 | memcpy(data, default_state, save_size); 33 | } 34 | 35 | void proc::simd::simd_state::deinit(){ 36 | if(data) { 37 | mm::hmm::kfree(data); 38 | data = nullptr; 39 | } 40 | } 41 | 42 | void proc::simd::simd_state::save(){ 43 | if(!data) 44 | init(); 45 | 46 | global_save(data); 47 | } 48 | 49 | void proc::simd::simd_state::restore(){ 50 | if(!data) 51 | init(); 52 | 53 | global_restore(data); 54 | } 55 | 56 | proc::simd::simd_state& proc::simd::simd_state::operator=(const simd_state& state){ 57 | init(); 58 | 59 | memcpy(data, state.data, save_size); 60 | 61 | return *this; 62 | } 63 | 64 | void proc::simd::init(){ 65 | uint32_t a1, b1, c1, d1; 66 | if(!x86_64::cpuid(1, a1, b1, c1, d1)) 67 | PANIC("Default CPUID leaf does not exist"); 68 | 69 | if(c1 & x86_64::cpuid_bits::XSAVE){ 70 | uint32_t a2, b2, c2, d2; 71 | if(!x86_64::cpuid(0xD, 0, a2, b2, c2, d2)) 72 | PANIC("XSAVE exists but CPUID leaf 0xD doesnt exist"); 73 | 74 | save_size = c2; 75 | save_align = 64; 76 | 77 | global_save = xsave_int; 78 | global_restore = xrstor_int; 79 | 80 | debug_printf("[PROC]: Initializing SIMD saving mechanism with xsave, size: %x\n", save_size); 81 | } else if(d1 & x86_64::cpuid_bits::FXSAVE){ 82 | save_size = 512; 83 | save_align = 16; 84 | 85 | global_save = +[](uint8_t* state){ asm("fxsave %0" : : "m"(*state)); }; 86 | global_restore = +[](uint8_t* state){ asm("fxrstor %0" : : "m"(*state)); }; 87 | 88 | debug_printf("[PROC]: Initializing SIMD saving mechanism with fxsave, size: %x\n", save_size); 89 | } else { 90 | PANIC("no known SIMD save mechanism available"); 91 | } 92 | 93 | default_state = static_cast(mm::hmm::kmalloc_a(save_size, save_align)); 94 | memset(static_cast(default_state), 0, save_size); 95 | auto* tmp = reinterpret_cast(default_state); 96 | 97 | tmp->fcw |= 1 << 0; // Set Invalid Operation Mask 98 | tmp->fcw |= 1 << 1; // Set Denormal Operand Mask 99 | tmp->fcw |= 1 << 2; // Set Divide by Zero Mask 100 | tmp->fcw |= 1 << 3; // Set Overflow Mask 101 | tmp->fcw |= 1 << 4; // Set Underflow Mask 102 | tmp->fcw |= 1 << 5; // Set Precision Mask 103 | tmp->fcw |= (1 << 8) | (1 << 9); // Set Double Extended Precision 104 | 105 | tmp->mxcsr |= 1 << 7; // Set Invalid Operation Mask 106 | tmp->mxcsr |= 1 << 8; // Set Denormal Mask 107 | tmp->mxcsr |= 1 << 9; // Set Divide by Zero Mask 108 | tmp->mxcsr |= 1 << 10; // Set Overflow Mask 109 | tmp->mxcsr |= 1 << 11; // Set Underflow Mask 110 | tmp->mxcsr |= 1 << 12; // Set Precision Mask 111 | } -------------------------------------------------------------------------------- /kernel/source/smp/gs.asm: -------------------------------------------------------------------------------- 1 | global get_current_cpu 2 | get_current_cpu: 3 | mov rax, qword [gs:0] 4 | ret -------------------------------------------------------------------------------- /kernel/source/smp/ipi.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | #pragma region tlb_shootdown 6 | 7 | static uint64_t shootdown_addr = 0; 8 | static uint64_t shootdown_length = 0; 9 | 10 | auto shootdown_mutex = x86_64::spinlock::mutex(); 11 | 12 | void smp::ipi::send_shootdown(uint64_t address, uint64_t length){ 13 | std::lock_guard guard{shootdown_mutex}; 14 | shootdown_addr = address; 15 | shootdown_length = length; 16 | debug_printf("[IPI]: Requested TLB shootdown on addr: %x, length: %x\n", shootdown_addr, shootdown_length); 17 | smp::cpu::get_current_cpu()->lapic.send_ipi_raw(0, ((1 << 19) | smp::ipi::shootdown_ipi_vector)); // All including self 18 | } 19 | 20 | 21 | 22 | static void shootdown_ipi(MAYBE_UNUSED_ATTRIBUTE x86_64::idt::idt_registers* regs, MAYBE_UNUSED_ATTRIBUTE void* userptr) { 23 | for(uint64_t offset = 0; offset < shootdown_length; offset += mm::pmm::block_size) { 24 | x86_64::paging::invalidate_addr(shootdown_addr + offset); 25 | } 26 | } 27 | 28 | #pragma endregion 29 | 30 | #pragma region ping 31 | 32 | void smp::ipi::send_ping(uint32_t apic_id){ 33 | smp::cpu::get_current_cpu()->lapic.send_ipi(apic_id, smp::ipi::ping_ipi_vector); 34 | } 35 | 36 | void smp::ipi::send_ping(){ 37 | smp::cpu::get_current_cpu()->lapic.send_ipi_raw(0, ((1 << 19) | (1 << 18) | smp::ipi::ping_ipi_vector)); // All excluding self 38 | } 39 | 40 | static void ping_ipi(MAYBE_UNUSED_ATTRIBUTE x86_64::idt::idt_registers* regs, MAYBE_UNUSED_ATTRIBUTE void* userptr) { 41 | debug_printf("[IPI]: Pong from cpu: %x\n", smp::cpu::get_current_cpu()->lapic_id); 42 | } 43 | 44 | #pragma endregion 45 | 46 | void smp::ipi::init_ipi(){ 47 | x86_64::idt::register_interrupt_handler({.vector = smp::ipi::ping_ipi_vector, .callback = ping_ipi, .is_irq = true}); 48 | x86_64::idt::register_interrupt_handler({.vector = smp::ipi::shootdown_ipi_vector, .callback = shootdown_ipi, .is_irq = true}); 49 | } -------------------------------------------------------------------------------- /kernel/source/smp/smp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static bool wait_for_boot(){ 4 | uint8_t* trampoline_booted_addr = &smp::trampoline_booted; 5 | 6 | uint64_t timeout = 100; 7 | while(timeout > 0){ 8 | if(*trampoline_booted_addr == 1) return true; 9 | 10 | for(size_t i = 0; i < 100000; i++) asm("nop"); // TODO: Real timeout 11 | 12 | timeout--; 13 | } 14 | 15 | return false; 16 | } 17 | 18 | static void clear_booted_flag(){ 19 | uint8_t* trampoline_booted_addr = &smp::trampoline_booted; 20 | *trampoline_booted_addr = 0; 21 | } 22 | 23 | void smp::multiprocessing::boot_apic(smp::cpu_entry& cpu){ 24 | auto& lapic = smp::cpu::get_current_cpu()->lapic; 25 | lapic.send_ipi_raw(cpu.lapic_id, (x86_64::apic::lapic_icr_tm_level | x86_64::apic::lapic_icr_levelassert | x86_64::apic::lapic_icr_dm_init)); 26 | //this->send_ipi_raw(cpu.lapic_id, (x86_64::apic::lapic_icr_tm_level | x86_64::apic::lapic_icr_dm_init)); 27 | lapic.send_ipi_raw(cpu.lapic_id, (x86_64::apic::lapic_icr_dm_sipi | ((smp::smp_trampoline_base >> 12) & 0xFF))); 28 | if(!wait_for_boot()) lapic.send_ipi_raw(cpu.lapic_id, (x86_64::apic::lapic_icr_dm_sipi | ((smp::smp_trampoline_base >> 12) & 0xFF))); 29 | } 30 | 31 | C_LINKAGE uint64_t trampoline_stack; 32 | C_LINKAGE uint64_t trampoline_paging; 33 | C_LINKAGE uint8_t trampoline_booted; 34 | 35 | void smp::multiprocessing::boot_cpu(cpu_entry& e){ 36 | constexpr size_t ap_stack_size = 4; 37 | 38 | uint64_t* trampoline_stack_addr = &smp::trampoline_stack; 39 | void* cpu_stack = mm::pmm::alloc_n_blocks(ap_stack_size); // 16kb stack 40 | if(cpu_stack == nullptr){ 41 | debug_printf("Failed to allocate stack for CPU with lapic_id: %d\n", e.lapic_id); 42 | return; 43 | } 44 | 45 | *trampoline_stack_addr = (reinterpret_cast(cpu_stack) + (mm::pmm::block_size * ap_stack_size) + KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE); 46 | 47 | uint64_t* trampoline_paging_addr = &smp::trampoline_paging; 48 | *trampoline_paging_addr = (mm::vmm::kernel_vmm::get_instance().get_paging_info() - KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE); 49 | 50 | this->boot_apic(e); 51 | 52 | if(wait_for_boot()){ 53 | debug_printf("[SMP]: Booted CPU with lapic_id: %d, stack: %x\n", e.lapic_id, *trampoline_stack_addr); 54 | } else { 55 | debug_printf("[SMP]: Failed to boot CPU with lapic_id: %d\n TODO: Implement multiframe freeing\n", e.lapic_id); 56 | } 57 | 58 | clear_booted_flag(); // Clear flag for next CPU 59 | } 60 | 61 | smp::multiprocessing::multiprocessing(types::linked_list& cpus): cpus{cpus} { 62 | uint64_t trampoline_start_addr = (uint64_t)&trampoline_start; 63 | uint64_t trampoline_end_addr = (uint64_t)&trampoline_end; 64 | 65 | for(uint64_t i = 0; i < (trampoline_end_addr - trampoline_start_addr); i += mm::pmm::block_size) 66 | mm::vmm::kernel_vmm::get_instance().map_page(smp::smp_trampoline_base + i, (smp::smp_trampoline_base + KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE + i), map_page_flags_present | map_page_flags_writable); 67 | 68 | memcpy(reinterpret_cast(smp::smp_trampoline_base + KERNEL_PHYSICAL_VIRTUAL_MAPPING_BASE), reinterpret_cast(trampoline_start_addr), (trampoline_end_addr - trampoline_start_addr)); 69 | 70 | smp::ipi::init_ipi(); 71 | } 72 | 73 | void smp::multiprocessing::boot_aps(){ 74 | for(auto& e : cpus) 75 | if(!(e.bsp)) // CPU is not the BSP, boot it 76 | this->boot_cpu(e); 77 | } -------------------------------------------------------------------------------- /kernel/source/smp/trampoline.S: -------------------------------------------------------------------------------- 1 | .code16 2 | 3 | .text 4 | 5 | .set KERNEL_VMA, 0xffffffff80000000 6 | .set SMP_START, 0x1000 7 | .set SMP_START_SEG, 0x100 8 | 9 | .globl trampoline_start 10 | trampoline_start: 11 | cli 12 | 13 | movw $SMP_START_SEG, %ax 14 | movw %ax, %ds 15 | movw %ax, %es 16 | movw %ax, %fs 17 | movw %ax, %gs 18 | movw %ax, %ss 19 | 20 | lgdt (trampoline_32bit_gdt_pointer - trampoline_start) 21 | 22 | movl %cr0, %eax 23 | bts $0, %eax // set PE (Protection Enable) bit 24 | movl %eax, %cr0 25 | 26 | jmp trampoline_flush_segements 27 | 28 | trampoline_flush_segements: 29 | movw $0x10, %ax 30 | movw %ax, %ds 31 | movw %ax, %es 32 | movw %ax, %fs 33 | movw %ax, %gs 34 | movw %ax, %ss 35 | 36 | DATA32 ljmp $0x08, $(SMP_START + (trampoline_enter_32 - trampoline_start)) 37 | 38 | cli 39 | hlt 40 | 41 | .code32 42 | 43 | trampoline_enter_32: 44 | movl %cr4, %eax 45 | bts $4, %eax // Set PSE (Page Size Extension) 46 | bts $5, %eax // Set PAE (Physical Address Extension 47 | bts $7, %eax // Set PGE 48 | mov %eax, %cr4 49 | 50 | lgdt (SMP_START + (trampoline_gdt64_pointer - trampoline_start)) 51 | 52 | mov $((SMP_START + (pml4_table - trampoline_start))), %eax 53 | mov %eax, %cr3 54 | 55 | movl $0xc0000080, %ecx 56 | rdmsr 57 | bts $8, %eax // Set Long Mode Enable Bit 58 | bts $11, %eax // Set NXE 59 | wrmsr 60 | 61 | movl %cr0, %eax 62 | bts $31, %eax // set PG (Paging) bit 63 | movl %eax, %cr0 64 | 65 | ljmp $0x08, $(SMP_START + (trampoline_enter_64 - trampoline_start)) 66 | 67 | cli 68 | hlt 69 | 70 | 71 | 72 | .code64 73 | 74 | .globl _smp_kernel_early 75 | trampoline_enter_64: 76 | xorw %ax, %ax 77 | movw %ax, %ds 78 | movw %ax, %es 79 | movw %ax, %fs 80 | movw %ax, %gs 81 | movw %ax, %ss 82 | 83 | movabsq $_smp_kernel_early, %rax 84 | jmp *%rax 85 | cli 86 | hlt 87 | 88 | 89 | .align 16 90 | trampoline_32bit_gdt_start: 91 | .word 0 // NULL entry 92 | .word 0 93 | .word 0 94 | .word 0 95 | trampoline_32bit_gdt_code: 96 | .word 0xffff 97 | .word 0x0000 98 | .word 0x9a00 99 | .word 0x00cf 100 | trampoline_32bit_gdt_data: 101 | .word 0xffff 102 | .word 0x0000 103 | .word 0x9200 104 | .word 0x00cf 105 | trampoline_32bit_gdt_end: 106 | 107 | 108 | .align 16 109 | trampoline_32bit_gdt_pointer: 110 | .word trampoline_32bit_gdt_end - trampoline_32bit_gdt_start - 1 111 | .long (SMP_START + (trampoline_32bit_gdt_start - trampoline_start)) 112 | 113 | .align 16 114 | trampoline_gdt64: 115 | .quad 0 116 | .quad (1 << 43) | (1 << 44) | (1 << 47) | (1 << 53) 117 | 118 | trampoline_gdt64_end: 119 | 120 | .align 16 121 | trampoline_gdt64_pointer: 122 | .word trampoline_gdt64_end - trampoline_gdt64 - 1 123 | .quad (SMP_START + (trampoline_gdt64 - trampoline_start)) 124 | 125 | .align 0x1000 126 | pml4_table: 127 | .quad ((SMP_START + (pdpt_table - trampoline_start)) + 3) 128 | .fill 510,8,0 129 | .quad ((SMP_START + (pdpt_table - trampoline_start)) + 3) 130 | 131 | pdpt_table: 132 | .quad ((SMP_START + (pd_table - trampoline_start)) + 3) 133 | .fill 509,8,0 134 | .quad ((SMP_START + (pd_table - trampoline_start)) + 3) 135 | .fill 1,8,0 136 | 137 | pd_table: 138 | .quad 0x0000000000000083 139 | .quad 0x0000000000200083 140 | .quad 0x0000000000400083 141 | .quad 0x0000000000600083 142 | .quad 0x0000000000800083 143 | .quad 0x0000000000A00083 144 | .fill 506,8,0 145 | 146 | .globl trampoline_end 147 | trampoline_end: -------------------------------------------------------------------------------- /kernel/subprojects/multiboot_loader/include/loader/common.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_MULTIBOOT_LOADER_COMMON 2 | #define SIGMA_MULTIBOOT_LOADER_COMMON 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace loader::common 9 | { 10 | void abort(); 11 | void debug_printf(const char* str); 12 | void init(); 13 | } // namespace common 14 | 15 | 16 | #endif -------------------------------------------------------------------------------- /kernel/subprojects/multiboot_loader/include/loader/multiboot.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_LOADER_MULTIBOOT 2 | #define SIGMA_LOADER_MULTIBOOT 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace loader 9 | { 10 | class multiboot { 11 | public: 12 | multiboot(void* mbd, uint64_t magic): mem_low(0), mem_high(0), rsdp(nullptr), elf_sections(nullptr), n_elf_sections(0), \ 13 | initrd_ptr(0), initrd_size(0), mmap_entry(0), mbd(mbd), magic(magic){ 14 | if(magic != MULTIBOOT2_BOOTLOADER_MAGIC){ 15 | loader::common::debug_printf("Multiboot header magic not correct\n"); 16 | loader::common::abort(); 17 | } 18 | 19 | this->parse_mbd(); 20 | } 21 | 22 | 23 | uint64_t get_memsize_mb(){ 24 | return ((((this->mem_low * 1024) + (this->mem_high * 1024)) / 1024) / 1024) + 1; 25 | } 26 | 27 | uint64_t get_rsdp(){ 28 | return reinterpret_cast(rsdp); 29 | } 30 | 31 | multiboot_tag_mmap* get_mmap_entry(){ 32 | return reinterpret_cast(mmap_entry); 33 | } 34 | 35 | uint64_t get_mbd_size(){ 36 | uint32_t* base = reinterpret_cast(this->mbd); 37 | uint64_t total_size = *base; 38 | return total_size; 39 | } 40 | 41 | uint64_t get_mbd_ptr(){ 42 | return reinterpret_cast(this->mbd); 43 | } 44 | 45 | uint64_t* get_elf_sections(){ 46 | return this->elf_sections; 47 | } 48 | 49 | uint64_t get_elf_n_sections(){ 50 | return this->n_elf_sections; 51 | } 52 | 53 | uint64_t get_initrd_ptr(){ 54 | return this->initrd_ptr; 55 | } 56 | 57 | uint64_t get_initrd_size(){ 58 | return this->initrd_size; 59 | } 60 | 61 | char* get_kernel_cmdline(){ 62 | return this->kernel_cmdline; 63 | } 64 | 65 | private: 66 | uint32_t mem_low, mem_high; 67 | uint64_t* rsdp; 68 | uint64_t* elf_sections; 69 | uint64_t n_elf_sections; 70 | 71 | uint64_t initrd_ptr, initrd_size; 72 | 73 | uint64_t mmap_entry; 74 | char* kernel_cmdline; 75 | 76 | void parse_mbd(); 77 | void* mbd; 78 | uint64_t magic; 79 | }; 80 | } // namespace loader 81 | 82 | #endif -------------------------------------------------------------------------------- /kernel/subprojects/multiboot_loader/include/loader/protocol.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGMA_LOADER_BOOT_PROTOCOL 2 | #define SIGMA_LOADER_BOOT_PROTOCOL 3 | 4 | #include 5 | 6 | namespace loader 7 | { 8 | struct boot_protocol { 9 | uint64_t acpi_pointer; 10 | uint64_t memsize; 11 | uint64_t mmap; 12 | uint64_t reserve_start; // Area to reserve 13 | uint64_t reserve_length; // Area to reserve 14 | uint64_t kernel_elf_sections; 15 | uint64_t kernel_n_elf_sections; 16 | uint64_t kernel_initrd_ptr; 17 | uint64_t kernel_initrd_size; 18 | char* cmdline; 19 | }; 20 | } // namespace loader 21 | 22 | 23 | #endif -------------------------------------------------------------------------------- /kernel/subprojects/multiboot_loader/meson.build: -------------------------------------------------------------------------------- 1 | project('sigma-multiboot-loader', 'cpp') 2 | 3 | loader_include = include_directories('include') 4 | 5 | loader_nasm_sources = files( 6 | 'source/load.asm', 7 | 'source/multiboot.asm') 8 | 9 | loader_nasm = find_program('nasm') 10 | loader_nasm_gen = generator(loader_nasm, output: '@BASENAME@.o', arguments: ['-f', 'elf64', '-g', '-F', 'dwarf', '@INPUT@', '-o', '@OUTPUT@']) 11 | extra_object_files = loader_nasm_gen.process(loader_nasm_sources) 12 | 13 | loader_source_files = files( 14 | 'source/common.cpp', 15 | 'source/loader_main.cpp', 16 | 'source/multiboot.cpp', 17 | 'source/start_longmode.S') 18 | 19 | 20 | loader_objects = [loader_source_files] 21 | 22 | loader_library = static_library('multiboot_loader', 23 | loader_objects, 24 | include_directories: loader_include, 25 | pic: false) 26 | 27 | dependency = declare_dependency(link_with: loader_library, 28 | include_directories: loader_include) -------------------------------------------------------------------------------- /kernel/subprojects/multiboot_loader/source/common.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void loader::common::abort(){ 4 | debug_printf("Loader aborted\n"); 5 | asm("cli; hlt"); 6 | while(true); 7 | } 8 | 9 | static uint8_t inb(uint16_t port){ 10 | uint8_t ret; 11 | asm volatile ("in %1, %0" : "=a"(ret) : "Nd"(port)); 12 | return ret; 13 | } 14 | 15 | static void outb(uint16_t port, uint8_t data){ 16 | asm volatile ("out %0, %1" : : "a"(data), "Nd"(port)); 17 | } 18 | 19 | constexpr uint16_t com1_base = 0x3F8; 20 | void loader::common::init(){ 21 | 22 | outb(com1_base + 3, 0x03); // Configure port 23 | outb(com1_base + 1, 0); // Disable interrupts 24 | 25 | uint8_t cmd = inb(com1_base + 3); 26 | cmd |= (1 << 7); 27 | outb(com1_base + 3, cmd); 28 | outb(com1_base, (3 >> 8) & 0xFF); 29 | outb(com1_base, 3 & 0xFF); 30 | 31 | cmd = inb(com1_base + 3); 32 | cmd &= ~(1 << 7); 33 | outb(com1_base + 3, cmd); 34 | } 35 | 36 | 37 | static void print_char(const char c){ 38 | while((inb(com1_base + 5) & 0x20) == 0); 39 | outb(com1_base, c); 40 | } 41 | 42 | void loader::common::debug_printf(const char* str){ 43 | while(*str){ 44 | print_char(*str); 45 | str++; 46 | } 47 | } -------------------------------------------------------------------------------- /kernel/subprojects/multiboot_loader/source/load.asm: -------------------------------------------------------------------------------- 1 | [bits 64] 2 | 3 | section .text 4 | 5 | global long_mode_start 6 | long_mode_start: 7 | mov ax, cs 8 | cmp ax, CODE_SEG 9 | jne .no_correct_code_seg 10 | 11 | mov ax, 0 12 | mov ss, ax 13 | mov ds, ax 14 | mov es, ax 15 | ;mov fs, ax 16 | ;mov gs, ax 17 | 18 | 19 | mov rax, cr3 20 | add rax, KERNEL_LMA 21 | mov qword [rax], 0x0 22 | invlpg [0] 23 | 24 | mov rsp, loader_stack_top 25 | and rsp, ~8 ; Make sure rsp + 8 is 16 byte aligned as mandated by the SysV ABI 26 | mov rbp, 0 27 | 28 | extern _start_multiboot_info 29 | extern _start_multiboot_magic 30 | 31 | mov rsi, 0 32 | mov esi, dword [_start_multiboot_magic] 33 | 34 | mov rdi, 0 35 | mov edi, dword [_start_multiboot_info] 36 | add rdi, KERNEL_LMA 37 | 38 | cld 39 | 40 | 41 | [extern kernel_loader_main] 42 | jmp kernel_loader_main 43 | 44 | .no_correct_code_seg: 45 | mov al, '6' 46 | call long_mode_error 47 | 48 | 49 | long_mode_error: 50 | mov dword [RAW_VGA_BUFFER], 0x4f524f45 51 | mov dword [RAW_VGA_BUFFER + 4], 0x4f3a4f52 52 | mov dword [RAW_VGA_BUFFER + 8], 0x4f204f20 53 | mov byte [RAW_VGA_BUFFER + 12], al 54 | 55 | cli 56 | hlt 57 | 58 | section .bss 59 | 60 | align 16 61 | loader_stack_bottom: 62 | resb 0x4000 63 | loader_stack_top: 64 | 65 | section .data 66 | align 0x1000 67 | global p4_table 68 | 69 | p4_table: 70 | dq p3_table - KERNEL_LMA + 3 71 | times 255 dq 0 72 | dq p3_table - KERNEL_LMA + 3 73 | times 254 dq 0 74 | dq p3_table - KERNEL_LMA + 3 75 | 76 | p3_table: 77 | dq p2_tableA - KERNEL_LMA + 3 78 | dq p2_tableB - KERNEL_LMA + 3 79 | dq p2_tableC - KERNEL_LMA + 3 80 | dq p2_tableD - KERNEL_LMA + 3 81 | dq p2_tableE - KERNEL_LMA + 3 82 | times 505 dq 0 83 | dq p2_tableA - KERNEL_LMA + 3 84 | times 1 dq 0 85 | 86 | %macro gen_pd_2mb 3 87 | %assign i %1 88 | %rep %2 89 | dq (i | 0x83) 90 | %assign i i+0x200000 91 | %endrep 92 | %rep %3 93 | dq 0 94 | %endrep 95 | %endmacro 96 | 97 | p2_tableA: 98 | gen_pd_2mb 0,512,0 99 | 100 | p2_tableB: 101 | gen_pd_2mb 1 * (0x200000 * 512), 512, 0 102 | 103 | p2_tableC: 104 | gen_pd_2mb 2 * (0x200000 * 512), 512, 0 105 | 106 | p2_tableD: 107 | gen_pd_2mb 3 * (0x200000 * 512), 512, 0 108 | 109 | p2_tableE: 110 | gen_pd_2mb 4 * (0x200000 * 512), 512, 0 111 | 112 | 113 | KERNEL_LMA equ 0xffffffff80000000 114 | CODE_SEG equ 0x08 115 | RAW_VGA_BUFFER equ (0xb8000 + KERNEL_LMA) -------------------------------------------------------------------------------- /kernel/subprojects/multiboot_loader/source/loader_main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | extern "C" { 6 | loader::boot_protocol boot_data; 7 | 8 | void _kernel_early(); 9 | 10 | void kernel_loader_main(void* multiboot_information, uint64_t magic){ 11 | loader::common::init(); 12 | 13 | 14 | auto mboot = loader::multiboot(multiboot_information, magic); 15 | 16 | 17 | 18 | boot_data.acpi_pointer = mboot.get_rsdp(); 19 | boot_data.kernel_elf_sections = reinterpret_cast(mboot.get_elf_sections()); 20 | boot_data.kernel_n_elf_sections = mboot.get_elf_n_sections(); 21 | boot_data.memsize = mboot.get_memsize_mb(); 22 | boot_data.mmap = reinterpret_cast(mboot.get_mmap_entry()); 23 | boot_data.reserve_start = mboot.get_mbd_ptr(); 24 | boot_data.reserve_length = mboot.get_mbd_size(); 25 | boot_data.kernel_initrd_ptr = mboot.get_initrd_ptr(); 26 | boot_data.kernel_initrd_size = mboot.get_initrd_size(); 27 | boot_data.cmdline = mboot.get_kernel_cmdline(); 28 | 29 | _kernel_early(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /kernel/subprojects/multiboot_loader/source/multiboot.asm: -------------------------------------------------------------------------------- 1 | MULTIBOOT2_HEADER_MAGIC equ 0xE85250D6 2 | MULTIBOOT2_ARCHITECTURE_i386 equ 0 3 | 4 | section .loader_header 5 | align 4 6 | global multiboot_header 7 | multiboot_header: 8 | dd MULTIBOOT2_HEADER_MAGIC ; MAGIC 9 | dd MULTIBOOT2_ARCHITECTURE_i386 ; ARCHITECTURE 10 | dd (multiboot_header_end - multiboot_header) ; LENGTH 11 | dd 0x100000000 - (MULTIBOOT2_HEADER_MAGIC + MULTIBOOT2_ARCHITECTURE_i386 + (multiboot_header_end - multiboot_header)) ; CHECKSUM 12 | 13 | 14 | ; Tags 15 | dw 6; Type: Page Align Modules 16 | dw 0; Flags: 0 17 | dd 8; Size: 8 18 | 19 | ; End Tag 20 | dw 0 ; Type 21 | dw 0 ; Flags 22 | dd 8 ; Size 23 | multiboot_header_end: -------------------------------------------------------------------------------- /kernel/subprojects/multiboot_loader/source/multiboot.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static int memcmp(const void* s1, const void* s2, size_t n){ 4 | const uint8_t* a = (const uint8_t*)s1; 5 | const uint8_t* b = (const uint8_t*)s2; 6 | 7 | for(size_t i = 0; i < n; i++){ 8 | if(a[i] < b[i]) return -1; 9 | else if(b[i] < a[i]) return 1; 10 | } 11 | 12 | return 0; 13 | } 14 | 15 | void loader::multiboot::parse_mbd(){ 16 | uint32_t* base = static_cast(this->mbd); 17 | uint64_t total_size = *base; 18 | 19 | uint64_t add_size = 0; 20 | 21 | for(uint64_t i = 8/*skip fixed part*/; i < total_size; i += add_size){ 22 | uint32_t* type = reinterpret_cast((uint64_t)base + i); 23 | if(*type == MULTIBOOT_TAG_TYPE_END) break; 24 | 25 | 26 | 27 | 28 | uint32_t* size = reinterpret_cast((uint64_t)base + i + 4); 29 | add_size = *size; 30 | 31 | if((add_size % 8)!= 0) add_size += (8 - add_size % 8); // Align 8byte 32 | 33 | switch (*type) 34 | { 35 | case MULTIBOOT_TAG_TYPE_CMDLINE: 36 | { 37 | auto info = reinterpret_cast(type); 38 | this->kernel_cmdline = info->string; 39 | } 40 | break; 41 | 42 | case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: 43 | { 44 | multiboot_tag_basic_meminfo* info = reinterpret_cast(type); 45 | this->mem_low = info->mem_lower; 46 | this->mem_high = info->mem_upper; 47 | } 48 | break; 49 | 50 | case MULTIBOOT_TAG_TYPE_MMAP: 51 | this->mmap_entry = reinterpret_cast(type); 52 | break; 53 | 54 | case MULTIBOOT_TAG_TYPE_ACPI_OLD: 55 | { 56 | multiboot_tag_old_acpi* info = reinterpret_cast(type); 57 | if(rsdp == nullptr) this->rsdp = reinterpret_cast(info->rsdp); 58 | } 59 | break; 60 | 61 | case MULTIBOOT_TAG_TYPE_ACPI_NEW: 62 | { 63 | multiboot_tag_new_acpi* info = reinterpret_cast(type); 64 | if(rsdp == nullptr) this->rsdp = reinterpret_cast(info->rsdp); 65 | } 66 | break; 67 | 68 | case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: 69 | { 70 | multiboot_tag_elf_sections* info = reinterpret_cast(type); 71 | /*for(uint64_t i = 0; i < info->num; i++){ 72 | multiboot_elf::Elf32_Shdr* shdr = reinterpret_cast(reinterpret_cast(info->sections) + (i * info->entsize)); 73 | if(shdr->sh_flags & 0x2){ 74 | printf("Section: base %x, len: %x, type: %x, ALLOCATED ", shdr->sh_addr, shdr->sh_size, shdr->sh_type); 75 | if(shdr->sh_flags & 0x1) printf("WRITABLE "); 76 | if(shdr->sh_flags & 0x4) printf("EXECUTABLE "); 77 | printf("\n"); 78 | } 79 | }*/ 80 | if(this->elf_sections == nullptr){ 81 | this->elf_sections = reinterpret_cast(info->sections); 82 | this->n_elf_sections = info->num; 83 | } 84 | } 85 | break; 86 | 87 | case MULTIBOOT_TAG_TYPE_MODULE: 88 | { 89 | multiboot_tag_module* info = reinterpret_cast(type); 90 | 91 | if(memcmp(info->cmdline, "initrd.tar", 10) == 0){ 92 | this->initrd_ptr = info->mod_start; 93 | this->initrd_size = (info->mod_end - info->mod_start); 94 | } 95 | } 96 | break; 97 | 98 | default: 99 | break; 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /kernel/subprojects/multiboot_loader/source/start_longmode.S: -------------------------------------------------------------------------------- 1 | .code32 2 | 3 | .set KERNEL_VMA, 0xffffffff80000000 4 | 5 | .section .text 6 | .globl _loader_start 7 | .globl p4_table 8 | _loader_start: 9 | movl %eax, (_start_multiboot_magic - KERNEL_VMA) 10 | movl %ebx, (_start_multiboot_info - KERNEL_VMA) 11 | 12 | movl $0x80000000, %eax 13 | cpuid 14 | cmpl $0x80000001, %eax 15 | jb no_long_mode 16 | 17 | movl $0x80000001, %eax 18 | cpuid 19 | testl $(1 << 29), %edx 20 | jz no_long_mode 21 | 22 | lgdt (gdt64_pointer - KERNEL_VMA) 23 | 24 | movl %cr0, %eax 25 | andl $0x7fffffff, %eax 26 | movl %eax, %cr0 27 | 28 | movl %cr4, %eax 29 | orl $0x30, %eax 30 | movl %eax, %cr4 31 | 32 | movl $p4_table - KERNEL_VMA, %eax 33 | mov %eax, %cr3 34 | 35 | movl $0xc0000080, %ecx 36 | rdmsr 37 | orl $0x00000101, %eax 38 | wrmsr 39 | 40 | movl %cr0, %eax 41 | orl $0x80000000, %eax 42 | movl %eax, %cr0 43 | 44 | 45 | ljmp $0x08, $(_start_64 - KERNEL_VMA) 46 | 47 | cli 48 | hlt 49 | 50 | no_long_mode: 51 | movb $0x30, (0xb8000) 52 | 53 | cli 54 | hlt 55 | 56 | .globl _start_multiboot_info 57 | _start_multiboot_info: .fill 1,4,0 58 | .globl _start_multiboot_magic 59 | _start_multiboot_magic: .fill 1,4,0 60 | 61 | 62 | .section .rodata 63 | .align 16 64 | gdt64: 65 | .quad 0 66 | .quad (1 << 43) | (1 << 44) | (1 << 47) | (1 << 53) 67 | 68 | gdt64_end: 69 | 70 | .align 16 71 | gdt64_pointer: 72 | .word gdt64_end - gdt64 - 1 73 | .quad (gdt64 - KERNEL_VMA) 74 | 75 | 76 | .section .text 77 | .code64 78 | .globl _start_64 79 | .globl long_mode_start 80 | _start_64: 81 | movabsq $long_mode_start, %rax 82 | jmp *%rax 83 | -------------------------------------------------------------------------------- /libs/libkbus/include/kbus/kbus.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LIBKBUS_H 2 | #define LIBKBUS_H 3 | 4 | #if !defined(__cplusplus) 5 | #error "Not compiling as C++" 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace kbus 13 | { 14 | using object_id = uint64_t; 15 | object_id allocate_object(); 16 | 17 | class object { 18 | public: 19 | object(); 20 | object(object_id id); 21 | 22 | std::string get_attribute(std::string key); 23 | void set_attribute(std::string key, std::string value); 24 | 25 | private: 26 | object_id id; 27 | }; 28 | 29 | std::vector find_devices(std::string query); 30 | } // namespace kbus 31 | 32 | #endif -------------------------------------------------------------------------------- /libs/libkbus/meson.build: -------------------------------------------------------------------------------- 1 | project('libkbus', 'cpp') 2 | 3 | kbus_includes = include_directories('include') 4 | 5 | kbus_sources = files('source/kbus.cpp') 6 | 7 | libsigma_dep = dependency('sigma') 8 | kbus_deps = [libsigma_dep] 9 | 10 | cpp_args = ['-std=c++17'] 11 | 12 | libkbus = shared_library('kbus', kbus_sources, dependencies: kbus_deps, cpp_args: cpp_args, include_directories: kbus_includes, install: true) 13 | 14 | pkg = import('pkgconfig') 15 | pkg.generate(libkbus) 16 | 17 | kbus_api_headers = files('include/kbus/kbus.hpp') 18 | 19 | install_headers(kbus_api_headers, subdir: 'kbus') -------------------------------------------------------------------------------- /libs/libsigma/include/libsigma/sys.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBSIGMA_SYS_H 2 | #define LIBSIGMA_SYS_H 3 | 4 | #if defined(__cplusplus) 5 | extern "C" { 6 | #include 7 | #include 8 | #elif defined(__STDC__) 9 | #include 10 | #include 11 | #include 12 | #else 13 | #error "Compiling libsigma/syscall.h on unknown language" 14 | #endif 15 | 16 | typedef uint64_t handle_t; 17 | typedef uint64_t tid_t; 18 | 19 | enum { 20 | devCtlNop = 0, 21 | devCtlClaim = 1, 22 | devCtlFindPci = 2, 23 | devCtlFindPciClass = 3, 24 | devCtlGetResourceRegion = 4, 25 | devCtlEnableIrq = 5, 26 | devCtlWaitOnIrq = 6, 27 | devCtlReadPci = 7, 28 | devCtlWritePci = 8, 29 | }; 30 | 31 | enum { 32 | resourceRegionOriginPciBar = 0, 33 | 34 | resourceRegionTypeMmio = 0, 35 | resourceRegionTypeIo = 1, 36 | resourceRegionTypeInvalid = 0xFF 37 | }; 38 | 39 | typedef struct libsigma_resource_region { 40 | uint8_t type; 41 | uint64_t origin; 42 | uint64_t base; 43 | uint64_t len; 44 | } libsigma_resource_region_t; 45 | 46 | uint64_t devctl(uint64_t command, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4); 47 | 48 | int libsigma_read_initrd_file(const char* filename, uint8_t* buffer, uint64_t offset, uint64_t length); 49 | size_t libsigma_initrd_get_file_size(const char* filename); 50 | 51 | int libsigma_set_fsbase(uint64_t fs); 52 | void libsigma_kill(void); 53 | void libsigma_yield(void); 54 | uint64_t libsigma_fork(void); 55 | 56 | tid_t libsigma_get_current_tid(void); 57 | 58 | enum libsigma_block_reasons{SIGMA_BLOCK_FOREVER = 0, SIGMA_BLOCK_WAITING_FOR_IPC}; 59 | int libsigma_block_thread(enum libsigma_block_reasons reason, handle_t handle); 60 | 61 | typedef struct libsigma_message { 62 | uint8_t byte; 63 | uint8_t data[]; 64 | } libsigma_message_t; 65 | 66 | int libsigma_ipc_send(handle_t ring, libsigma_message_t* msg, size_t msg_size); 67 | int libsigma_ipc_receive(handle_t ring, libsigma_message_t* msg); 68 | size_t libsigma_ipc_get_msg_size(handle_t ring); 69 | 70 | void* libsigma_vm_map(size_t size, void *virt_addr, void* phys_addr, int prot, int flags); 71 | 72 | typedef struct { 73 | uint64_t physical_addr; 74 | uint64_t virtual_addr; 75 | size_t size; 76 | } libsigma_phys_region_t; 77 | 78 | int libsigma_get_phys_region(size_t size, int prot, int flags, libsigma_phys_region_t* region); 79 | 80 | int libsigma_klog(const char* str); 81 | 82 | #ifdef __cplusplus 83 | } 84 | #endif 85 | 86 | #endif -------------------------------------------------------------------------------- /libs/libsigma/include/libsigma/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBSIGMA_SYSCALLS_H 2 | #define LIBSIGMA_SYSCALLS_H 3 | 4 | #if defined(__cplusplus) 5 | extern "C" { 6 | #include 7 | #include 8 | #elif defined(__STDC__) 9 | #include 10 | #include 11 | #else 12 | #error "Compiling libsigma/syscall.h on unknown language" 13 | #endif 14 | 15 | enum { 16 | sigmaSyscallEarlyKlog = 0, 17 | 18 | sigmaSyscallSetFsBase, 19 | sigmaSyscallKill, 20 | sigmaSyscallFork, 21 | sigmaSyscallYield, 22 | sigmaSyscallGetCurrentTid, 23 | sigmaSyscallBlockThread, 24 | 25 | sigmaSyscallVmMap, 26 | sigmaSyscallGetPhysRegion, 27 | 28 | sigmaSyscallReadInitrd, 29 | sigmaSyscallInitrdSize, 30 | 31 | sigmaSyscallIpcSend, 32 | sigmaSyscallIpcReceive, 33 | sigmaSyscallIpcGetSize, 34 | 35 | sigmaSyscallDevCtl, 36 | sigmaSyscallVCtl, 37 | }; 38 | 39 | uint64_t libsigma_syscall0(uint64_t number); 40 | uint64_t libsigma_syscall1(uint64_t number, uint64_t arg1); 41 | uint64_t libsigma_syscall2(uint64_t number, uint64_t arg1, uint64_t arg2); 42 | uint64_t libsigma_syscall3(uint64_t number, uint64_t arg1, uint64_t arg2, uint64_t arg3); 43 | uint64_t libsigma_syscall4(uint64_t number, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4); 44 | uint64_t libsigma_syscall5(uint64_t number, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5); 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #endif -------------------------------------------------------------------------------- /libs/libsigma/include/libsigma/virt.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBSIGMA_VIRT_H 2 | #define LIBSIGMA_VIRT_H 3 | 4 | #if defined(__cplusplus) 5 | extern "C" { 6 | #include 7 | #include 8 | #elif defined(__STDC__) 9 | #include 10 | #include 11 | #else 12 | #error "Compiling libsigma/virt.h on unknown language" 13 | #endif 14 | 15 | enum { 16 | vCtlExitReasonHlt = 0, 17 | vCtlExitReasonRdtsc, 18 | vCtlExitReasonPortRead, 19 | vCtlExitReasonPortWrite, 20 | vCtlExitReasonMsrRead, 21 | vCtlExitReasonMsrWrite, 22 | vCtlExitReasonSRegRead, 23 | vCtlExitReasonSRegWrite, 24 | vCtlExitReasonNestedPageFault, 25 | vCtlExitReasonHypercall, 26 | vCtlExitReasonInterrupt, 27 | 28 | vCtlExitReasonInvalidInternalState = -1 29 | }; 30 | 31 | enum { 32 | vCtlExitRegNumberCr0, 33 | vCtlExitRegNumberCr1, 34 | vCtlExitRegNumberCr2, 35 | vCtlExitRegNumberCr3, 36 | vCtlExitRegNumberCr4, 37 | vCtlExitRegNumberCr5, 38 | vCtlExitRegNumberCr6, 39 | vCtlExitRegNumberCr7, 40 | vCtlExitRegNumberCr8, 41 | vCtlExitRegNumberCr9, 42 | vCtlExitRegNumberCr10, 43 | vCtlExitRegNumberCr11, 44 | vCtlExitRegNumberCr12, 45 | vCtlExitRegNumberCr13, 46 | vCtlExitRegNumberCr14, 47 | vCtlExitRegNumberCr15, 48 | vCtlExitRegNumberGdtr, 49 | vCtlExitRegNumberIdtr, 50 | vCtlExitRegNumberLdtr, 51 | vCtlExitRegNumberTr, 52 | }; 53 | 54 | struct vexit { 55 | uint64_t reason; 56 | uint8_t opcode[15]; 57 | uint8_t opcode_length; 58 | 59 | uint8_t interrupt_number; 60 | 61 | union { 62 | struct { 63 | uint16_t port; 64 | uint32_t value; 65 | bool repeated; 66 | bool string; 67 | } port; 68 | struct { 69 | uint32_t number; 70 | uint64_t value; 71 | } msr; 72 | struct { 73 | uint8_t reg_number; 74 | uint64_t value; 75 | } sreg; 76 | struct { 77 | uint64_t phys_addr; 78 | uint64_t value; 79 | uint8_t len; 80 | bool write; 81 | } npf; 82 | }; 83 | }; 84 | 85 | struct vselector { 86 | uint16_t selector; 87 | uint16_t attrib; 88 | uint32_t limit; 89 | uint64_t base; 90 | }; 91 | 92 | struct vdtable { 93 | uint64_t base; 94 | uint16_t limit; 95 | }; 96 | 97 | struct vregs { 98 | uint64_t rax, rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15; 99 | uint64_t rsp, rbp, rip, rflags; 100 | 101 | uint64_t cr0, cr2, cr3, cr4, cr8; 102 | uint64_t efer; 103 | 104 | struct vselector cs, ds, ss, es, fs, gs; 105 | struct vselector ldtr, tr; 106 | struct vdtable gdtr, idtr; 107 | }; 108 | 109 | enum { 110 | vCtlCreateVcpu = 0, 111 | vCtlRunVcpu, 112 | vCtlGetRegs, 113 | vCtlSetRegs, 114 | vCtlCreateVspace, 115 | vCtlMapVspace, 116 | vCtlMapVspacePhys, 117 | }; 118 | 119 | uint64_t vctl(uint64_t cmd, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4); 120 | 121 | #if defined(__cplusplus) 122 | } 123 | #endif 124 | 125 | #endif -------------------------------------------------------------------------------- /libs/libsigma/meson.build: -------------------------------------------------------------------------------- 1 | project('libsigma', 'c') 2 | 3 | headers_only = get_option('headers_only') 4 | no_headers = get_option('no_headers') 5 | 6 | if no_headers 7 | 8 | libsigma_includes = include_directories('include') 9 | 10 | libsigma_sources = files( 11 | 'source/syscall.c', 12 | 'source/sys.c', 13 | 'source/virt.c') 14 | 15 | c_args = ['-std=gnu18', '-fvisibility=hidden'] 16 | 17 | libsigma = static_library('sigma', libsigma_sources, c_args: c_args, include_directories: libsigma_includes, pic: false, install: true) 18 | 19 | pkg = import('pkgconfig') 20 | pkg.generate(libsigma) 21 | endif 22 | 23 | if headers_only 24 | 25 | libsigma_api_headers = files( 26 | 'include/libsigma/sys.h', 27 | 'include/libsigma/syscall.h', 28 | 'include/libsigma/virt.h') 29 | 30 | install_headers(libsigma_api_headers, subdir: 'libsigma') 31 | 32 | endif -------------------------------------------------------------------------------- /libs/libsigma/meson_options.txt: -------------------------------------------------------------------------------- 1 | option('headers_only', type : 'boolean', value : false) 2 | option('no_headers', type : 'boolean', value : false) -------------------------------------------------------------------------------- /libs/libsigma/source/common.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBSIGMA_COMMON_H 2 | #define LIBSIGMA_COMMON_H 3 | 4 | #if defined(__GNUC__) || defined(__clang__) 5 | #define ALWAYSINLINE_ATTRIBUTE __attribute__((always_inline)) 6 | #define NORETURN_ATTRIBUTE __attribute__((__noreturn__)) 7 | #else 8 | #error "Compiling libsigma on an unknown compiler" 9 | #endif 10 | 11 | #endif -------------------------------------------------------------------------------- /libs/libsigma/source/sys.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "common.h" 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | uint64_t devctl(uint64_t command, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4){ 10 | return libsigma_syscall5(sigmaSyscallDevCtl, command, arg1, arg2, arg3, arg4); 11 | } 12 | 13 | int libsigma_read_initrd_file(const char* filename, uint8_t* buffer, uint64_t offset, uint64_t length){ 14 | return libsigma_syscall4(sigmaSyscallReadInitrd, (uint64_t)filename, (uint64_t)buffer, offset, length); 15 | } 16 | 17 | size_t libsigma_initrd_get_file_size(const char* filename){ 18 | return libsigma_syscall1(sigmaSyscallInitrdSize, (uint64_t) filename); 19 | } 20 | 21 | int libsigma_ipc_send(handle_t ring, libsigma_message_t* msg, size_t msg_size){ 22 | return libsigma_syscall3(sigmaSyscallIpcSend, ring, (uint64_t)msg, msg_size); 23 | } 24 | 25 | int libsigma_ipc_receive(handle_t ring, libsigma_message_t* msg){ 26 | return libsigma_syscall2(sigmaSyscallIpcReceive, ring, (uint64_t)msg); 27 | } 28 | 29 | size_t libsigma_ipc_get_msg_size(handle_t ring){ 30 | return libsigma_syscall1(sigmaSyscallIpcGetSize, ring); 31 | } 32 | 33 | int libsigma_klog(const char* str){ 34 | return libsigma_syscall1(sigmaSyscallEarlyKlog, (uint64_t)str); 35 | } 36 | 37 | void* libsigma_vm_map(size_t size, void *virt_addr, void* phys_addr, int prot, int flags){ 38 | return (void*)libsigma_syscall5(sigmaSyscallVmMap, (uint64_t)virt_addr, (uint64_t)phys_addr, size, prot, flags); 39 | } 40 | 41 | int libsigma_get_phys_region(size_t size, int prot, int flags, libsigma_phys_region_t* region){ 42 | return libsigma_syscall4(sigmaSyscallGetPhysRegion, size, prot, flags, (uint64_t)region); 43 | } 44 | 45 | int libsigma_set_fsbase(uint64_t fs){ 46 | return libsigma_syscall1(sigmaSyscallSetFsBase, fs); 47 | } 48 | 49 | NORETURN_ATTRIBUTE 50 | void libsigma_kill(void){ 51 | libsigma_syscall0(sigmaSyscallKill); 52 | while(1); // Why are we still here 53 | // Just to suffer 54 | } 55 | 56 | tid_t libsigma_get_current_tid(void){ 57 | return libsigma_syscall0(sigmaSyscallGetCurrentTid); 58 | } 59 | 60 | int libsigma_block_thread(enum libsigma_block_reasons reason, handle_t handle){ 61 | return libsigma_syscall2(sigmaSyscallBlockThread, reason, handle); 62 | } 63 | 64 | uint64_t libsigma_fork(void){ 65 | return libsigma_syscall0(sigmaSyscallFork); 66 | } 67 | 68 | void libsigma_yield(void){ 69 | libsigma_syscall0(sigmaSyscallYield); 70 | } 71 | 72 | #ifdef __cplusplus 73 | } 74 | #endif -------------------------------------------------------------------------------- /libs/libsigma/source/syscall.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "common.h" 3 | 4 | ALWAYSINLINE_ATTRIBUTE 5 | inline uint64_t libsigma_syscall0(uint64_t number){ 6 | uint64_t ret = 0; 7 | asm("int $249" : "=a"(ret): "a"(number)); 8 | return ret; 9 | } 10 | 11 | ALWAYSINLINE_ATTRIBUTE 12 | inline uint64_t libsigma_syscall1(uint64_t number, uint64_t arg1){ 13 | uint64_t ret = 0; 14 | asm("int $249" : "=a"(ret): "a"(number), "b"(arg1)); 15 | return ret; 16 | } 17 | 18 | ALWAYSINLINE_ATTRIBUTE 19 | inline uint64_t libsigma_syscall2(uint64_t number, uint64_t arg1, uint64_t arg2){ 20 | uint64_t ret = 0; 21 | asm("int $249" : "=a"(ret): "a"(number), "b"(arg1), "c"(arg2)); 22 | return ret; 23 | } 24 | 25 | ALWAYSINLINE_ATTRIBUTE 26 | inline uint64_t libsigma_syscall3(uint64_t number, uint64_t arg1, uint64_t arg2, uint64_t arg3){ 27 | uint64_t ret = 0; 28 | asm("int $249" : "=a"(ret): "a"(number), "b"(arg1), "c"(arg2), "d" (arg3)); 29 | return ret; 30 | } 31 | 32 | ALWAYSINLINE_ATTRIBUTE 33 | inline uint64_t libsigma_syscall4(uint64_t number, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4){ 34 | uint64_t ret = 0; 35 | asm("int $249" : "=a"(ret): "a"(number), "b"(arg1), "c"(arg2), "d" (arg3), "S"(arg4)); 36 | return ret; 37 | } 38 | 39 | ALWAYSINLINE_ATTRIBUTE 40 | inline uint64_t libsigma_syscall5(uint64_t number, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5){ 41 | uint64_t ret = 0; 42 | asm("int $249" : "=a"(ret): "a"(number), "b"(arg1), "c"(arg2), "d" (arg3), "S"(arg4), "D"(arg5)); 43 | return ret; 44 | } 45 | -------------------------------------------------------------------------------- /libs/libsigma/source/virt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "common.h" 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | uint64_t vctl(uint64_t cmd, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4){ 10 | return libsigma_syscall5(sigmaSyscallVCtl, cmd, arg1, arg2, arg3, arg4); 11 | } 12 | 13 | #ifdef __cplusplus 14 | } 15 | #endif -------------------------------------------------------------------------------- /protocol/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | INPUT="$(realpath $1)" 3 | touch $2 4 | OUTPUT="$(realpath $2)" 5 | 6 | pwd $SYSROOT 7 | 8 | cd $4 9 | ./iota.py -s $3 -g cpp $INPUT -o $OUTPUT -------------------------------------------------------------------------------- /protocol/kbus.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | NoOperation 4 | CreateDevice 5 | AddAttribute 6 | GetAttribute 7 | FindDevices 8 | 9 | 10 | 11 | command 12 | device 13 | 14 | key 15 | value 16 | 17 | query 18 | 19 | 20 | 21 | Success 22 | 23 | 24 | 25 | status 26 | device 27 | 28 | value 29 | results 30 | 31 | -------------------------------------------------------------------------------- /protocol/zeta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | NoOperation 4 | Open 5 | Close 6 | Read 7 | Write 8 | Seek 9 | Tell 10 | Dup2 11 | 12 | 13 | 14 | command 15 | flags 16 | 17 | 18 | path 19 | 20 | 21 | fd 22 | 23 | 24 | newfd 25 | 26 | 27 | count 28 | 29 | 30 | buffer 31 | 32 | 33 | whence 34 | offset 35 | 36 | 37 | 38 | status 39 | 40 | 41 | fd 42 | 43 | 44 | offset 45 | 46 | 47 | buffer 48 | 49 | -------------------------------------------------------------------------------- /zeta/include/Zeta/singleton.h: -------------------------------------------------------------------------------- 1 | #ifndef ZETA_SINGLETON 2 | #define ZETA_SINGLETON 3 | 4 | template 5 | class singleton { 6 | public: 7 | static T& getInstance(){ 8 | static T instance; 9 | static bool constructed = false; 10 | if(!constructed) instance = T(); 11 | return instance; 12 | } 13 | 14 | singleton(singleton const&) = delete; 15 | void operator=(singleton const&) = delete; 16 | private: 17 | singleton() {} 18 | }; 19 | 20 | 21 | #endif -------------------------------------------------------------------------------- /zeta/include/Zeta/tree.h: -------------------------------------------------------------------------------- 1 | #ifndef ZETA_TREE 2 | #define ZETA_TREE 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | struct tree_node { 10 | tree_node() {} 11 | tree_node(T item): item(item) {} 12 | ~tree_node(){ 13 | for(auto* child : this->children) delete child; 14 | } 15 | T item; 16 | std::vector*> children; 17 | tree_node* parent; 18 | }; 19 | 20 | template 21 | class tree { 22 | public: 23 | tree(): root(new tree_node) {} 24 | ~tree() { 25 | delete root; 26 | } 27 | 28 | tree_node* get_root(){ 29 | return root; 30 | } 31 | 32 | tree_node* insert(tree_node& node, T item){ 33 | //T& ref = item; 34 | node.children.push_back(new tree_node); 35 | tree_node* child = node.children.back(); 36 | 37 | child->item = item; 38 | child->parent = &node; 39 | 40 | return child; 41 | } 42 | 43 | void print(){ 44 | std::string prefix = ""; 45 | this->print_internal(prefix, this->get_root()); 46 | } 47 | 48 | private: 49 | tree_node* root; 50 | 51 | void print_internal(std::string& prefix, tree_node* node){ 52 | std::cout << prefix << "├──"; 53 | std::cout << node->item << std::endl; 54 | 55 | for(auto* child : node->children){ 56 | std::string next_prefix; 57 | next_prefix.append(prefix); 58 | next_prefix.append(" "); 59 | 60 | print_internal(next_prefix, child); 61 | } 62 | } 63 | }; 64 | 65 | #endif -------------------------------------------------------------------------------- /zeta/include/Zeta/vfs.h: -------------------------------------------------------------------------------- 1 | #ifndef ZETA_VFS 2 | #define ZETA_VFS 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | namespace fs { 15 | 16 | // TODO: File things 17 | #pragma region file_data 18 | 19 | enum class fs_node_types { 20 | file, 21 | directory, 22 | mountpoint, 23 | block_device, 24 | }; 25 | 26 | struct fs_node; // Forward decleration for use in fs_calls 27 | 28 | struct fs_calls { 29 | // out_node, Path, Mode 30 | std::function open; 31 | // Node, Buf, Count, Offset 32 | std::function read; 33 | // Node, Buf, Count, Offset 34 | std::function write; 35 | // Node 36 | std::function close; 37 | }; 38 | 39 | // TODO: 40 | struct fs_node { 41 | public: 42 | fs_node_types type; 43 | std::string path; 44 | uint64_t flags; 45 | uint64_t owner; 46 | uint64_t group; 47 | size_t length; 48 | fs_calls calls; 49 | }; 50 | 51 | #pragma endregion 52 | 53 | #pragma region thread_data 54 | struct fd_data { 55 | bool open; 56 | int fd; 57 | fs::fs_node* node; 58 | int mode; 59 | 60 | std::uint64_t offset; 61 | }; 62 | 63 | struct thread_vfs_entry { 64 | thread_vfs_entry(): enabled(false) {} 65 | void init(tid_t tid) { 66 | // TODO: CWD 67 | this->enabled = true; 68 | this->fd_map = std::unordered_map(); 69 | this->tid = tid; 70 | } 71 | tid_t tid; 72 | int free_fd = 3; // TODO: Handle this correctly 73 | std::unordered_map fd_map; 74 | std::string cwd; 75 | bool enabled; 76 | }; 77 | 78 | #pragma endregion 79 | 80 | #pragma region vfs_data 81 | 82 | struct vfs_entry { 83 | std::string name; 84 | fs_node* file; 85 | std::string device; 86 | fs_calls* fs; 87 | }; 88 | 89 | class vfs { 90 | public: 91 | vfs(): 92 | mount_list(std::vector()), thread_data(std::unordered_map()), 93 | filesystems(std::unordered_map()) {} 94 | 95 | void* mount(fs_node* node, std::string_view path, fs_calls* fs); 96 | void* mount(fs_node* node, std::string_view path, std::string_view fs_type); 97 | int open(tid_t tid, std::string_view path, int mode); 98 | int close(tid_t tid, int fd); 99 | int read(tid_t tid, int fd, void* buf, size_t count); 100 | int write(tid_t tid, int fd, const void* buf, size_t count); 101 | int seek(tid_t tid, int fd, uint64_t offset, int whence, uint64_t& new_offset); 102 | uint64_t tell(tid_t tid, int fd); 103 | int dup2(tid_t tid, int oldfd, int newfd); 104 | 105 | std::string make_path_absolute(tid_t tid, std::string_view path); 106 | std::vector split_path(std::string& path); 107 | 108 | fs_calls* get_mountpoint(tid_t tid, std::string path, std::string& out_local_path); 109 | 110 | void register_fs(std::string_view fs_name, fs_calls calls); 111 | 112 | private: 113 | thread_vfs_entry& get_thread_entry(tid_t tid); 114 | std::vector mount_list; 115 | 116 | std::unordered_map thread_data; 117 | std::unordered_map filesystems; 118 | }; 119 | 120 | #pragma endregion 121 | 122 | #pragma region constants 123 | constexpr char path_separator = '/'; 124 | constexpr char root_char = '/'; 125 | #pragma endregion 126 | 127 | vfs& get_vfs(); 128 | 129 | } // namespace fs 130 | 131 | 132 | #endif -------------------------------------------------------------------------------- /zeta/meson.build: -------------------------------------------------------------------------------- 1 | project('zeta', 'cpp', version: '0.0.1', default_options : ['cpp_std=c++17']) 2 | 3 | include_dirs = include_directories('include') 4 | 5 | 6 | source_files = files( 7 | 'source/main.cpp', 8 | 'source/vfs.cpp') 9 | 10 | libsigma_dep = dependency('sigma') 11 | deps = [libsigma_dep] 12 | 13 | add_project_arguments('-Wall', '-Wextra', '-Wno-unknown-pragmas', '-std=c++2a', '-fcoroutines-ts', language: 'cpp') 14 | 15 | 16 | executable('zeta', source_files, include_directories: include_dirs, dependencies: deps, install: true) --------------------------------------------------------------------------------