├── .github └── workflows │ └── commitlint.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── docs ├── CALLING-CONVENTIONS.md ├── CROSS-COMPILER.md └── STYLEGUIDE.md ├── kernel ├── Makefile ├── gensyms.sh └── src │ ├── boot │ ├── boot.cpp │ ├── boot.h │ ├── kconf.cpp │ ├── kconf.h │ ├── kentry.asm │ └── kmain.cpp │ ├── cpu │ ├── gdt.asm │ ├── gdt.cpp │ ├── gdt.h │ ├── interrupts.asm │ ├── interrupts.cpp │ ├── interrupts.h │ ├── tss.cpp │ └── tss.h │ ├── drivers │ ├── 8259 │ │ ├── pic.cpp │ │ └── pic.h │ ├── acpi │ │ ├── acpi.cpp │ │ ├── acpi.h │ │ ├── pci.cpp │ │ ├── pci.h │ │ ├── power.cpp │ │ └── power.h │ ├── audio │ │ └── beeper │ │ │ ├── beeper.cpp │ │ │ └── beeper.h │ ├── disk │ │ └── ahci │ │ │ ├── ahci.cpp │ │ │ └── ahci.h │ ├── gfx │ │ └── gop │ │ │ ├── gop.cpp │ │ │ └── gop.h │ ├── io.h │ ├── kbd │ │ ├── kbd.cpp │ │ └── kbd.h │ ├── tty │ │ ├── printf.cpp │ │ ├── tty.cpp │ │ └── tty.h │ └── uart │ │ ├── serial.cpp │ │ └── serial.h │ ├── fs │ └── gpt │ │ └── gpt.h │ ├── memory │ ├── heap.cpp │ ├── heap.h │ ├── operations.cpp │ ├── operations.h │ ├── paging.cpp │ ├── paging.h │ ├── pat.asm │ ├── pmm.cpp │ └── pmm.h │ ├── mnk.lds │ ├── scheduling │ ├── sleep.asm │ ├── timer.cpp │ └── timer.h │ ├── symbols.h │ ├── types.h │ ├── userspace │ ├── entry │ │ ├── cpuid.cpp │ │ ├── ecpuid.h │ │ ├── kcascii.cpp │ │ ├── keyboard.h │ │ ├── uentry.asm │ │ └── umain.cpp │ ├── syscalls.asm │ └── syscalls.cpp │ └── util │ ├── bitmap.cpp │ ├── bitmap.h │ ├── guid.h │ ├── kutil.cpp │ └── kutil.h └── res ├── GenerateImage ├── OVMF.fd ├── dir2fat32.sh ├── limine.cfg └── limine.efi /.github/workflows/commitlint.yml: -------------------------------------------------------------------------------- 1 | name: Lint Commit Messages 2 | on: 3 | push: 4 | pull_request: 5 | branches: [ master ] 6 | 7 | jobs: 8 | commitlint: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | with: 13 | fetch-depth: 0 14 | - uses: wagoid/commitlint-github-action@v2 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | bin/ 4 | img/ 5 | compile_commands.json -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Cross Compiler 4 | 5 | microCORE builds using the `x86_64-elf-gcc` cross-compiler. You cannot install this cross compiler through prebuilt packages, as the compiler used specifically for microCORE is built with special options. 6 | 7 | See [this document](docs/CROSS-COMPILER.md) for more info. 8 | 9 | ## Styling 10 | 11 | The maintainer of this project strictly requires all code follow a styleguide. Any contributions made that do not follow the styleguide, no matter how helpful they may be, will be rejected. 12 | 13 | See [the styleguide](docs/STYLEGUIDE.md) for more info. 14 | 15 | ## Calling Conventions 16 | 17 | microCORE uses very specific calling conventions. When writing C++ code, the following information is rather useless to you. 18 | 19 | However, when writing assembly, it is critical that you follow this guide. 20 | 21 | See [the calling conventions](docs/CALLING-CONVENTIONS.md) for more info. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: kernel image all run clean 2 | 3 | kernel: 4 | @ mkdir -p bin 5 | @ make -C kernel all 6 | @ mv kernel/bin bin/kernel 7 | 8 | all: kernel 9 | 10 | image: all 11 | @ mkdir -p img 12 | @ res/GenerateImage 13 | 14 | run: 15 | @ qemu-system-x86_64 -bios res/OVMF.fd -drive file=img/microNET.fat -serial stdio -net none -m 512M -machine q35 -soundhw pcspk 16 | 17 | clean: 18 | @ rm -rf bin img 19 | @ make -C kernel clean -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # \*\***NOTICE**\*\* 2 | micron has been archived. No further updates will be made to this project. 3 | 4 | # micron 5 | 6 | # About 7 | ## Use Case 8 | micron is designed uniquely, as an operating system, to be as small, performant, secure, and stable as possible, to run on embedded devices which lack power or memory, for extended periods of time. 9 | 10 | ## Stable 11 | micron has been designed to be stable. We are adding more features for stability, but at the time, these include: 12 | 13 | - relocatable kernel 14 | - strong code quality standards 15 | 16 | ## Secure 17 | micron has been designed to be secure. We are adding more features for security, but at the time, these include: 18 | 19 | - KASLR, a Spectre-class mitigation, for the kernel 20 | 21 | ## Speedy 22 | micron is compiled, at release target, with maximum optimizations. More features are to come. 23 | 24 | ## Small 25 | micron is optimized to the fullest extent so that the kernel has minimal components, for modularity, and size. 26 | 27 | Compare this to the Linux kernel, which is 80MB **at compressed size**, or the NT kernel (as of Windows 7), which is 25MB. 28 | -------------------------------------------------------------------------------- /docs/CALLING-CONVENTIONS.md: -------------------------------------------------------------------------------- 1 | # Calling Conventions 2 | 3 | microCORE follows the System V x86-64 calling conventions. You must adhere to the calling conventions, in order for microCORE to keep compatibillity with C++ code, and stay relocatable. 4 | 5 | ## Passing Parameters 6 | 7 | When passing parameters to **any** function, C++ or not, you must pass parameters in a specific order. 8 | 9 | Take, for example, the following function's prototype: 10 | ```c++ 11 | extern "C" int foo(uint8_t bar, uint64_t baz, uint64_t quux); 12 | ``` 13 | 14 | When passing the parameters, you would pass the parameters in this order: 15 | 16 | ```nasm 17 | mov rdi, 0xFF ; bar 18 | mov rsi, 0xDEADBEEF ; baz 19 | mov rdx, 0xBEEFCAFE ; quux 20 | ``` 21 | 22 | See [this webpage](https://wiki.osdev.org/Calling_Conventions) for more info. 23 | 24 | ## Calling Functions/Accessing Data 25 | 26 | microCORE is **position-independent**, meaning that no matter what address the kernel is loaded to, it will always function properly. 27 | 28 | When calling functions, there is a specific method to keep the code position-independent. 29 | 30 | This also applies to pointers, or accessing any kind of field defined in the kernel's executable. 31 | 32 | Say we want to call this function here: 33 | ```c++ 34 | extern "C" int foo(char* bar, uint32_t baz); 35 | ``` 36 | Say that `bar` is a pointer to a string. 37 | 38 | In assembly, this is how you would call the function: 39 | ```nasm 40 | extern foo 41 | 42 | fee: ; executing here 43 | lea rdi, [rel bar] ; load address of bar into rdi 44 | lea r14, [rel baz] ; load address of baz into r14 45 | mov esi, [r14] ; access the data of baz 46 | lea r14, [rel foo] ; load the address of foo into r14 47 | call r14 ; call the address of foo, stored in r14 48 | 49 | bar: 50 | db "quux",0 ; string defined here 51 | 52 | baz: 53 | dd 4 ; length of quux 54 | ``` 55 | The process is a little tedious, but it is required for functionality. -------------------------------------------------------------------------------- /docs/CROSS-COMPILER.md: -------------------------------------------------------------------------------- 1 | # Cross Compiler 2 | microCORE is built with no red zone, using an x86-64 GCC cross compiler. You cannot download a prebuilt package of this cross-compiler due to special compiler options when built. 3 | 4 | ## Instructions 5 | 6 | **NOTE:** you may need root privileges for this process. 7 | 8 | ### Get source code 9 | You will need to obtain the `binutils` and `gcc` source code. 10 | 11 | GCC source code can be found [here](ftp://ftp.gnu.org/gnu/gcc/), and binutils source code can be found [here](ftp://ftp.gnu.org/gnu/binutils/). It is recommended you download the latest release. 12 | 13 | Extract these two archives to a folder. You should have a folder for GCC, and a folder for Binutils. The two folders should be in one same folder. 14 | 15 | ### **Set up build environment** 16 | You will need to run Linux for this compilation process. 17 | 18 | First, install these packages from your package manager: 19 | ``` 20 | gcc 21 | make 22 | bison 23 | flex 24 | libgmp3-dev 25 | libmpc-dev 26 | libmpfr-dev 27 | texinfo 28 | libcloog-isl-dev 29 | libisl-dev 30 | ``` 31 | 32 | Open a terminal, and type these commands: 33 | ```bash 34 | export PREFIX="$HOME/opt/cross" 35 | export TARGET=x86_64-elf 36 | export PATH="$PREFIX/bin:$PATH" 37 | ``` 38 | Do not close the terminal. 39 | 40 | ### **Building** 41 | #### **`binutils`:** 42 | 43 | Type these commands: 44 | ```bash 45 | mkdir build-binutils 46 | cd build-binutils 47 | ../binutils-x.y.z/configure --target=$TARGET --prefix="$PREFIX" --with-sysroot --disable-nls --disable-werror 48 | make 49 | make install 50 | ``` 51 | Compilation may take anywhere from 5-10 minutes. 52 | 53 | Do not close the terminal. 54 | 55 | #### **`gcc`:** 56 | Before you compile GCC, you will need to edit some configurations. 57 | 58 | Create a file with these contents: 59 | ``` 60 | MULTILIB_OPTIONS += mno-red-zone 61 | MULTILIB_DIRNAMES += no-red-zone 62 | ``` 63 | Save the file as `t-x86_64-elf` under the `gcc/config/i386/` directory in the GCC source tree. 64 | 65 | Edit `gcc/config.gcc` in the GCC source tree, and replace this case block: 66 | ```bash 67 | x86_64-*-elf*) 68 | tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h" 69 | ;; 70 | ``` 71 | with 72 | ```bash 73 | x86_64-*-elf*) 74 | tmake_file="${tmake_file} i386/t-x86_64-elf" 75 | tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h" 76 | ;; 77 | ``` 78 | Now, leave the GCC source tree. 79 | Type these following commands: 80 | ```bash 81 | mkdir build-gcc 82 | cd build-gcc 83 | ../gcc-x.y.z/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --without-headers 84 | make all-gcc 85 | make all-target-libgcc 86 | make install-gcc 87 | make install-target-libgcc 88 | ``` 89 | If you did not build Binutils, GCC will throw errors when you try to build libgcc. 90 | 91 | Compilation can take anywhere from 30 minutes to 2 hours. 92 | 93 | When you are done, you should have a properly configured `x86_64-elf-gcc` cross-compiler. 94 | 95 | Now, you are ready to build microCORE. -------------------------------------------------------------------------------- /docs/STYLEGUIDE.md: -------------------------------------------------------------------------------- 1 | # Styling 2 | microCORE requires a specific styling to keep the codebase clean and consistent. 3 | 4 | ## Names 5 | All names must be in snake_case and must be descriptive. 6 | ```c++ 7 | // NO 8 | void fooPtr(baz& Bar); 9 | 10 | // STILL NO, BUT BETTER 11 | void foo_pointer(baz& bar); 12 | ``` 13 | 14 | ## Namespaces 15 | All methods should be in namespaces. You may **not** create a new root namespace without approval. 16 | ```c++ 17 | // NO 18 | void foo_pointer(baz& bar); 19 | 20 | // NO 21 | void fie::quux::foo_pointer(baz& bar); 22 | 23 | // PERFECT 24 | void sys::quux::foo_pointer(baz& bar); 25 | ``` 26 | 27 | ## Formatting 28 | Put brackets on the same line. 29 | Do not use brackets on one-statement conditionals. 30 | Break lines and tab on one-statement conditionals. 31 | Prefer to align names when defining structures. 32 | Space between brackets and parenthesis. 33 | ```c++ 34 | // FUCK NO 35 | void sys::quux::foo_pointer(baz& bar){ 36 | if (bar.fie == 0) { return; } 37 | else if (bar.fie < 0) 38 | { bar.fie++; } 39 | else if (bar.fie > 0) 40 | { bar.fie++; } 41 | else{ 42 | bar.quux = 0; 43 | } 44 | } 45 | 46 | // PERFECTION 47 | void sys::quux::foo_pointer(baz& bar) { 48 | 49 | if (bar.fie == 0) 50 | return; 51 | else if (bar.fie < 0) 52 | bar.fie++; 53 | else if (bar.fie > 0) 54 | bar.fie++; 55 | else 56 | bar.quux = 0; 57 | 58 | } 59 | ``` -------------------------------------------------------------------------------- /kernel/Makefile: -------------------------------------------------------------------------------- 1 | SRCDIR = src 2 | BINDIR = bin 3 | OBJDIR = bin/obj 4 | 5 | CPPSRC = $(call rwildcard,$(SRCDIR),*.cpp) 6 | ASMSRC = $(call rwildcard,$(SRCDIR),*.asm) 7 | LDS = src/mnk.lds 8 | 9 | OBJS = $(patsubst $(SRCDIR)/%.cpp, $(OBJDIR)/%.cc.o, $(CPPSRC)) 10 | OBJS += $(patsubst $(SRCDIR)/%.asm, $(OBJDIR)/%.as.o, $(ASMSRC)) 11 | SYMS = $(OBJDIR)/syms.o 12 | KERNEL = $(BINDIR)/mnk.elf 13 | 14 | rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d)) 15 | 16 | CC = x86_64-elf-gcc 17 | AS = nasm 18 | GS = ./gensyms.sh 19 | 20 | # Flags to enable all (reasonable) warnings possible 21 | # and treat them as errors to ensure code quality 22 | WRFLAGS =\ 23 | -Werror \ 24 | -Wall \ 25 | -Wno-int-to-pointer-cast 26 | 27 | CCFLAGS = \ 28 | -ffreestanding \ 29 | -I$(SRCDIR) \ 30 | -fno-pic \ 31 | -fpie \ 32 | -std=c++20 \ 33 | -gdwarf \ 34 | -O0 \ 35 | -mno-red-zone \ 36 | -msse3 \ 37 | -fno-threadsafe-statics \ 38 | -fno-omit-frame-pointer \ 39 | $(WRFLAGS) 40 | 41 | LDFLAGS = -ffreestanding \ 42 | -nostdlib \ 43 | -fno-pic \ 44 | -fpie \ 45 | -static-pie \ 46 | -pie \ 47 | -z max-page-size=0x1000 \ 48 | -lgcc \ 49 | -T $(LDS) 50 | 51 | ASFLAGS = \ 52 | -f elf64 \ 53 | -g \ 54 | -F dwarf 55 | 56 | .DEFAULT-GOAL = all 57 | .PHONY = all kernel clean 58 | 59 | $(OBJDIR)/%.cc.o: $(SRCDIR)/%.cpp 60 | @ echo "] CC $^" 61 | @ mkdir -p $(@D) 62 | @ $(CC) $(CCFLAGS) -c $^ -o $@ 63 | 64 | $(OBJDIR)/%.as.o: $(SRCDIR)/%.asm 65 | @ echo "] AS $^" 66 | @ mkdir -p $(@D) 67 | @ $(AS) $(ASFLAGS) $^ -o $@ 68 | 69 | $(KERNEL): $(OBJS) 70 | @ echo "] LD $@" 71 | @ $(CC) $(LDFLAGS) $(OBJS) -o $@ 72 | 73 | 74 | @ echo "] GS $@" 75 | @ $(GS) $@ 76 | 77 | @ echo "] CC syms.gen" 78 | @ $(CC) -fno-pic -fpie -xc -c syms.gen -o $(SYMS) 79 | 80 | @ echo "] RM syms.gen" 81 | @ rm syms.gen 82 | 83 | @ echo "] LD $@" 84 | @ $(CC) $(LDFLAGS) $(OBJS) $(SYMS) -o $@ 85 | 86 | all: $(KERNEL) 87 | kernel: $(KERNEL) 88 | 89 | clean: 90 | @ rm -rf bin -------------------------------------------------------------------------------- /kernel/gensyms.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "/*\n Auto-generated by gensyms.sh." > syms.gen 4 | echo " DO NOT EDIT\n*/\n\n#include \"src/symbols.h\"\n" >> syms.gen 5 | echo "const symbol __kernel_symtab[] = {" >> syms.gen 6 | nm $1 | grep -i " t " | awk '{ print " { .addr = 0x"$1", .name = \""$3"\" }," }' | sort >> syms.gen 7 | echo " { .addr = 0xffffffffffffffff, .name = \"\" }\n};" >> syms.gen -------------------------------------------------------------------------------- /kernel/src/boot/boot.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by rizet on 11/27/20. 3 | // 4 | 5 | #include "boot/boot.h" 6 | 7 | // The stivale2 specification says we need to define a "header structure". 8 | // This structure needs to reside in the .stivale2hdr ELF section in order 9 | // for the bootloader to find it. We use this __attribute__ directive to 10 | // tell the compiler to put the following structure in said section. 11 | __attribute__((section(".stivalehdr"), used)) 12 | struct stivale_header stivale_hdr = { 13 | 14 | .stack = 0, 15 | 16 | .flags = 0b001, 17 | 18 | .framebuffer_width = 0, 19 | 20 | .framebuffer_height = 0, 21 | 22 | .framebuffer_bpp = 32, 23 | 24 | .entry_point = 0, 25 | }; -------------------------------------------------------------------------------- /kernel/src/boot/boot.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | #include "drivers/acpi/acpi.h" 5 | 6 | /* --- Header --------------------------------------------------------------- */ 7 | /* Information passed from the kernel to the bootloader */ 8 | 9 | 10 | 11 | struct stivale_header { 12 | address stack; 13 | word flags; 14 | uint16 framebuffer_width; 15 | uint16 framebuffer_height; 16 | uint16 framebuffer_bpp; 17 | address entry_point; 18 | } __attribute__((packed)); 19 | 20 | /* --- Struct --------------------------------------------------------------- */ 21 | /* Information passed from the bootloader to the kernel */ 22 | 23 | struct stivale_module { 24 | address begin; 25 | address end; 26 | char string[128]; 27 | address next; 28 | } __attribute__((__packed__)); 29 | 30 | #define STIVALE_MMAP_USABLE 1 31 | #define STIVALE_MMAP_RESERVED 2 32 | #define STIVALE_MMAP_ACPI_RECLAIMABLE 3 33 | #define STIVALE_MMAP_ACPI_NVS 4 34 | #define STIVALE_MMAP_BAD_MEMORY 5 35 | #define STIVALE_MMAP_KERNEL_AND_MODULES 10 36 | #define STIVALE_MMAP_BOOTLOADER_RECLAIMABLE 0x1000 37 | 38 | struct stivale_mmap_entry { 39 | address base; 40 | uint64 length; 41 | uint32 type; 42 | uint32 unused; 43 | } __attribute__((packed)); 44 | 45 | struct stivale_framebuffer { 46 | address framebuffer_addr; 47 | uint16 framebuffer_pitch; 48 | uint16 framebuffer_width; 49 | uint16 framebuffer_height; 50 | uint16 framebuffer_bpp; 51 | } __attribute__((packed)); 52 | 53 | struct stivale_memory_map { 54 | address memory_map_addr; 55 | uint64 memory_map_entries; 56 | } __attribute__((packed)); 57 | 58 | #define STIVALE_FBUF_MMODEL_RGB 1 59 | 60 | struct stivale_struct { 61 | address cmdline; 62 | stivale_memory_map memory_map; 63 | stivale_framebuffer framebuffer; 64 | sys::acpi::rsdp2* rsdp; 65 | uint64 module_count; 66 | address modules; 67 | uint64 epoch; 68 | qword flags; // bit 0: 1 if booted with BIOS, 0 if booted with UEFI 69 | // bit 1: 1 if extended colour information passed, 0 if not 70 | uint08 fb_memory_model; 71 | uint08 fb_red_mask_size; 72 | uint08 fb_red_mask_shift; 73 | uint08 fb_green_mask_size; 74 | uint08 fb_green_mask_shift; 75 | uint08 fb_blue_mask_size; 76 | uint08 fb_blue_mask_shift; 77 | } __attribute__((packed)); -------------------------------------------------------------------------------- /kernel/src/boot/kconf.cpp: -------------------------------------------------------------------------------- 1 | #include "boot/kconf.h" 2 | #include "boot/boot.h" 3 | #include "drivers/io.h" 4 | #include "drivers/acpi/pci.h" 5 | #include "util/kutil.h" 6 | #include "memory/paging.h" 7 | #include "memory/operations.h" 8 | #include "memory/pmm.h" 9 | #include "memory/heap.h" 10 | #include "drivers/tty/tty.h" 11 | #include "drivers/gfx/gop/gop.h" 12 | #include "util/bitmap.h" 13 | 14 | uint64 sys::config::__kernel_pages; 15 | uint64 sys::config::__kernel_size; 16 | 17 | extern util::bitmap page_bitmap_map; 18 | 19 | extern "C" void configure_pat(); 20 | 21 | void sys::config::setup_paging(stivale_framebuffer *framebuffer) 22 | { 23 | configure_pat(); 24 | 25 | memory::paging::pml_4 = (memory::paging::page_table *)memory::pmm::request_page(); 26 | 27 | memory::operations::memset(memory::paging::pml_4, 0, 0x1000); 28 | 29 | memory::paging::map_memory((void*)memory::paging::pml_4, (void*)memory::paging::pml_4, false); 30 | 31 | for (address t = 0x0; t < memory::pmm::get_total_memory_size(nullptr, 0, 0); t+=0x1000) 32 | { memory::paging::map_memory((void *)t, (void *)t, false); } 33 | 34 | address fb_base = (address)framebuffer->framebuffer_addr; 35 | uint64 fb_size = (((uint64)framebuffer->framebuffer_width * framebuffer->framebuffer_height * (framebuffer->framebuffer_bpp / 8) + 1024)); 36 | 37 | for (uint64 t = fb_base; t < fb_base + fb_size; t+=0x1000) 38 | { memory::paging::map_memory((void*)t, (void*)t, true); } 39 | 40 | asm volatile ("mov %0, %%cr3" : : "r" (memory::paging::pml_4)); 41 | } 42 | 43 | void sys::config::configure_memory(stivale_framebuffer *framebuffer, stivale_memory_map *memory_map) 44 | { 45 | memory::operations::memset((void *)framebuffer->framebuffer_addr, 0xFF, 0xFFFF); 46 | memory::pmm::initialize(memory_map, memory_map->memory_map_entries * sizeof(stivale_mmap_entry), sizeof(stivale_mmap_entry)); 47 | 48 | sys::config::setup_paging(framebuffer); 49 | 50 | for (int t = 0; t < 0x100; t++) { 51 | void* pos = (void*)0xffff800000000000; 52 | memory::paging::map_memory(pos, memory::pmm::request_page(), false); 53 | pos = (void*)((uint64)pos + 0x1000); 54 | } 55 | 56 | memory::heap::initialize_heap((void*)0xffff800000000000, 0x100000); 57 | } 58 | 59 | void sys::config::configure_graphics(stivale_framebuffer *framebuffer) 60 | { 61 | gfx::gop = *(framebuffer); 62 | 63 | gfx::buffer = (uint32 *)memory::pmm::request_pages(gfx::gop.framebuffer_width * gfx::gop.framebuffer_height * (gfx::gop.framebuffer_bpp / 8) / 0x1000 + 1); 64 | 65 | io::tty::initialize(); 66 | } 67 | 68 | void sys::config::configure_pci(sys::acpi::rsdp2* rsdp) 69 | { 70 | sys::acpi::rsdp = rsdp; 71 | sys::acpi::mcfg_header* mcfg = (sys::acpi::mcfg_header *)sys::acpi::get_table((char *)"MCFG"); 72 | io::pci::mcfg = mcfg; 73 | io::pci::enumerate_pci(); 74 | } 75 | 76 | void sys::config::calculate_kernel_size() 77 | { 78 | __kernel_size = (address)&__kernel_end - (address)&__kernel_start; 79 | __kernel_pages = (uint64)__kernel_size / 4096 + 1; 80 | } 81 | 82 | extern "C" void uentry(); 83 | void sys::config::configure_userspace() 84 | { 85 | memory::paging::donate_to_userspace((void *)uentry); 86 | } -------------------------------------------------------------------------------- /kernel/src/boot/kconf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "types.h" 4 | #include "symbols.h" 5 | #include "boot/boot.h" 6 | #include "drivers/acpi/acpi.h" 7 | 8 | namespace sys { 9 | namespace config { 10 | extern "C" uint64 __kernel_start; 11 | extern "C" uint64 __kernel_end; 12 | extern "C" __attribute__((weak)) const symbol __kernel_symtab[]; 13 | extern uint64 __kernel_size; 14 | extern uint64 __kernel_pages; 15 | void calculate_kernel_size(); 16 | void setup_paging(stivale_framebuffer *framebuffer); 17 | void configure_memory(stivale_framebuffer *framebuffer, stivale_memory_map *memory_map); 18 | void configure_graphics(stivale_framebuffer *framebuffer); 19 | void configure_pci(sys::acpi::rsdp2* rsdp); 20 | void configure_userspace(); 21 | } 22 | } -------------------------------------------------------------------------------- /kernel/src/boot/kentry.asm: -------------------------------------------------------------------------------- 1 | extern mnkmain 2 | extern load_idt 3 | extern gdt_init 4 | extern configure_pic 5 | extern enter_userspace 6 | 7 | default rel 8 | 9 | mnkentry: 10 | 11 | mov r15, rdi ; preserve parameters 12 | 13 | lea rsp, [rel stack.end] ; reconfigure the stack 14 | 15 | xor rbp, rbp 16 | push rbp 17 | mov rbp, rsp 18 | 19 | ; replace the UEFI-owned 20 | ; existing GDT and IDT, ofc 21 | 22 | cli ; clear the interrupt flag 23 | 24 | ; gdt 25 | lea r14, [rel gdt_init] 26 | call r14 27 | 28 | ; pic 29 | lea r14, [rel configure_pic] 30 | call r14 31 | 32 | mov rdi, r15 ; bring back original rdi 33 | mov rsi, rsp ; pass rsp to kernel for tss 34 | 35 | lea r14, [rel mnkmain] 36 | call r14 ; call kernel to configure 37 | 38 | lea r14, [rel enter_userspace] 39 | call r14 40 | global mnkentry:function ($ - mnkentry) 41 | 42 | section .bss 43 | 44 | stack: 45 | resb 4096 ; one page 46 | .end: -------------------------------------------------------------------------------- /kernel/src/boot/kmain.cpp: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "drivers/kbd/kbd.h" 3 | #include "drivers/io.h" 4 | #include "boot/boot.h" 5 | #include "cpu/interrupts.h" 6 | #include "drivers/gfx/gop/gop.h" 7 | #include "drivers/acpi/power.h" 8 | #include "scheduling/timer.h" 9 | #include "drivers/audio/beeper/beeper.h" 10 | #include "boot/kconf.h" 11 | #include "drivers/uart/serial.h" 12 | #include "cpu/tss.h" 13 | #include "drivers/disk/ahci/ahci.h" 14 | 15 | #ifndef ARCH 16 | #define ARCH "$RED!UNKNOWN" 17 | #endif 18 | 19 | extern "C" void mnkmain(stivale_struct *bootloader_info, uint stack) 20 | { 21 | // do some startup configurations 22 | sys::config::calculate_kernel_size(); 23 | sys::config::configure_memory(&(bootloader_info->framebuffer), &(bootloader_info->memory_map)); 24 | cpu::tss::tss_install(0, stack); 25 | cpu::idt::load_idt(); 26 | asm volatile ("sti"); 27 | sys::config::configure_graphics(&(bootloader_info->framebuffer)); 28 | sys::config::configure_pci(bootloader_info->rsdp); 29 | 30 | io::pit::set_c0_frequency(1000); 31 | io::pit::pit_init(); 32 | 33 | sys::audio::pcspk::init(); 34 | 35 | io::keyboard::init(); 36 | 37 | sys::config::configure_userspace(); 38 | } -------------------------------------------------------------------------------- /kernel/src/cpu/gdt.asm: -------------------------------------------------------------------------------- 1 | global load_gdt 2 | global load_tss 3 | 4 | default rel 5 | 6 | load_gdt: 7 | lgdt [rdi] ; Load the new GDT pointer 8 | mov ax, 0x10 9 | mov ds, ax 10 | mov es, ax 11 | mov fs, ax 12 | mov gs, ax 13 | mov ss, ax 14 | pop rax 15 | push 0x08 16 | push rax 17 | retfq 18 | 19 | load_tss: 20 | ltr di 21 | ret -------------------------------------------------------------------------------- /kernel/src/cpu/gdt.cpp: -------------------------------------------------------------------------------- 1 | #include "cpu/gdt.h" 2 | 3 | static __attribute__((aligned(0x1000))) cpu::gdt::gdt_desc_t s_gdt_descriptors[cpu::gdt::GDT_MAX_DESCRIPTORS]; 4 | static cpu::gdt::gdt_t s_gdt; 5 | static uint32 s_gdt_index; 6 | 7 | constexpr uint08 BASE_DESC = cpu::gdt::GDT_DESC_PRESENT | cpu::gdt::GDT_DESC_READWRITE | cpu::gdt::GDT_DESC_CODEDATA; 8 | constexpr uint08 BASE_GRAN = cpu::gdt::GDT_GRAN_64BIT | cpu::gdt::GDT_GRAN_4K; 9 | 10 | extern "C" void cpu::gdt::gdt_init() { 11 | s_gdt.limit = (sizeof(cpu::gdt::gdt_desc_t) * cpu::gdt::GDT_MAX_DESCRIPTORS) - 1; 12 | s_gdt.base = (uint64)&s_gdt_descriptors[0]; 13 | 14 | // NULL first 15 | gdt_install_descriptor(0, 0, 0, 0); 16 | 17 | // KERNEL CODE 18 | gdt_install_descriptor(0, 0, BASE_DESC | GDT_DESC_EXECUTABLE, BASE_GRAN); 19 | 20 | // KERNEL DATA 21 | gdt_install_descriptor(0, 0, BASE_DESC, BASE_GRAN); 22 | 23 | // USER DATA 24 | gdt_install_descriptor(0, 0, BASE_DESC | GDT_DESC_DPL, BASE_GRAN); 25 | 26 | // USER CODE 27 | gdt_install_descriptor(0, 0, BASE_DESC | GDT_DESC_EXECUTABLE | GDT_DESC_DPL, BASE_GRAN); 28 | 29 | load_gdt(&s_gdt); 30 | } 31 | 32 | void cpu::gdt::gdt_install_descriptor(address base, address limit, byte access, byte granularity) { 33 | if (s_gdt_index >= cpu::gdt::GDT_MAX_DESCRIPTORS) 34 | return; 35 | 36 | s_gdt_descriptors[s_gdt_index].base_low = (word)(base & 0xFFFF); 37 | s_gdt_descriptors[s_gdt_index].base_mid = (byte)((base >> 16) & 0xFF); 38 | s_gdt_descriptors[s_gdt_index].base_high = (byte)((base >> 24) & 0xFF); 39 | s_gdt_descriptors[s_gdt_index].limit = (word)(limit & 0xFFFF); 40 | 41 | s_gdt_descriptors[s_gdt_index].flags = access; 42 | s_gdt_descriptors[s_gdt_index].granularity = (byte)((limit >> 16) & 0x0F); 43 | s_gdt_descriptors[s_gdt_index].granularity |= granularity & 0xF0; 44 | 45 | s_gdt_index++; 46 | } 47 | 48 | void cpu::gdt::gdt_install_tss(uint64 base, uint64 limit) { 49 | word tss_type = cpu::gdt::GDT_DESC_ACCESS | cpu::gdt::GDT_DESC_EXECUTABLE | cpu::gdt::GDT_DESC_PRESENT; 50 | cpu::gdt::gdt_system_desc_t* gdt_desc = (cpu::gdt::gdt_system_desc_t *)&s_gdt_descriptors[s_gdt_index]; 51 | 52 | if (s_gdt_index >= cpu::gdt::GDT_MAX_DESCRIPTORS) 53 | return; 54 | 55 | gdt_desc->type_0 = (word)(tss_type & 0x00FF); 56 | 57 | gdt_desc->addr_0 = base & 0xFFFF; 58 | gdt_desc->addr_1 = (base & 0xFF0000) >> 16; 59 | gdt_desc->addr_2 = (base & 0xFF000000) >> 24; 60 | gdt_desc->addr_3 = base >> 32; 61 | 62 | gdt_desc->limit_0 = limit & 0xFFFF; 63 | gdt_desc->limit_1 = (limit & 0xF0000) >> 16; 64 | 65 | gdt_desc->reserved = 0; 66 | 67 | s_gdt_index += 2; 68 | } -------------------------------------------------------------------------------- /kernel/src/cpu/gdt.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by rizet on 1/26/21. 3 | // 4 | #pragma once 5 | #include "types.h" 6 | 7 | /* 8 | * Credit: Jim Borden (borrrden) on GitHub 9 | * https://github.com/borrrden/borrrdex 10 | * There was no legal need for this source disclosure. 11 | * The code is licensed under the Unlicense. 12 | * I felt it was necessary to give credit. 13 | */ 14 | namespace cpu 15 | { 16 | namespace gdt 17 | { 18 | constexpr byte GDT_MAX_DESCRIPTORS = 16; 19 | constexpr byte GDT_DESC_ACCESS = 0x01; 20 | constexpr byte GDT_DESC_READWRITE = 0x02; 21 | constexpr byte GDT_DESC_DC = 0x04; 22 | constexpr byte GDT_DESC_EXECUTABLE = 0x08; 23 | constexpr byte GDT_DESC_CODEDATA = 0x10; 24 | constexpr byte GDT_DESC_DPL = 0x60; 25 | constexpr byte GDT_DESC_PRESENT = 0x80; 26 | constexpr byte GDT_GRAN_LIMITHIMAST = 0x0F; 27 | constexpr byte GDT_GRAN_OS = 0x10; 28 | constexpr byte GDT_GRAN_64BIT = 0x20; 29 | constexpr byte GDT_GRAN_32BIT = 0x40; 30 | constexpr byte GDT_GRAN_4K = 0x80; 31 | 32 | // Predefined selectors 33 | constexpr byte GDT_SELECTOR_KERNEL_CODE = (0x01 << 3); 34 | constexpr byte GDT_SELECTOR_KERNEL_DATA = (0x02 << 3); 35 | constexpr byte GDT_SELECTOR_USER_DATA = (0x03 << 3); 36 | constexpr byte GDT_SELECTOR_USER_CODE = (0x04 << 3); 37 | 38 | typedef struct gdt_descriptor { 39 | word limit; 40 | word base_low; 41 | byte base_mid; 42 | byte flags; 43 | byte granularity; 44 | byte base_high; 45 | } __attribute__((packed)) gdt_desc_t; 46 | 47 | typedef struct gdt_system_descriptor { 48 | word limit_0; 49 | word addr_0; 50 | byte addr_1; 51 | byte type_0; 52 | byte limit_1; 53 | byte addr_2; 54 | dword addr_3; 55 | dword reserved; 56 | } __attribute__((packed)) gdt_system_desc_t; 57 | 58 | typedef struct gdt { 59 | word limit; 60 | address base; 61 | } __attribute__((packed)) gdt_t; 62 | 63 | extern "C" void gdt_init(); 64 | 65 | void gdt_install_descriptor(address base, address limit, byte access, byte granularity); 66 | 67 | void gdt_install_tss(address base, address limit); 68 | 69 | extern "C" void load_gdt(cpu::gdt::gdt_t *); 70 | } 71 | } -------------------------------------------------------------------------------- /kernel/src/cpu/interrupts.asm: -------------------------------------------------------------------------------- 1 | ; Defined in idt.cxx 2 | extern isr_handler 3 | extern irq_handler 4 | 5 | global lidt 6 | 7 | default rel 8 | 9 | lidt: 10 | lidt [rdi] 11 | ret 12 | 13 | 14 | 15 | ; We don't get information about which interrupt was caller 16 | ; when the handler is run, so we will need to have a different handler 17 | ; for every interrupt. 18 | ; Furthermore, some interrupts push an error code onto the stack but others 19 | ; don't, so we will push a dummy error code for those which don't, so that 20 | ; we have a consistent stack for all of them. 21 | 22 | ; First make the ISRs global 23 | global isr0 24 | global isr1 25 | global isr2 26 | global isr3 27 | global isr4 28 | global isr5 29 | global isr6 30 | global isr7 31 | global isr8 32 | global isr9 33 | global isr10 34 | global isr11 35 | global isr12 36 | global isr13 37 | global isr14 38 | global isr15 39 | global isr16 40 | global isr17 41 | global isr18 42 | global isr19 43 | global isr20 44 | global isr21 45 | global isr22 46 | global isr23 47 | global isr24 48 | global isr25 49 | global isr26 50 | global isr27 51 | global isr28 52 | global isr29 53 | global isr30 54 | global isr31 55 | ; then IRQs 56 | 57 | global irq0 58 | global irq1 59 | global irq2 60 | global irq3 61 | global irq4 62 | global irq5 63 | global irq6 64 | global irq7 65 | global irq8 66 | global irq9 67 | global irq10 68 | global irq11 69 | global irq12 70 | global irq13 71 | global irq14 72 | global irq15 73 | 74 | global isr_common_stub 75 | global irq_common_stub 76 | 77 | ; 0: Divide By Zero Exception 78 | isr0: 79 | push 0 80 | push 0 81 | lea r14, [rel isr_common_stub] 82 | jmp r14 83 | 84 | 85 | ; Seems this interrupt is raised without reason. 86 | ; e.g. is raised on a nop in $print. 87 | ; Ignored, however this is not a long term solution. 88 | ; 1: Debug Exception 89 | isr1: 90 | ; push 0 91 | ; push 0 92 | ; lea r14, [rel isr_common_stub] 93 | ; jmp r14 94 | iretq 95 | 96 | ; 2: Non Maskable Interrupt Exception 97 | isr2: 98 | push 0 99 | push 2 100 | lea r14, [rel isr_common_stub] 101 | jmp r14 102 | 103 | 104 | ; 3: Breakpoint Exception 105 | isr3: 106 | push 0 107 | push 3 108 | lea r14, [rel isr_common_stub] 109 | jmp r14 110 | 111 | 112 | ; 4: INTO Exception 113 | isr4: 114 | push 0 115 | push 4 116 | lea r14, [rel isr_common_stub] 117 | jmp r14 118 | 119 | 120 | ; 5: Out of Bounds Exception 121 | isr5: 122 | push 0 123 | push 5 124 | lea r14, [rel isr_common_stub] 125 | jmp r14 126 | 127 | 128 | ; 6: Invalid Opcode Exception 129 | isr6: 130 | push 0 131 | push 6 132 | lea r14, [rel isr_common_stub] 133 | jmp r14 134 | 135 | 136 | ; 7: Coprocessor Not Available Exception 137 | isr7: 138 | push 0 139 | push 7 140 | lea r14, [rel isr_common_stub] 141 | jmp r14 142 | 143 | 144 | ; 8: Double Fault Exception (With Error Code!) 145 | isr8: 146 | push 8 147 | lea r14, [rel isr_common_stub] 148 | jmp r14 149 | 150 | 151 | ; 9: Coprocessor Segment Overrun Exception 152 | isr9: 153 | push 0 154 | push 9 155 | lea r14, [rel isr_common_stub] 156 | jmp r14 157 | 158 | 159 | ; 10: Bad TSS Exception (With Error Code!) 160 | isr10: 161 | push 10 162 | lea r14, [rel isr_common_stub] 163 | jmp r14 164 | 165 | 166 | ; 11: Segment Not Present Exception (With Error Code!) 167 | isr11: 168 | push 11 169 | lea r14, [rel isr_common_stub] 170 | jmp r14 171 | 172 | 173 | ; 12: Stack Fault Exception (With Error Code!) 174 | isr12: 175 | push 12 176 | lea r14, [rel isr_common_stub] 177 | jmp r14 178 | 179 | 180 | ; 13: General Protection Fault Exception (With Error Code!) 181 | isr13: 182 | push 13 183 | lea r14, [rel isr_common_stub] 184 | jmp r14 185 | 186 | 187 | ; 14: Page Fault Exception (With Error Code!) 188 | isr14: 189 | push 14 190 | lea r14, [rel isr_common_stub] 191 | jmp r14 192 | 193 | 194 | ; 15: Reserved Exception 195 | isr15: 196 | push 0 197 | push 15 198 | lea r14, [rel isr_common_stub] 199 | jmp r14 200 | 201 | 202 | ; 16: Floating Point Exception 203 | isr16: 204 | push 0 205 | push 16 206 | lea r14, [rel isr_common_stub] 207 | jmp r14 208 | 209 | 210 | ; 17: Alignment Check Exception 211 | isr17: 212 | push 0 213 | push 17 214 | lea r14, [rel isr_common_stub] 215 | jmp r14 216 | 217 | 218 | ; 18: Machine Check Exception 219 | isr18: 220 | push 0 221 | push 18 222 | lea r14, [rel isr_common_stub] 223 | jmp r14 224 | 225 | 226 | ; 19: Reserved 227 | isr19: 228 | push 0 229 | push 19 230 | lea r14, [rel isr_common_stub] 231 | jmp r14 232 | 233 | 234 | ; 20: Reserved 235 | isr20: 236 | push 0 237 | push 20 238 | lea r14, [rel isr_common_stub] 239 | jmp r14 240 | 241 | 242 | ; 21: Reserved 243 | isr21: 244 | push 0 245 | push 21 246 | lea r14, [rel isr_common_stub] 247 | jmp r14 248 | 249 | 250 | ; 22: Reserved 251 | isr22: 252 | push 0 253 | push 22 254 | lea r14, [rel isr_common_stub] 255 | jmp r14 256 | 257 | 258 | ; 23: Reserved 259 | isr23: 260 | push 0 261 | push 23 262 | lea r14, [rel isr_common_stub] 263 | jmp r14 264 | 265 | 266 | ; 24: Reserved 267 | isr24: 268 | push 0 269 | push 24 270 | lea r14, [rel isr_common_stub] 271 | jmp r14 272 | 273 | 274 | ; 25: Reserved 275 | isr25: 276 | push 0 277 | push 25 278 | lea r14, [rel isr_common_stub] 279 | jmp r14 280 | 281 | 282 | ; 26: Reserved 283 | isr26: 284 | push 0 285 | push 26 286 | lea r14, [rel isr_common_stub] 287 | jmp r14 288 | 289 | 290 | ; 27: Reserved 291 | isr27: 292 | push 0 293 | push 27 294 | lea r14, [rel isr_common_stub] 295 | jmp r14 296 | 297 | 298 | ; 28: Reserved 299 | isr28: 300 | push 0 301 | push 28 302 | lea r14, [rel isr_common_stub] 303 | jmp r14 304 | 305 | 306 | ; 29: Reserved 307 | isr29: 308 | push 0 309 | push 29 310 | lea r14, [rel isr_common_stub] 311 | jmp r14 312 | 313 | 314 | ; 30: Reserved 315 | isr30: 316 | push 0 317 | push 30 318 | lea r14, [rel isr_common_stub] 319 | jmp r14 320 | 321 | 322 | ; 31: Reserved 323 | isr31: 324 | push 0 325 | push 31 326 | lea r14, [rel isr_common_stub] 327 | jmp r14 328 | 329 | 330 | ; IRQ handlers 331 | 332 | ; This IRQ is the Programmable Interval Timer. Since it spams us with 333 | ; interrupts, we will ignore it until we have a use for chronology 334 | irq0: 335 | push 0 336 | push 32 337 | lea r14, [rel irq_common_stub] 338 | jmp r14 339 | 340 | 341 | irq1: 342 | push 1 343 | push 33 344 | lea r14, [rel irq_common_stub] 345 | jmp r14 346 | 347 | 348 | irq2: 349 | push 2 350 | push 34 351 | lea r14, [rel irq_common_stub] 352 | jmp r14 353 | 354 | 355 | irq3: 356 | push 3 357 | push 35 358 | lea r14, [rel irq_common_stub] 359 | jmp r14 360 | 361 | 362 | irq4: 363 | push 4 364 | push 36 365 | lea r14, [rel irq_common_stub] 366 | jmp r14 367 | 368 | 369 | irq5: 370 | push 5 371 | push 37 372 | lea r14, [rel irq_common_stub] 373 | jmp r14 374 | 375 | 376 | irq6: 377 | push 6 378 | push 38 379 | lea r14, [rel irq_common_stub] 380 | jmp r14 381 | 382 | 383 | irq7: 384 | push 7 385 | push 39 386 | lea r14, [rel irq_common_stub] 387 | jmp r14 388 | 389 | 390 | irq8: 391 | push 8 392 | push 40 393 | lea r14, [rel irq_common_stub] 394 | jmp r14 395 | 396 | 397 | irq9: 398 | push 9 399 | push 41 400 | lea r14, [rel irq_common_stub] 401 | jmp r14 402 | 403 | 404 | irq10: 405 | push 10 406 | push 42 407 | lea r14, [rel irq_common_stub] 408 | jmp r14 409 | 410 | 411 | irq11: 412 | push 11 413 | push 43 414 | lea r14, [rel irq_common_stub] 415 | jmp r14 416 | 417 | 418 | irq12: 419 | push 12 420 | push 44 421 | lea r14, [rel irq_common_stub] 422 | jmp r14 423 | 424 | 425 | irq13: 426 | push 13 427 | push 45 428 | lea r14, [rel irq_common_stub] 429 | jmp r14 430 | 431 | 432 | irq14: 433 | push 14 434 | push 46 435 | lea r14, [rel irq_common_stub] 436 | jmp r14 437 | 438 | 439 | irq15: 440 | push 15 441 | push 47 442 | lea r14, [rel irq_common_stub] 443 | jmp r14 444 | 445 | 446 | %macro pusha 0 447 | push rax 448 | push rcx 449 | push rdx 450 | push rbx 451 | push rbp 452 | push rsi 453 | push rdi 454 | %endmacro 455 | 456 | %macro popa 0 457 | pop rdi 458 | pop rsi 459 | pop rbp 460 | pop rbx 461 | pop rdx 462 | pop rcx 463 | pop rax 464 | %endmacro 465 | 466 | ; Common ISR code 467 | isr_common_stub: 468 | ; Save CPU state into a structure, 469 | ; assembled onto the stack 470 | pusha ; Pushes rdi, rsi, rbp and r[a-d]x 471 | mov ax, ds ; Set the lower 16 bits of rax to ds 472 | push rax ; save the value of rax, which is now ds 473 | mov ax, 0x10 ; kernel data segment descriptor 474 | mov ds, ax 475 | mov es, ax 476 | mov fs, ax 477 | mov gs, ax 478 | 479 | mov rax, cr0 480 | push rax ; gp control register 481 | mov rax, cr2 482 | push rax ; page fault faulty addy 483 | mov rax, cr3 484 | push rax ; paging table ptr 485 | mov rax, cr4 486 | push rax ; gp control register 487 | 488 | ; Since we assembled the struct 489 | ; on the stack, we can simply 490 | ; pass the stack pointer as a 491 | ; pointer to our structure 492 | mov rdi, rsp 493 | 494 | ; 2. Call C handler 495 | cld 496 | call isr_handler 497 | 498 | ; 3. Restore state 499 | pop rdx 500 | pop rdx 501 | pop rdx 502 | pop rdx 503 | pop rbx 504 | mov ds, bx 505 | mov es, bx 506 | mov fs, bx 507 | mov gs, bx 508 | popa 509 | add rsp, 16 ; Cleans up the pushed error code and pushed ISR number 510 | iretq ; pops 5 things at once: CS, RIP, RFLAGS, SS, and RSP 511 | 512 | 513 | ; Common IRQ code. Identical to ISR code except for the 'call' 514 | ; and the 'pop ebx' 515 | irq_common_stub: 516 | ; Save CPU state into a structure, 517 | ; assembled onto the stack 518 | pusha ; Pushes rdi, rsi, rbp and r[a-d]x 519 | mov ax, ds ; Set the lower 16 bits of rax to ds 520 | push rax ; save the value of rax, which is now ds 521 | mov ax, 0x10 ; kernel data segment descriptor 522 | mov ds, ax 523 | mov es, ax 524 | mov fs, ax 525 | mov gs, ax 526 | 527 | mov rax, cr0 528 | push rax ; gp control register 529 | mov rax, cr2 530 | push rax ; page fault faulty addy 531 | mov rax, cr3 532 | push rax ; page fault error info 533 | mov rax, cr4 534 | push rax ; gp control register 535 | 536 | ; Since we assembled the struct 537 | ; on the stack, we can simply 538 | ; pass the stack pointer as a 539 | ; pointer to our structure 540 | mov rdi, rsp 541 | 542 | ; 2. Call C handler 543 | cld 544 | lea r14, [rel irq_handler] 545 | call r14 546 | 547 | ; 3. Restore state 548 | pop rdx 549 | pop rdx 550 | pop rdx 551 | pop rdx 552 | pop rax 553 | mov ds, ax 554 | mov es, ax 555 | mov fs, ax 556 | mov gs, ax 557 | popa 558 | add rsp, 16 ; Cleans up the pushed error code and pushed ISR number 559 | iretq ; pops 5 things at once: CS, RIP, RFLAGS, SS, and RSP 560 | -------------------------------------------------------------------------------- /kernel/src/cpu/interrupts.cpp: -------------------------------------------------------------------------------- 1 | #include "memory/operations.h" 2 | #include "cpu/interrupts.h" 3 | #include "drivers/tty/tty.h" 4 | #include "drivers/io.h" 5 | #include "util/kutil.h" 6 | #include "drivers/kbd/kbd.h" 7 | #include "drivers/acpi/power.h" 8 | #include "drivers/uart/serial.h" 9 | #include "scheduling/timer.h" 10 | #include "boot/kconf.h" 11 | 12 | extern "C" 13 | { 14 | 15 | cpu::idt::idt_descriptor idt_s[256]; 16 | cpu::idt::idt_ptr idtPointer; 17 | 18 | extern void isr0(); 19 | extern void isr1(); 20 | extern void isr2(); 21 | extern void isr3(); 22 | extern void isr4(); 23 | extern void isr5(); 24 | extern void isr6(); 25 | extern void isr7(); 26 | extern void isr8(); 27 | extern void isr9(); 28 | extern void isr10(); 29 | extern void isr11(); 30 | extern void isr12(); 31 | extern void isr13(); 32 | extern void isr14(); 33 | extern void isr15(); 34 | extern void isr16(); 35 | extern void isr17(); 36 | extern void isr18(); 37 | extern void isr19(); 38 | extern void isr20(); 39 | extern void isr21(); 40 | extern void isr22(); 41 | extern void isr23(); 42 | extern void isr24(); 43 | extern void isr25(); 44 | extern void isr26(); 45 | extern void isr27(); 46 | extern void isr28(); 47 | extern void isr29(); 48 | extern void isr30(); 49 | extern void isr31(); 50 | extern void irq0(); 51 | extern void irq1(); 52 | extern void irq2(); 53 | extern void irq3(); 54 | extern void irq4(); 55 | extern void irq5(); 56 | extern void irq6(); 57 | extern void irq7(); 58 | extern void irq8(); 59 | extern void irq9(); 60 | extern void irq10(); 61 | extern void irq11(); 62 | extern void irq12(); 63 | extern void irq13(); 64 | extern void irq14(); 65 | extern void irq15(); 66 | extern void lidt(address); 67 | 68 | typedef struct s_registers 69 | { 70 | qword cr4; 71 | qword cr3; 72 | qword cr2; 73 | qword cr0; 74 | qword ds; 75 | qword rdi; 76 | qword rsi; 77 | qword rbp; 78 | qword rbx; 79 | qword rdx; 80 | qword rcx; 81 | qword rax; 82 | qword interrupt_number; 83 | qword error_code; 84 | qword rip; 85 | qword cs; 86 | qword rflags; 87 | qword rsp; 88 | } registers; 89 | 90 | const char* exception_messages[32] { 91 | "Division by Zero", 92 | "Debug", 93 | "Non-maskable interrupt", 94 | "Breakpoint", 95 | "Overflow", 96 | "Bound Range Exceeded", 97 | "Invalid Opcode", 98 | "Device Not Available", 99 | "Double Fault", 100 | "Coprocessor Segment Overrun", 101 | "Invalid TSS", 102 | "Segment Not Present", 103 | "Stack-Segment Fault", 104 | "General Protection Fault", 105 | "Page Fault", 106 | "Reserved", 107 | "x87 Floating-Point", 108 | "Alignment Check", 109 | "Machine Check", 110 | "SIMD Floating-Point", 111 | "Virtualization", 112 | "Reserved", 113 | "Reserved", 114 | "Reserved", 115 | "Reserved", 116 | "Reserved", 117 | "Reserved", 118 | "Reserved", 119 | "Reserved", 120 | "Reserved", 121 | "Security", 122 | "Reserved" 123 | }; 124 | 125 | enum page_fault_bit { 126 | present, 127 | write, 128 | user, 129 | reserved_write, 130 | no_execute 131 | }; 132 | 133 | char* $get_symbol_label(uint64 addr) 134 | { 135 | for (int i = 0; sys::config::__kernel_symtab[i].addr != 0xFFFFFFFFFFFFFFFF; i++) 136 | 137 | if (addr >= sys::config::__kernel_symtab[i].addr 138 | && 139 | addr < sys::config::__kernel_symtab[i + 1].addr 140 | && 141 | addr < (uint64)&sys::config::__kernel_end) 142 | 143 | return sys::config::__kernel_symtab[i].name; 144 | 145 | return (char *)""; 146 | } 147 | 148 | void exception_handler(registers& regs) 149 | { 150 | io::tty::clear(); 151 | 152 | printf("\n\tFATAL ERROR: CPU Exception: %s\n\n", exception_messages[regs.interrupt_number]); 153 | printf("\tERROR CODE: %x\n\n\n", regs.error_code); 154 | 155 | if (regs.interrupt_number == 0xE) 156 | { 157 | printf("\t\t >>> Page Fault accessing %x\n", regs.cr2); 158 | 159 | printf("\t\t\t >> accessed %s page\n", ((regs.error_code >> page_fault_bit::present) & 1) ? "protected" : "non-present"); 160 | 161 | if ((regs.error_code >> page_fault_bit::no_execute) & 1) 162 | printf("\t\t\t >> executed non-executable page\n"); 163 | 164 | printf("\t\t\t >> during %s\n", ((regs.error_code >> page_fault_bit::write) & 1) ? "write" : "read"); 165 | printf("\t\t\t >> inside %s\n", ((regs.error_code >> page_fault_bit::user) & 1) ? "userspace" : "kernel"); 166 | 167 | } 168 | 169 | uint64 kaslr_slide = ((uint64)&sys::config::__kernel_start) - 0x200000; 170 | 171 | printf("\n\t\t >>> [de-KASLR'd] Instruction Pointer\n"); 172 | printf("\t\t\t >> %x \n", regs.rip - kaslr_slide); 173 | 174 | printf("\n\t\t >>> Stacktrace\n"); 175 | 176 | printf("\t\t\t >> %s\n", $get_symbol_label(regs.rip - kaslr_slide)); 177 | 178 | uint64 rbp = regs.rbp; 179 | while (true) 180 | { 181 | if (!rbp) 182 | break; 183 | 184 | printf("\t\t\t >> %s\n", $get_symbol_label((*((uint64 *)(rbp + 8))) - kaslr_slide)); 185 | rbp = *((uint64 *)rbp); 186 | } 187 | 188 | asm volatile("cli; hlt"); 189 | cpu::power::restart_cold(); 190 | } 191 | 192 | void isr_handler(registers& regs) 193 | { 194 | exception_handler(regs); 195 | } 196 | 197 | uint32 milliseconds = 0; 198 | uint64 seconds = 0; 199 | 200 | extern void kbd_irq_handler(); 201 | 202 | void irq_handler(registers& regs) 203 | { 204 | if (regs.interrupt_number == 32) // PIT 205 | { 206 | sys::chrono::ms_clock++; 207 | milliseconds++; 208 | if (milliseconds >= io::pit::frequency_hz) 209 | { 210 | milliseconds = 0; 211 | seconds++; 212 | } 213 | } 214 | 215 | if (regs.interrupt_number == 33) // keyboard 216 | kbd_irq_handler(); 217 | 218 | if (regs.interrupt_number == 36) // com port 219 | io::serial::console::read_character(); 220 | 221 | if (regs.interrupt_number >= 40) 222 | io::outb(0xA0, 0x20); /* slave */ 223 | io::outb(0x20, 0x20); /* master */ 224 | } 225 | 226 | void idt_set(uint08 number, address base, word selector, byte flags) { 227 | /* Set Base Address */ 228 | idt_s[number].baseLow = base & 0xFFFF; 229 | idt_s[number].baseMid = (base >> 16) & 0xFFFF; 230 | idt_s[number].baseHigh = (base >> 32) & 0xFFFFFFFF; 231 | 232 | /* Set Selector */ 233 | idt_s[number].selector = selector; 234 | idt_s[number].flags = flags; 235 | 236 | 237 | /* Set IST */ 238 | if (number < 32) 239 | idt_s[number].reservedIst = 1; 240 | else if (number < 48) 241 | idt_s[number].reservedIst = 2; 242 | else 243 | idt_s[number].reservedIst = 3; 244 | 245 | /* Set Reserved Areas to Zero */ 246 | idt_s[number].reserved = 0; 247 | } 248 | 249 | void cpu::idt::load_idt() 250 | { 251 | idtPointer.limit = sizeof(cpu::idt::idt_descriptor) * 256 - 1; 252 | idtPointer.base = (address)&idt_s; 253 | 254 | memory::operations::memset((byte *)&idt_s, 0, sizeof(cpu::idt::idt_descriptor) * 256); 255 | 256 | idt_set(0, (address)isr0, 0x08, 0x8E); 257 | idt_set(1, (address)isr1, 0x08, 0x8E); 258 | idt_set(2, (address)isr2, 0x08, 0x8E); 259 | idt_set(3, (address)isr3, 0x08, 0x8E); 260 | idt_set(4, (address)isr4, 0x08, 0x8E); 261 | idt_set(5, (address)isr5, 0x08, 0x8E); 262 | idt_set(6, (address)isr6, 0x08, 0x8E); 263 | idt_set(7, (address)isr7, 0x08, 0x8E); 264 | idt_set(8, (address)isr8, 0x08, 0x8E); 265 | idt_set(9, (address)isr9, 0x08, 0x8E); 266 | idt_set(10, (address)isr10, 0x08, 0x8E); 267 | idt_set(11, (address)isr11, 0x08, 0x8E); 268 | idt_set(12, (address)isr12, 0x08, 0x8E); 269 | idt_set(13, (address)isr13, 0x08, 0x8E); 270 | idt_set(14, (address)isr14, 0x08, 0x8E); 271 | idt_set(15, (address)isr15, 0x08, 0x8E); 272 | idt_set(16, (address)isr16, 0x08, 0x8E); 273 | idt_set(17, (address)isr17, 0x08, 0x8E); 274 | idt_set(18, (address)isr18, 0x08, 0x8E); 275 | idt_set(19, (address)isr19, 0x08, 0x8E); 276 | idt_set(20, (address)isr20, 0x08, 0x8E); 277 | idt_set(21, (address)isr21, 0x08, 0x8E); 278 | idt_set(22, (address)isr22, 0x08, 0x8E); 279 | idt_set(23, (address)isr23, 0x08, 0x8E); 280 | idt_set(24, (address)isr24, 0x08, 0x8E); 281 | idt_set(25, (address)isr25, 0x08, 0x8E); 282 | idt_set(26, (address)isr26, 0x08, 0x8E); 283 | idt_set(27, (address)isr27, 0x08, 0x8E); 284 | idt_set(28, (address)isr28, 0x08, 0x8E); 285 | idt_set(29, (address)isr29, 0x08, 0x8E); 286 | idt_set(30, (address)isr30, 0x08, 0x8E); 287 | idt_set(31, (address)isr31, 0x08, 0x8E); 288 | idt_set(32, (address)irq0, 0x08, 0x8E); 289 | idt_set(33, (address)irq1, 0x08, 0x8E); 290 | idt_set(34, (address)irq2, 0x08, 0x8E); 291 | idt_set(35, (address)irq3, 0x08, 0x8E); 292 | idt_set(36, (address)irq4, 0x08, 0x8E); 293 | idt_set(37, (address)irq5, 0x08, 0x8E); 294 | idt_set(38, (address)irq6, 0x08, 0x8E); 295 | idt_set(39, (address)irq7, 0x08, 0x8E); 296 | idt_set(40, (address)irq8, 0x08, 0x8E); 297 | idt_set(41, (address)irq9, 0x08, 0x8E); 298 | idt_set(42, (address)irq10, 0x08, 0x8E); 299 | idt_set(43, (address)irq11, 0x08, 0x8E); 300 | idt_set(44, (address)irq12, 0x08, 0x8E); 301 | idt_set(45, (address)irq13, 0x08, 0x8E); 302 | idt_set(46, (address)irq14, 0x08, 0x8E); 303 | idt_set(47, (address)irq15, 0x08, 0x8E); 304 | 305 | lidt((address)&idtPointer); 306 | } 307 | 308 | } 309 | -------------------------------------------------------------------------------- /kernel/src/cpu/interrupts.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | extern "C" { 6 | 7 | namespace cpu { 8 | namespace idt { 9 | typedef struct { 10 | word baseLow; 11 | word selector; 12 | byte reservedIst; 13 | byte flags; 14 | word baseMid; 15 | dword baseHigh; 16 | dword reserved; 17 | } __attribute__((packed)) idt_descriptor; 18 | 19 | /* 20 | * Interrupt Descriptor Pointer 21 | */ 22 | typedef struct { 23 | word limit; 24 | address base; 25 | } __attribute__((packed)) idt_ptr; 26 | 27 | void load_idt(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /kernel/src/cpu/tss.cpp: -------------------------------------------------------------------------------- 1 | #include "cpu/tss.h" 2 | #include "cpu/gdt.h" 3 | #include "memory/paging.h" 4 | #include "memory/pmm.h" 5 | #include "memory/operations.h" 6 | 7 | static cpu::tss::tss_t s_tss_descriptors[CONFIG_MAX_CPUS]; 8 | 9 | static void* isr_stack; 10 | static void* irq_stack; 11 | static void* sgi_stack; 12 | 13 | void cpu::tss::tss_init() { 14 | memory::operations::memset(s_tss_descriptors, 0, sizeof(cpu::tss::tss_t) * CONFIG_MAX_CPUS); 15 | } 16 | 17 | void cpu::tss::tss_install(int num_cpu, address stack) { 18 | isr_stack = (void *)((address)memory::pmm::request_page() + 0x1000); 19 | irq_stack = (void *)((address)memory::pmm::request_page() + 0x1000); 20 | sgi_stack = (void *)((address)memory::pmm::request_page() + 0x1000); 21 | 22 | memory::paging::map_memory((void *)((address)isr_stack - 0x1000), (void *)((address)isr_stack - 0x1000), false); 23 | memory::paging::map_memory((void *)((address)irq_stack - 0x1000), (void *)((address)irq_stack - 0x1000), false); 24 | memory::paging::map_memory((void *)((address)sgi_stack - 0x1000), (void *)((address)sgi_stack - 0x1000), false); 25 | 26 | address tss_base = (address)&s_tss_descriptors[num_cpu]; 27 | memory::operations::memset((void *)tss_base, 0, sizeof(cpu::tss::tss_t)); 28 | 29 | cpu::gdt::gdt_install_tss(tss_base, sizeof(cpu::tss::tss_t)); 30 | 31 | s_tss_descriptors[num_cpu].rsp[0] = stack; 32 | s_tss_descriptors[num_cpu].io_map = sizeof(cpu::tss::tss_t); 33 | s_tss_descriptors[num_cpu].ist[0] = (address)isr_stack; 34 | s_tss_descriptors[num_cpu].ist[1] = (address)irq_stack; 35 | s_tss_descriptors[num_cpu].ist[2] = (address)sgi_stack; 36 | 37 | cpu::tss::load_tss(0x28); 38 | } 39 | 40 | void cpu::tss::tss_setstack(int num_cpu, address stack) { 41 | s_tss_descriptors[num_cpu].rsp[0] = stack; 42 | } 43 | 44 | extern "C" cpu::tss::tss_t* tss_get(int num_cpu) { 45 | return &s_tss_descriptors[num_cpu]; 46 | } 47 | 48 | extern "C" void userspace_debug_catch() 49 | { 50 | return; 51 | } -------------------------------------------------------------------------------- /kernel/src/cpu/tss.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | #define CONFIG_MAX_CPUS 1 6 | 7 | namespace cpu { 8 | namespace tss { 9 | typedef struct tss { 10 | dword pad; 11 | address rsp[3]; 12 | qword pad_ex; 13 | address ist[7]; 14 | qword pad_ex_ex; 15 | word pad_ex_ex_ex; 16 | word io_map; 17 | } __attribute__((packed)) tss_t; 18 | 19 | void tss_init(); 20 | extern "C" void tss_install(int num_cpu, address cpu_stack); 21 | 22 | void tss_setstack(int num_cpu, address stack); 23 | 24 | extern "C" void load_tss(word); 25 | extern "C" tss_t* tss_get(int num_cpu); 26 | } 27 | } -------------------------------------------------------------------------------- /kernel/src/drivers/8259/pic.cpp: -------------------------------------------------------------------------------- 1 | #include "pic.h" 2 | #include "../io.h" 3 | 4 | void io::pic::pic_send_eoi(byte irq) 5 | { 6 | if(irq >= 8) 7 | io::outb(PIC2_COMMAND, PIC_EOI); 8 | 9 | io::outb(PIC1_COMMAND, PIC_EOI); 10 | } 11 | 12 | void io::pic::pic_remap(byte offset1, byte offset2) 13 | { 14 | byte a1, a2; 15 | 16 | a1 = io::inb(PIC1_DATA); // save masks 17 | a2 = io::inb(PIC2_DATA); 18 | 19 | io::outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); // starts the initialization sequence (in cascade mode) 20 | io::io_wait(); 21 | io::outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4); 22 | io::io_wait(); 23 | io::outb(PIC1_DATA, offset1); // ICW2: Master PIC vector offset 24 | io::io_wait(); 25 | io::outb(PIC2_DATA, offset2); // ICW2: Slave PIC vector offset 26 | io::io_wait(); 27 | io::outb(PIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100) 28 | io::io_wait(); 29 | io::outb(PIC2_DATA, 2); // ICW3: tell Slave PIC its cascade identity (0000 0010) 30 | io::io_wait(); 31 | 32 | io::outb(PIC1_DATA, ICW4_8086); 33 | io::io_wait(); 34 | io::outb(PIC2_DATA, ICW4_8086); 35 | io::io_wait(); 36 | 37 | io::outb(PIC1_DATA, a1); // restore saved masks. 38 | io::outb(PIC2_DATA, a2); 39 | } 40 | 41 | void io::pic::irq_mask(byte irq) { 42 | word port; 43 | byte value; 44 | 45 | if(irq < 8) { 46 | port = PIC1_DATA; 47 | } else { 48 | port = PIC2_DATA; 49 | irq -= 8; 50 | } 51 | value = io::inb(port) | (1 << irq); 52 | io::outb(port, value); 53 | } 54 | 55 | void io::pic::irq_unmask(byte irq) 56 | { 57 | word port; 58 | byte value; 59 | 60 | if (irq < 8) 61 | port = PIC1_DATA; 62 | else { 63 | port = PIC2_DATA; 64 | irq -= 8; 65 | } 66 | value = io::inb(port) & ~(1 << irq); 67 | io::outb(port, value); 68 | } 69 | 70 | extern "C" void configure_pic() { 71 | io::pic::pic_remap(0x20, 0x28); 72 | } -------------------------------------------------------------------------------- /kernel/src/drivers/8259/pic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.h" 3 | 4 | #define PIC1 0x20 5 | #define PIC2 0xA0 6 | #define PIC1_COMMAND PIC1 7 | #define PIC1_DATA (PIC1+1) 8 | #define PIC2_COMMAND PIC2 9 | #define PIC2_DATA (PIC2+1) 10 | #define PIC_EOI 0x20 11 | 12 | #define ICW1_ICW4 0x01 /* ICW4 (not) needed */ 13 | #define ICW1_SINGLE 0x02 /* Single (cascade) mode */ 14 | #define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */ 15 | #define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */ 16 | #define ICW1_INIT 0x10 /* Initialization - required! */ 17 | 18 | #define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */ 19 | #define ICW4_AUTO 0x02 /* Auto (normal) EOI */ 20 | #define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */ 21 | #define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */ 22 | 23 | namespace io { 24 | namespace pic { 25 | extern "C" void irq_mask(unsigned char irq); 26 | extern "C" void irq_unmask(unsigned char irq); 27 | extern "C" void pic_remap(byte offset1, byte offset2); 28 | extern "C" void pic_send_eoi(unsigned char irq); 29 | } 30 | } -------------------------------------------------------------------------------- /kernel/src/drivers/acpi/acpi.cpp: -------------------------------------------------------------------------------- 1 | #include "acpi.h" 2 | #include "../io.h" 3 | #include "../uart/serial.h" 4 | 5 | sys::acpi::rsdp2* sys::acpi::rsdp; 6 | 7 | sys::acpi::sdt_header* sys::acpi::get_table(char* signature) 8 | { 9 | io::serial::serial_byte('\n'); 10 | uint xsdt_entries = (rsdp->xsdt->length - sizeof(sys::acpi::sdt_header)) / 8; 11 | for (uint i = 0; i < xsdt_entries; i++) 12 | { 13 | struct sys::acpi::sdt_header* current_sdt_header = (sys::acpi::sdt_header *)*(address *)((uint64)rsdp->xsdt + sizeof(sys::acpi::sdt_header) + (i * 8)); 14 | for (int j = 0; j < 4; j++) { 15 | if (signature[j] != current_sdt_header->signature[j]) 16 | break; 17 | if (j == 3) 18 | return current_sdt_header; 19 | } 20 | } 21 | return nullptr; 22 | } -------------------------------------------------------------------------------- /kernel/src/drivers/acpi/acpi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.h" 3 | 4 | namespace sys { 5 | namespace acpi { 6 | struct sdt_header { 7 | uint08 signature[4]; 8 | uint32 length; 9 | uint08 revision; 10 | uint08 checksum; 11 | uint08 vendor_id[6]; 12 | uint08 vendor_table_id[8]; 13 | uint32 vendor_revision; 14 | uint32 creator_id; 15 | uint32 creator_revision; 16 | } __attribute__((packed)); 17 | 18 | struct rsdp2 { 19 | uint08 signature[8]; 20 | uint08 checksum; 21 | uint08 vendor_id[6]; 22 | uint08 revision; 23 | uint32 rsdt_address; 24 | uint32 length; 25 | sdt_header* xsdt; 26 | uint08 echecksum; 27 | uint08 pad[3]; 28 | } __attribute__((packed)); 29 | 30 | struct mcfg_header { 31 | sdt_header header; 32 | uint08 pad[8]; 33 | } __attribute__((packed)); 34 | 35 | extern rsdp2* rsdp; 36 | 37 | sys::acpi::sdt_header* get_table(char* signature); 38 | } 39 | } -------------------------------------------------------------------------------- /kernel/src/drivers/acpi/pci.cpp: -------------------------------------------------------------------------------- 1 | #include "pci.h" 2 | #include "../disk/ahci/ahci.h" 3 | #include "memory/paging.h" 4 | #include "../tty/tty.h" 5 | 6 | sys::acpi::mcfg_header* io::pci::mcfg; 7 | 8 | void enumerate_function(address device_address, uint function) 9 | { 10 | uint64 offset = function << 12; 11 | address function_address = device_address + offset; 12 | memory::paging::map_memory((void *)function_address, (void *)function_address, false); 13 | 14 | io::pci::device_header* device_header = (io::pci::device_header *)function_address; 15 | 16 | if (!device_header->device_id) 17 | return; 18 | if (device_header->device_id == 0xFFFF) 19 | return; 20 | 21 | switch (device_header->device_class) { 22 | case 0x01: // mass storage controller 23 | switch (device_header->device_subclass) { 24 | case 0x06: //Serial ATA 25 | switch (device_header->program_interface) { 26 | case 0x01: //AHCI 1.0 device 27 | io::disk::ahci::initialize(device_header); 28 | break; 29 | } 30 | } 31 | } 32 | } 33 | 34 | void enumerate_device(address bus_address, uint device) 35 | { 36 | uint64 offset = device << 15; 37 | address device_address = bus_address + offset; 38 | memory::paging::map_memory((void *)device_address, (void *)device_address, false); 39 | 40 | io::pci::device_header* device_header = (io::pci::device_header *)device_address; 41 | 42 | if (!device_header->device_id) 43 | return; 44 | if (device_header->device_id == 0xFFFF) 45 | return; 46 | 47 | for (int function = 0; function < 8; function++) 48 | enumerate_function(device_address, function); 49 | } 50 | 51 | void enumerate_bus(address base, uint bus) 52 | { 53 | uint64 offset = bus << 20; 54 | address bus_address = base + offset; 55 | memory::paging::map_memory((void *)bus_address, (void *)bus_address, false); 56 | 57 | io::pci::device_header* device_header = (io::pci::device_header *)bus_address; 58 | 59 | if (!device_header->device_id) 60 | return; 61 | if (device_header->device_id == 0xFFFF) 62 | return; 63 | 64 | for (int device = 0; device < 32; device++) 65 | enumerate_device(bus_address, device); 66 | } 67 | 68 | void io::pci::enumerate_pci() 69 | { 70 | int mcfg_entries = ((mcfg->header.length) - sizeof(sys::acpi::mcfg_header)) / sizeof(io::pci::device_configuration); 71 | for (int i = 0; i < mcfg_entries; i++) 72 | { 73 | io::pci::device_configuration* current_device = (io::pci::device_configuration *)((uint64)mcfg + sizeof(sys::acpi::mcfg_header) + (sizeof(io::pci::device_configuration) * i)); 74 | for (uint bus = current_device->start_bus; bus < current_device->end_bus; bus++) 75 | enumerate_bus(current_device->base, bus); 76 | } 77 | } -------------------------------------------------------------------------------- /kernel/src/drivers/acpi/pci.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | #include "acpi.h" 5 | 6 | namespace io { 7 | namespace pci { 8 | struct device_configuration { 9 | address base; 10 | uint16 pci_segment_group; 11 | uint08 start_bus; 12 | uint08 end_bus; 13 | uint08 pad[4]; 14 | } __attribute__((packed)); 15 | 16 | struct device_header { 17 | uint16 vendor_id; 18 | uint16 device_id; 19 | uint16 command; 20 | uint16 status; 21 | uint08 revision_id; 22 | uint08 program_interface; 23 | uint08 device_subclass; 24 | uint08 device_class; 25 | uint08 cache_line_size; 26 | uint08 latency_timer; 27 | uint08 header_type; 28 | uint08 bist; 29 | }; 30 | 31 | struct device_header_ex0 { 32 | device_header common; 33 | uint32 bar0; 34 | uint32 bar1; 35 | uint32 bar2; 36 | uint32 bar3; 37 | uint32 bar4; 38 | uint32 bar5; 39 | uint32 cardbus_cis_pointer; 40 | uint16 subsystem_vendor_id; 41 | uint16 subsystem_id; 42 | uint32 expansion_rom_base; 43 | uint08 capabillities_ptr; 44 | uint08 pad[7]; 45 | uint08 interrupt_line; 46 | uint08 interrupt_pin; 47 | uint08 minimum_grant; 48 | uint08 maximum_latency; 49 | }; 50 | 51 | extern sys::acpi::mcfg_header* mcfg; 52 | 53 | void enumerate_pci(); 54 | } 55 | } -------------------------------------------------------------------------------- /kernel/src/drivers/acpi/power.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by rizet on 11/27/20. 3 | // 4 | 5 | #include "power.h" 6 | #include "boot/boot.h" 7 | #include "drivers/tty/tty.h" 8 | 9 | // extern as C so can be called from ASM 10 | extern "C" 11 | { 12 | void cpu::power::shutdown() { 13 | io::tty::clear(); 14 | asm volatile ("cli; hlt"); 15 | } 16 | 17 | void cpu::power::restart_warm() { 18 | asm volatile ("jmp 0x0"); 19 | } 20 | 21 | void cpu::power::restart_cold() { 22 | asm volatile ("jmp 0x0"); 23 | } 24 | } -------------------------------------------------------------------------------- /kernel/src/drivers/acpi/power.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by rizet on 11/27/20. 3 | // 4 | #pragma once 5 | 6 | extern "C" 7 | { 8 | namespace cpu { 9 | namespace power { 10 | void shutdown(); 11 | void restart_cold(); 12 | void restart_warm(); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /kernel/src/drivers/audio/beeper/beeper.cpp: -------------------------------------------------------------------------------- 1 | #include "beeper.h" 2 | 3 | void sys::audio::pcspk::init() 4 | { 5 | io::outb(0x61, io::inb(0x61) | 0x1); 6 | } 7 | 8 | void sys::audio::pcspk::play_sound(uint32 frequency) { 9 | byte tmp; 10 | 11 | io::pit::set_c2_frequency(frequency); 12 | 13 | tmp = io::inb(0x61); 14 | if (tmp != (tmp | 3)) { 15 | io::outb(0x61, tmp | 3); 16 | } 17 | } 18 | 19 | void sys::audio::pcspk::stop_sound() { 20 | byte tmp = io::inb(0x61) & 0xFC; 21 | 22 | io::outb(0x61, tmp); 23 | } 24 | 25 | void sys::audio::pcspk::beep() { 26 | play_sound(1000); 27 | sys::chrono::sleep(10); 28 | stop_sound(); 29 | io::pit::set_c2_frequency(1); 30 | } 31 | 32 | void sys::audio::pcspk::beep(uint32 frequency, uint32 duration) { 33 | play_sound(frequency); 34 | sys::chrono::sleep(duration); 35 | stop_sound(); 36 | io::pit::set_c2_frequency(1); 37 | } -------------------------------------------------------------------------------- /kernel/src/drivers/audio/beeper/beeper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "drivers/io.h" 4 | #include "scheduling/timer.h" 5 | 6 | namespace sys { 7 | namespace audio { 8 | namespace pcspk { 9 | void init(); 10 | void play_sound(uint32 frequency); 11 | void stop_sound(); 12 | void beep(); 13 | void beep(uint32 frequency, uint32 duration); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /kernel/src/drivers/disk/ahci/ahci.cpp: -------------------------------------------------------------------------------- 1 | #include "ahci.h" 2 | #include "drivers/tty/tty.h" 3 | #include "memory/paging.h" 4 | #include "memory/operations.h" 5 | #include "memory/pmm.h" 6 | #include "memory/heap.h" 7 | 8 | io::pci::device_header* io::disk::ahci::ahci_controller; 9 | io::disk::ahci::hba_memory* io::disk::ahci::abar; 10 | io::disk::ahci::ahci_port* io::disk::ahci::ports[32]; 11 | uint08 io::disk::ahci::usable_ports; 12 | 13 | int $find_command_slot(io::disk::ahci::hba_port* port) 14 | { 15 | uint32 slots = (port->sata_active | port->command_issue); 16 | for (int i = 0; i < 32; i++) 17 | { 18 | if ((slots & 1) == 0) 19 | return i; 20 | slots >>= 1; 21 | } 22 | return -1; 23 | } 24 | 25 | void io::disk::ahci::initialize(pci::device_header* ahci_device_header) { 26 | ahci_controller = ahci_device_header; 27 | abar = ((io::disk::ahci::hba_memory *)((io::pci::device_header_ex0 *)ahci_device_header)->bar5); 28 | memory::paging::map_memory((void *)abar, (void *)abar, false); 29 | probe_ports(); 30 | 31 | for (int i = 0; i < usable_ports; i++) 32 | configure_port(i); 33 | } 34 | 35 | io::disk::ahci::port_type io::disk::ahci::get_port_type(hba_port* port) { 36 | uint32 sata_status = port->sata_status; 37 | uint08 interface_power_management = (sata_status >> 8) & 0x7; 38 | uint08 device_detection = sata_status & 0x7; 39 | 40 | if (device_detection != device_detection_code::present) 41 | return none; 42 | if (interface_power_management != ipm_code::active) 43 | return none; 44 | 45 | switch (port->signature) 46 | { 47 | case port_signature::sata_s: 48 | return port_type::sata; 49 | case port_signature::semb_s: 50 | return port_type::semb; 51 | case port_signature::sata_pi_s: 52 | return port_type::sata_pi; 53 | case port_signature::pm_s: 54 | return port_type::pm; 55 | default: 56 | return port_type::none; 57 | } 58 | } 59 | 60 | void io::disk::ahci::probe_ports() { 61 | uint32 implemented_ports = abar->ports_implemented; 62 | for (int i = 0; i < 32; i++) { 63 | if (implemented_ports & (1 << i)) { 64 | port_type current_port_type = get_port_type(&abar->ports[i]); 65 | 66 | if (current_port_type != none) 67 | { 68 | ports[usable_ports] = (ahci_port *)memory::heap::malloc(sizeof(ahci_port)); 69 | ports[usable_ports]->port = &abar->ports[i]; 70 | ports[usable_ports]->ahci_port_number = usable_ports; 71 | usable_ports++; 72 | } 73 | } 74 | } 75 | } 76 | 77 | void io::disk::ahci::configure_port(uint port_number) 78 | { 79 | ahci_port* port = ports[port_number]; 80 | 81 | command_stop(port_number); 82 | 83 | void* new_list_base = memory::pmm::request_page(); 84 | port->port->command_list_base = (uint32)(uint64)new_list_base; 85 | port->port->command_list_base_upper = (uint32)((uint64)new_list_base >> 32); 86 | memory::operations::memset(new_list_base, 0x00, 0x400); 87 | 88 | void* new_fis_base = memory::pmm::request_page(); 89 | port->port->fis_base = (uint32)(uint64)new_fis_base; 90 | port->port->fis_base_upper = (uint32)((uint64)new_fis_base >> 32); 91 | memory::operations::memset(new_fis_base, 0x00, 0x100); 92 | 93 | hba_command_header* command_header = (hba_command_header *)((port->port->command_list_base) | (uint32)((uint64)port->port->command_list_base_upper << 32)); 94 | 95 | for (int i = 0; i < 32; i++) { 96 | command_header[i].prdt_length = 8; 97 | void* command_table_address = memory::pmm::request_page(); 98 | uint64 address = (uint64)command_table_address + (i << 8); 99 | command_header[i].command_table_base = (uint32)address; 100 | command_header[i].command_table_base_upper |= (uint32)(address << 32); 101 | memory::operations::memset((void *)address, 0, 0x100); 102 | } 103 | 104 | command_start(port_number); 105 | } 106 | 107 | void io::disk::ahci::command_start(uint port_number) 108 | { 109 | ahci_port* port = ports[port_number]; 110 | 111 | while (port->port->command_status & command_status_field::pxcmd_cr); 112 | 113 | port->port->command_status |= command_status_field::pxcmd_fre; 114 | port->port->command_status |= command_status_field::pxcmd_st; 115 | } 116 | 117 | void io::disk::ahci::command_stop(uint port_number) 118 | { 119 | ahci_port* port = ports[port_number]; 120 | 121 | port->port->command_status &= ~command_status_field::pxcmd_fre; 122 | port->port->command_status &= ~command_status_field::pxcmd_st; 123 | 124 | while (true) { 125 | if (port->port->command_status & command_status_field::pxcmd_fr) continue; 126 | if (port->port->command_status & command_status_field::pxcmd_cr) continue; 127 | break; 128 | } 129 | } 130 | 131 | int io::disk::ahci::command_read(uint port_number, uint64 sector, uint16 sector_count, void* buffer) 132 | { 133 | ahci_port* port = ports[port_number]; 134 | 135 | int command_list_slot = $find_command_slot(port->port); 136 | 137 | if (command_list_slot < 0) 138 | return ahci_read_status::r_device_too_busy; 139 | 140 | uint32 sector_low = (uint32)sector; 141 | uint32 sector_high = (uint32)(sector >> 32); 142 | 143 | port->port->interrupt_status = (uint32)-1; 144 | 145 | hba_command_header* command_header = (hba_command_header *)port->port->command_list_base; 146 | command_header = (hba_command_header *)(((uint64)command_header) | (((uint64)port->port->command_list_base_upper) << 32)); 147 | command_header += command_list_slot; 148 | 149 | command_header->command_fis_length = sizeof(fis_register_h2d) / sizeof(uint32); 150 | command_header->write = false; 151 | command_header->prdt_length = 1; 152 | 153 | hba_command_table* command_table = (hba_command_table *)command_header->command_table_base; 154 | command_table = (hba_command_table *)(((uint64)command_table) | (((uint64)command_header->command_table_base_upper) << 32)); 155 | 156 | memory::operations::memset(command_table, 0, sizeof(hba_command_table) + (command_header->prdt_length - 1) * sizeof(hba_prdt_entry)); 157 | 158 | command_table->prdt_entries[0].data_base_address = (uint32)((address)buffer); 159 | command_table->prdt_entries[0].data_base_address_upper = (uint32)((address)buffer >> 32); 160 | command_table->prdt_entries[0].byte_count = (sector_count << 9) - 1; 161 | command_table->prdt_entries[0].interrupt_on_completion = 1; 162 | 163 | fis_register_h2d* command_fis = (fis_register_h2d *)&command_table->command_fis; 164 | command_fis->fis_type = fis_type::reg_h2d; 165 | command_fis->cc = 1; 166 | command_fis->command = sata_command::read_dma_ex; 167 | 168 | command_fis->lba0 = (uint08)sector_low; 169 | command_fis->lba1 = (uint08)sector_low >> 8; 170 | command_fis->lba2 = (uint08)sector_low >> 16; 171 | command_fis->lba3 = (uint08)sector_low >> 24; 172 | command_fis->lba4 = (uint08)sector_high; 173 | command_fis->lba5 = (uint08)sector_high >> 8; 174 | 175 | command_fis->device = 1 << 6; 176 | 177 | command_fis->count_low = sector_count & 0xFF; 178 | command_fis->count_high = (sector_count >> 8) & 0xFF; 179 | 180 | uint64 spinlock = 0; 181 | 182 | while ((port->port->task_file_data & (tf_data_bits::busy | tf_data_bits::drq)) && spinlock < 1000000) 183 | spinlock++; 184 | 185 | if (spinlock >= 1000000) 186 | return ahci_read_status::r_device_hung; 187 | 188 | port->port->command_issue |= 1 << command_list_slot; 189 | 190 | while (true) 191 | { 192 | if (!((port->port->command_issue >> command_list_slot) & 1)) 193 | break; 194 | 195 | if (port->port->interrupt_status & hba_pxis::tfes) 196 | return ahci_read_status::r_task_file_error; 197 | } 198 | 199 | return ahci_read_status::r_success; 200 | } 201 | 202 | int io::disk::ahci::command_write(uint port_number, uint64 sector, uint16 sector_count, void* data) 203 | { 204 | ahci_port* port = ports[port_number]; 205 | 206 | int command_list_slot = $find_command_slot(port->port); 207 | 208 | if (command_list_slot < 0) 209 | return ahci_write_status::w_device_too_busy; 210 | 211 | uint32 sector_low = (uint32)sector; 212 | uint32 sector_high = (uint32)(sector >> 32); 213 | 214 | port->port->interrupt_status = (uint32)-1; 215 | 216 | hba_command_header* command_header = (hba_command_header *)port->port->command_list_base; 217 | command_header = (hba_command_header *)(((uint64)command_header) | (((uint64)port->port->command_list_base_upper) << 32)); 218 | command_header += command_list_slot; 219 | 220 | command_header->command_fis_length = sizeof(fis_register_h2d) / sizeof(uint32); 221 | command_header->write = true; 222 | command_header->prdt_length = 1; 223 | 224 | hba_command_table* command_table = (hba_command_table *)command_header->command_table_base; 225 | command_table = (hba_command_table *)(((uint64)command_table) | (((uint64)command_header->command_table_base_upper) << 32)); 226 | 227 | memory::operations::memset(command_table, 0, sizeof(hba_command_table) + (command_header->prdt_length - 1) * sizeof(hba_prdt_entry)); 228 | 229 | command_table->prdt_entries[0].data_base_address = (uint32)((address)data); 230 | command_table->prdt_entries[0].data_base_address_upper = (uint32)((address)data >> 32); 231 | command_table->prdt_entries[0].byte_count = (sector_count << 9) - 1; 232 | command_table->prdt_entries[0].interrupt_on_completion = 1; 233 | 234 | fis_register_h2d* command_fis = (fis_register_h2d *)&command_table->command_fis; 235 | command_fis->fis_type = fis_type::reg_h2d; 236 | command_fis->cc = 1; 237 | command_fis->command = sata_command::write_dma_ex; 238 | 239 | command_fis->lba0 = (uint08)sector_low; 240 | command_fis->lba1 = (uint08)sector_low >> 8; 241 | command_fis->lba2 = (uint08)sector_low >> 16; 242 | command_fis->lba3 = (uint08)sector_low >> 24; 243 | command_fis->lba4 = (uint08)sector_high; 244 | command_fis->lba5 = (uint08)sector_high >> 8; 245 | 246 | command_fis->device = 1 << 6; 247 | 248 | command_fis->count_low = sector_count & 0xFF; 249 | command_fis->count_high = (sector_count >> 8) & 0xFF; 250 | 251 | uint64 spinlock = 0; 252 | 253 | while ((port->port->task_file_data & (tf_data_bits::busy | tf_data_bits::drq)) && spinlock < 1000000) 254 | spinlock++; 255 | 256 | if (spinlock >= 1000000) 257 | return ahci_write_status::w_device_hung; 258 | 259 | port->port->command_issue |= 1 << command_list_slot; 260 | 261 | while (true) 262 | { 263 | if (!((port->port->command_issue >> command_list_slot) & 1)) 264 | break; 265 | 266 | if (port->port->interrupt_status & hba_pxis::tfes) 267 | return ahci_write_status::w_task_file_error; 268 | } 269 | 270 | return ahci_write_status::w_success; 271 | } -------------------------------------------------------------------------------- /kernel/src/drivers/disk/ahci/ahci.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.h" 3 | #include "drivers/acpi/pci.h" 4 | 5 | namespace io { 6 | namespace disk { 7 | namespace ahci { 8 | enum port_type { 9 | none = 0, 10 | sata = 1, 11 | semb = 2, 12 | pm = 3, 13 | sata_pi = 4 14 | }; 15 | 16 | enum device_detection_code { 17 | present = 0x03 18 | }; 19 | 20 | enum ipm_code { 21 | active = 0x01 22 | }; 23 | 24 | enum port_signature { 25 | sata_pi_s = 0xEB140101, 26 | sata_s = 0x00000101, 27 | semb_s = 0xC33C0101, 28 | pm_s = 0x96690101 29 | }; 30 | 31 | enum command_status_field { 32 | pxcmd_st = 0x0001, 33 | pxcmd_fre = 0x0010, 34 | pxcmd_fr = 0x4000, 35 | pxcmd_cr = 0x8000 36 | }; 37 | 38 | enum fis_type { 39 | reg_h2d = 0x27, // Register FIS - host to device 40 | reg_d2h = 0x34, // Register FIS - device to host 41 | dma_act = 0x39, // DMA activate FIS - device to host 42 | dma_setup = 0x41, // DMA setup FIS - bidirectional 43 | data = 0x46, // Data FIS - bidirectional 44 | bist = 0x58, // BIST activate FIS - bidirectional 45 | pio_setup = 0x5F, // PIO setup FIS - device to host 46 | dev_bits = 0xA1, // Set device bits FIS - device to host 47 | }; 48 | 49 | enum sata_command { 50 | read_pio = 0x20, 51 | read_dma_ex = 0x25, 52 | write_pio = 0x30, 53 | write_dma_ex = 0x35, 54 | packet = 0xA1, 55 | flush = 0xE7, 56 | identify = 0xEC 57 | }; 58 | 59 | enum tf_data_bits { 60 | busy = 0x80, 61 | drq = 0x08 62 | }; 63 | 64 | enum hba_pxis { 65 | tfes = (1 << 30) 66 | }; 67 | 68 | enum ahci_read_status { 69 | r_success = 0, 70 | r_device_hung = 1, 71 | r_task_file_error = 2, 72 | r_device_too_busy = 3 73 | }; 74 | 75 | enum ahci_write_status { 76 | w_success = 0, 77 | w_device_hung = 1, 78 | w_task_file_error = 2, 79 | w_device_too_busy = 3 80 | }; 81 | 82 | struct hba_port { 83 | uint32 command_list_base; 84 | uint32 command_list_base_upper; 85 | uint32 fis_base; 86 | uint32 fis_base_upper; 87 | uint32 interrupt_status; 88 | uint32 interrupt_enable; 89 | uint32 command_status; 90 | uint08 pad[4]; 91 | uint32 task_file_data; 92 | uint32 signature; 93 | uint32 sata_status; 94 | uint32 sata_control; 95 | uint32 sata_error; 96 | uint32 sata_active; 97 | uint32 command_issue; 98 | uint32 sata_notification; 99 | uint32 fis_switch_control; 100 | uint08 pad_ex[44]; 101 | uint32 vendor[4]; 102 | }; 103 | 104 | struct hba_memory { 105 | uint32 host_capability; 106 | uint32 global_host_control; 107 | uint32 interrupt_status; 108 | uint32 ports_implemented; 109 | uint32 version; 110 | uint32 c3_control; 111 | uint32 c3_ports; 112 | uint32 enclosure_management_location; 113 | uint32 enclosure_management_control; 114 | uint32 host_capability_ex; 115 | uint32 bios_handoff_control_status; 116 | uint08 pad[116]; 117 | uint08 vendor[96]; 118 | hba_port ports[1]; 119 | }; 120 | 121 | struct hba_command_header { 122 | uint08 command_fis_length : 5; 123 | uint08 sata_pi : 1; 124 | uint08 write : 1; 125 | uint08 prefetchable : 1; 126 | uint08 reset : 1; 127 | uint08 bist : 1; 128 | uint08 clear_busy : 1; 129 | uint08 pad : 1; 130 | uint08 port_multiplier : 4; 131 | uint16 prdt_length : 16; 132 | uint32 prdb_count : 32; 133 | uint32 command_table_base : 32; 134 | uint32 command_table_base_upper : 32; 135 | uint08 pad_ex[16]; 136 | }; 137 | 138 | struct hba_prdt_entry { 139 | uint32 data_base_address; 140 | uint32 data_base_address_upper; 141 | uint32 pad; 142 | uint32 byte_count : 22; 143 | uint32 pad_ex : 9; 144 | uint08 interrupt_on_completion : 1; 145 | }; 146 | 147 | struct hba_command_table { 148 | uint08 command_fis[64]; 149 | uint08 sata_pi_command[16]; 150 | uint08 pad[48]; 151 | hba_prdt_entry prdt_entries[1]; 152 | }; 153 | 154 | struct ahci_port { 155 | hba_port* port; 156 | port_type type; 157 | uint08* dma_buffer; 158 | uint08 ahci_port_number; 159 | }; 160 | 161 | struct fis_register_h2d { 162 | uint08 fis_type; 163 | uint08 port_multiplier : 4; 164 | uint08 pad : 3; 165 | uint08 cc : 1; 166 | uint08 command; 167 | uint08 feature_low; 168 | uint08 lba0; 169 | uint08 lba1; 170 | uint08 lba2; 171 | uint08 device; 172 | uint08 lba3; 173 | uint08 lba4; 174 | uint08 lba5; 175 | uint08 feature_high; 176 | uint08 count_low; 177 | uint08 count_high; 178 | uint08 icc; 179 | uint08 control; 180 | uint08 pad_ex[4]; 181 | }; 182 | 183 | struct fis_register_d2h { 184 | uint08 fis_type; 185 | uint08 port_multiplier : 4; 186 | uint08 pad : 2; 187 | uint08 interrupt : 1; 188 | uint08 pad_ex : 1; 189 | uint08 status; 190 | uint08 error; 191 | uint08 lba0; 192 | uint08 lba1; 193 | uint08 lba2; 194 | uint08 device; 195 | uint08 lba3; 196 | uint08 lba4; 197 | uint08 lba5; 198 | uint08 pad_ex_ex; 199 | uint08 count_low; 200 | uint08 count_high; 201 | uint08 pad_ex_ex_ex[6]; 202 | }; 203 | 204 | struct fis_data { 205 | uint08 fis_type; 206 | uint08 port_multiplier : 4; 207 | uint08 pad : 4; 208 | uint08 pad_ex[2]; 209 | uint32 data[1]; 210 | }; 211 | 212 | struct fis_pio_setup { 213 | uint08 fis_type; 214 | uint08 port_multiplier : 4; 215 | uint08 pad : 1; 216 | uint08 transfer_direction : 1; 217 | uint08 interrupt : 1; 218 | uint08 pad_ex : 1; 219 | uint08 status; 220 | uint08 error; 221 | uint08 lba0; 222 | uint08 lba1; 223 | uint08 lba2; 224 | uint08 device; 225 | uint08 lba3; 226 | uint08 lba4; 227 | uint08 lba5; 228 | uint08 pad_ex_ex; 229 | uint08 count_low; 230 | uint08 count_high; 231 | uint08 pad_ex_ex_ex; 232 | uint08 e_status; 233 | uint16 transfer_count; 234 | uint08 rsv4[2]; 235 | }; 236 | 237 | struct fis_dma_setup { 238 | uint08 fis_type; 239 | uint08 port_multiplier : 4; 240 | uint08 pad : 1; 241 | uint08 transfer_direction : 1; 242 | uint08 interrupt : 1; 243 | uint08 auto_activate : 1; 244 | uint08 pad_ex[2]; 245 | uint64 dma_buffer_id; 246 | uint32 pad_ex_ex; 247 | uint32 dma_buffer_offset; 248 | uint32 transfer_count; 249 | uint32 pad_ex_ex_ex; 250 | }; 251 | 252 | void initialize(pci::device_header* ahci_device_header); 253 | void probe_ports(); 254 | void configure_port(uint port_number); 255 | void command_start(uint port_number); 256 | void command_stop(uint port_number); 257 | int command_read(uint port_number, uint64 sector, uint16 sector_count, void* buffer); 258 | int command_write(uint port_number, uint64 sector, uint16 sector_count, void* data); 259 | port_type get_port_type(hba_port* port); 260 | extern pci::device_header* ahci_controller; 261 | extern hba_memory* abar; 262 | extern ahci_port* ports[]; 263 | extern uint08 usable_ports; 264 | } 265 | } 266 | } -------------------------------------------------------------------------------- /kernel/src/drivers/gfx/gop/gop.cpp: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "memory/operations.h" 3 | #include "gop.h" 4 | 5 | stivale_framebuffer gfx::gop; 6 | uint32* gfx::buffer; 7 | 8 | gfx::shapes::positional_point gfx::shapes::pos(uint32 x, uint32 y) { 9 | 10 | gfx::shapes::positional_point posi; 11 | posi.x = x; 12 | posi.y = y; 13 | return posi; 14 | } 15 | 16 | gfx::shapes::dimensions gfx::shapes::dims(uint32 w, uint32 h) { 17 | 18 | gfx::shapes::dimensions dimens; 19 | dimens.w = w; 20 | dimens.h = h; 21 | return dimens; 22 | } 23 | 24 | void gfx::shapes::rect(gfx::shapes::positional_point posi, gfx::shapes::dimensions dimens, uint32 color) { 25 | 26 | gfx::shapes::positional_point rect_relative_center = gfx::shapes::rect_center(pos(0, 0), pos(dimens.w, dimens.h)); 27 | 28 | posi.x -= rect_relative_center.x; 29 | posi.y -= rect_relative_center.y; 30 | 31 | gfx::shapes::positional_point rect_absolute_center = pos(posi.x + rect_relative_center.x, posi.y + rect_relative_center.y); 32 | 33 | for (uint xx = (rect_absolute_center.x - (dimens.w / 2)); (xx <= (rect_absolute_center.x + (dimens.w / 2))) && (xx < gop.framebuffer_width); xx++) 34 | for (uint yy = (rect_absolute_center.y - (dimens.h / 2)); (yy <= rect_absolute_center.y + (dimens.h / 2)) && (yy < gop.framebuffer_height); yy++) 35 | gfx::screen::plot_pixel(gfx::shapes::pos(xx, yy), color); 36 | 37 | gfx::screen::buff(); 38 | } 39 | 40 | void gfx::screen::buff() 41 | { 42 | memory::operations::memcpy((void*)gop.framebuffer_addr, buffer, gop.framebuffer_width * gop.framebuffer_height * 4); 43 | } 44 | 45 | void gfx::screen::save_screen() 46 | { 47 | memory::operations::memcpy(buffer, (void *)gop.framebuffer_addr, gop.framebuffer_width * gop.framebuffer_height * 4); 48 | } 49 | 50 | void gfx::screen::restore_screen() 51 | { 52 | memory::operations::memcpy((void *)gop.framebuffer_addr, buffer, gop.framebuffer_width * gop.framebuffer_height * 4); 53 | } 54 | 55 | gfx::shapes::positional_point gfx::shapes::rect_center(gfx::shapes::positional_point posTL, gfx::shapes::positional_point posBR) 56 | { 57 | return gfx::shapes::pos((posTL.x + posBR.x) / 2, (posTL.y + posBR.y) / 2); 58 | } 59 | 60 | const uint64 kernel_font[] = 61 | { 62 | 0x0000000000000000, 63 | 0x0000000000000000, 64 | 0x000000FF00000000, 65 | 0x000000FF00FF0000, 66 | 0x1818181818181818, 67 | 0x6C6C6C6C6C6C6C6C, 68 | 0x181818F800000000, 69 | 0x6C6C6CEC0CFC0000, 70 | 0x1818181F00000000, 71 | 0x6C6C6C6F607F0000, 72 | 0x000000F818181818, 73 | 0x000000FC0CEC6C6C, 74 | 0x0000001F18181818, 75 | 0x0000007F606F6C6C, 76 | 0x187E7EFFFF7E7E18, // circle 0x00187EFFFF7E1800 77 | 0x0081818181818100, // square 78 | 0x0000000000000000, 79 | 0x0000000000000000, 80 | 0x0000000000000000, 81 | 0x0000000000000000, 82 | 0x0000000000000000, 83 | 0x0000000000000000, 84 | 0x0000000000000000, 85 | 0x0000000000000000, 86 | 0x0000000000000000, 87 | 0x0000000000000000, 88 | 0x0000000000000000, 89 | 0x0000000000000000, 90 | 0x0000000000000000, 91 | 0x0000000000000000, 92 | 0x0000000000000000, 93 | 0x0008000000000000,// 94 | 0x0000000000000000,// 95 | 0x00180018183C3C18,//! 96 | 0x0000000000121236,//" 97 | 0x006C6CFE6CFE6C6C,//# 98 | 0x00187ED07C16FC30,//$$ 99 | 0x0060660C18306606,//% 100 | 0x00DC66B61C36361C,//& 101 | 0x0000000000181818,//' 102 | 0x0030180C0C0C1830,//( 103 | 0x000C18303030180C,//) 104 | 0x0000187E3C7E1800,//* 105 | 0x000018187E181800,//+ 106 | 0x0C18180000000000,//, 107 | 0x000000007E000000,//- 108 | 0x0018180000000000,//. 109 | 0x0000060C18306000,/// 110 | 0x003C42464A52623C,//0 111 | 0x007E101010101C10,//1 112 | 0x007E04081020423C,//2 113 | 0x003C42403840423C,//3 114 | 0x0020207E22242830,//4 115 | 0x003C4240403E027E,//5 116 | 0x003C42423E020438,//6 117 | 0x000404081020407E,//7 118 | 0x003C42423C42423C,//8 119 | 0x001C20407C42423C,//9 120 | 0x0018180018180000,//: 121 | 0x0C18180018180000,//; 122 | 0x0030180C060C1830,//< 123 | 0x0000007E007E0000,//= 124 | 0x000C18306030180C,//> 125 | 0x001800181830663C,//? 126 | 0x003C06765676663C,//@ 127 | 0x0042427E42422418,//A 128 | 0x003E42423E42423E,//B 129 | 0x003C42020202423C,//C 130 | 0x001E22424242221E,//D 131 | 0x007E02023E02027E,//E 132 | 0x000202023E02027E,//F 133 | 0x003C42427202423C,//G 134 | 0x004242427E424242,//H 135 | 0x007C10101010107C,//I 136 | 0x001C22202020207E,//J 137 | 0x004222120E0A1222,//K 138 | 0x007E020202020202,//L 139 | 0x0082828292AAC682,//M 140 | 0x00424262524A4642,//N 141 | 0x003C42424242423C,//O 142 | 0x000202023E42423E,//P 143 | 0x005C22424242423C,//Q 144 | 0x004242423E42423E,//R 145 | 0x003C42403C02423C,//S 146 | 0x001010101010107C,//T 147 | 0x003C424242424242,//U 148 | 0x0018244242424242,//V 149 | 0x0044AAAA92828282,//W 150 | 0x0042422418244242,//X 151 | 0x0010101038444444,//Y 152 | 0x007E04081020407E,//Z 153 | 0x003E02020202023E,//[ 154 | 0x00006030180C0600, /* //\ */ 155 | 0x007C40404040407C, //] 156 | 0x000000000000663C,//^ 157 | 0xFF00000000000000,//_ 158 | 0x000000000030180C,//` 159 | 0x007C427C403C0000,//a 160 | 0x003E4242423E0202,//b 161 | 0x003C4202423C0000,//c 162 | 0x007C4242427C4040,//d 163 | 0x003C027E423C0000,//e 164 | 0x000404043E040438,//f 165 | 0x3C407C42427C0000,//g 166 | 0x00424242423E0202,//h 167 | 0x003C1010101C0018,//i 168 | 0x0E101010101C0018,//j 169 | 0x0042221E22420200,//k 170 | 0x003C101010101018,//l 171 | 0x00829292AA440000,//m 172 | 0x00424242423E0000,//n 173 | 0x003C4242423C0000,//o 174 | 0x02023E42423E0000,//p 175 | 0xC0407C42427C0000,//q 176 | 0x00020202463A0000,//r 177 | 0x003E403C027C0000,//s 178 | 0x00380404043E0404,//t 179 | 0x003C424242420000,//u 180 | 0x0018244242420000,//v 181 | 0x006C929292820000,//w 182 | 0x0042241824420000,//x 183 | 0x3C407C4242420000,//y 184 | 0x007E0418207E0000,//z 185 | 0x003018180E181830,//{ 186 | 0x0018181818181818,//| 187 | 0x000C18187018180C,//} 188 | 0x000000000062D68C,//~ 189 | 0xFFFFFFFFFFFFFFFF, 190 | 0x1E30181E3303331E,//€ 191 | 0x007E333333003300,// 192 | 0x001E033F331E0038,//‚ 193 | 0x00FC667C603CC37E,//ƒ 194 | 0x007E333E301E0033,//„ 195 | 0x007E333E301E0007,//… 196 | 0x007E333E301E0C0C,//† 197 | 0x3C603E03033E0000,//‡ 198 | 0x003C067E663CC37E,//ˆ 199 | 0x001E033F331E0033,//‰ 200 | 0x001E033F331E0007,//Š 201 | 0x001E0C0C0C0E0033,//‹ 202 | 0x003C1818181C633E,//Œ 203 | 0x001E0C0C0C0E0007,// 204 | 0x00333F33331E0C33,//Ž 205 | 0x00333F331E000C0C,// 206 | 0x003F061E063F0038,// 207 | 0x00FE33FE30FE0000,//‘ 208 | 0x007333337F33367C,//’ 209 | 0x001E33331E00331E,//“ 210 | 0x001E33331E003300,//” 211 | 0x001E33331E000700,//• 212 | 0x007E33333300331E,//– 213 | 0x007E333333000700,//— 214 | 0x1F303F3333003300,//˜ 215 | 0x001C3E63633E1C63,//™ 216 | 0x001E333333330033,//š 217 | 0x18187E03037E1818,//› 218 | 0x003F67060F26361C,//œ 219 | 0x000C3F0C3F1E3333,// 220 | 0x70337B332F1B1B0F,//ž 221 | 0x0E1B18187E18D870,//Ÿ 222 | 0x007E333E301E0038,// 223 | 0x001E0C0C0C0E001C,//¡ 224 | 0x001E33331E003800,//¢ 225 | 0x007E333333003800,//£ 226 | 0x003333331F001F00,//¤ 227 | 0x00333B3F3733003F,//¥ 228 | 0x00007E007C36363C,//¦ 229 | 0x00007E003C66663C,//§ 230 | 0x001E3303060C000C,//¨ 231 | 0x000003033F000000,//© 232 | 0x000030303F000000,//ª 233 | 0xF81973C67C1B3363,//« 234 | 0xC0F9F3E6CF1B3363,//¬ 235 | 0x183C3C1818001800,//­ 236 | 0x0000CC663366CC00,//® 237 | 0x00003366CC663300,//¯ 238 | 0x1144114411441144,//° 239 | 0x55AA55AA55AA55AA,//± 240 | 0xEEBBEEBBEEBBEEBB,//² 241 | 0x1818181818181818,//³ 242 | 0x1818181F18181818,//´ 243 | 0x1818181F181F1818,//µ 244 | 0x6C6C6C6F6C6C6C6C,//¶ 245 | 0x6C6C6C7F00000000,//· 246 | 0x1818181F181F0000,//¸ 247 | 0x6C6C6C6F606F6C6C,//¹ 248 | 0x6C6C6C6C6C6C6C6C,//º 249 | 0x6C6C6C6F607F0000,//» 250 | 0x0000007F606F6C6C,//¼ 251 | 0x0000007F6C6C6C6C,//½ 252 | 0x0000001F181F1818,//¾ 253 | 0x1818181F00000000,//¿ 254 | 0x000000F818181818,//À 255 | 0x000000FF18181818,//Á 256 | 0x181818FF00000000,// 257 | 0x181818F818181818,//à 258 | 0x000000FF00000000,//Ä 259 | 0x181818FF18181818,//Å 260 | 0x181818F818F81818,//Æ 261 | 0x6C6C6CEC6C6C6C6C,//Ç 262 | 0x000000FC0CEC6C6C,//È 263 | 0x6C6C6CEC0CFC0000,//É 264 | 0x000000FF00EF6C6C,//Ê 265 | 0x6C6C6CEF00FF0000,//Ë 266 | 0x6C6C6CEC0CEC6C6C,//Ì 267 | 0x000000FF00FF0000,//Í 268 | 0x6C6C6CEF00EF6C6C,//Î 269 | 0x000000FF00FF1818,//Ï 270 | 0x000000FF6C6C6C6C,//Ð 271 | 0x181818FF00FF0000,//Ñ 272 | 0x6C6C6CFF00000000,//Ò 273 | 0x000000FC6C6C6C6C,//Ó 274 | 0x000000F818F81818,//Ô 275 | 0x181818F818F80000,//Õ 276 | 0x6C6C6CFC00000000,//Ö 277 | 0x6C6C6CEF6C6C6C6C,//× 278 | 0x181818FF00FF1818,//Ø 279 | 0x0000001F18181818,//Ù 280 | 0x181818F800000000,//Ú 281 | 0xFFFFFFFFFFFFFFFF,//Û 282 | 0xFFFFFFFF00000000,//Ü 283 | 0x0F0F0F0F0F0F0F0F,//Ý 284 | 0xF0F0F0F0F0F0F0F0,//Þ 285 | 0x00000000FFFFFFFF,//ß 286 | 0x006E3B133B6E0000,//à 287 | 0x03031F331F331E00,//á 288 | 0x0003030303637F00,//â 289 | 0x0036363636367F00,//ã 290 | 0x007F660C180C667F,//ä 291 | 0x001E3333337E0000,//å 292 | 0x03063E6666666600,//æ 293 | 0x00181818183B6E00,//ç 294 | 0x3F0C1E33331E0C3F,//è 295 | 0x001C36637F63361C,//é 296 | 0x007736366363361C,//ê 297 | 0x001E33333E180C38,//ë 298 | 0x00007EDBDB7E0000,//ì 299 | 0x03067EDBDB7E3060,//í 300 | 0x003C06033F03063C,//î 301 | 0x003333333333331E,//ï 302 | 0x00003F003F003F00,//ð 303 | 0x003F000C0C3F0C0C,//ñ 304 | 0x003F00060C180C06,//ò 305 | 0x003F00180C060C18,//ó 306 | 0x1818181818D8D870,//ô 307 | 0x0E1B1B1818181818,//õ 308 | 0x000C0C003F000C0C,//ö 309 | 0x0000394E00394E00,//÷ 310 | 0x000000001C36361C,//ø 311 | 0x0000001818000000,//ù 312 | 0x0000001800000000,//ú 313 | 0x383C3637303030F0,//û 314 | 0x000000363636361E,//ü 315 | 0x0000003E061C301E,//ý 316 | 0x00003C3C3C3C0000,//þ 317 | 0xFFFFFFFFFFFFFFFF //ÿ 318 | }; 319 | 320 | qword gfx::fonts::get_character_font(char c) { return kernel_font[(int)c]; } -------------------------------------------------------------------------------- /kernel/src/drivers/gfx/gop/gop.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by rizet on 10/25/20. 3 | // 4 | #pragma once 5 | #include "types.h" 6 | #include "boot/boot.h" 7 | 8 | namespace gfx { 9 | 10 | extern uint32* buffer; 11 | extern stivale_framebuffer gop; 12 | 13 | namespace fonts { 14 | uint64 get_character_font(char c); 15 | } 16 | namespace shapes { 17 | typedef struct s_pos_point { 18 | uint32 x; 19 | uint32 y; 20 | } positional_point; 21 | 22 | typedef struct s_dimensions { 23 | uint32 w; 24 | uint32 h; 25 | } dimensions; 26 | positional_point pos(uint32 x, uint32 y); 27 | dimensions dims(uint32 w, uint32 h); 28 | void rect(positional_point posi, dimensions dimens, uint32 color); 29 | positional_point rect_center(positional_point posTL, positional_point posBR); 30 | } 31 | namespace screen { 32 | 33 | static inline void plot_pixel(gfx::shapes::positional_point posi, uint32 pixel) 34 | { 35 | ((dword *)gop.framebuffer_addr)[gop.framebuffer_width * posi.y + posi.x] = pixel; 36 | } 37 | 38 | static inline void plot_pixel_buffer(gfx::shapes::positional_point posi, uint32 pixel) 39 | { 40 | ((dword *)gop.framebuffer_addr)[gop.framebuffer_width * posi.y + posi.x] = pixel; 41 | } 42 | 43 | void save_screen(); 44 | void restore_screen(); 45 | void buff(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /kernel/src/drivers/io.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.h" 3 | 4 | namespace io { 5 | static inline void outb(word port, byte val) 6 | { 7 | asm volatile("outb %0, %1" 8 | : 9 | : "a"(val), "Nd"(port)); 10 | } 11 | 12 | static inline byte inb(word port) 13 | { 14 | byte ret; 15 | asm volatile("inb %1, %0" 16 | : "=a"(ret) 17 | : "Nd"(port)); 18 | return ret; 19 | } 20 | 21 | static inline void outw(word port, byte val) 22 | { 23 | asm volatile("outw %0, %1" 24 | : 25 | : "a"(val), "Nd"(port)); 26 | } 27 | 28 | static inline word inw(word port) 29 | { 30 | word ret; 31 | asm volatile("inw %1, %0" 32 | : "=a"(ret) 33 | : "Nd"(port)); 34 | return ret; 35 | } 36 | 37 | static inline void outl(word port, long val) 38 | { 39 | asm volatile("outl %0, %1" 40 | : 41 | : "a"(val), "Nd"(port)); 42 | } 43 | 44 | static inline qword inl(word port) 45 | { 46 | word ret; 47 | asm volatile("inl %1, %0" 48 | : "=a"(ret) 49 | : "Nd"(port)); 50 | return ret; 51 | } 52 | 53 | static inline void io_wait() 54 | { 55 | asm volatile ( "outb %%al, $0x80" : : "a"(0) ); 56 | } 57 | } -------------------------------------------------------------------------------- /kernel/src/drivers/kbd/kbd.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by rizet on 10/19/20. 3 | // 4 | 5 | #include "kbd.h" 6 | #include "../8259/pic.h" 7 | #include "../io.h" 8 | 9 | void (*keyboard_event_subscriber[256])(struct io::keyboard::keyboard_packet kbpacket); 10 | int keyboard_subscribers = 0; 11 | 12 | void io::keyboard::keyboard_event_publisher(struct keyboard_packet kbpacket) 13 | { 14 | for (int i = 0; i < keyboard_subscribers; i++) 15 | { 16 | keyboard_event_subscriber[i](kbpacket); 17 | } 18 | } 19 | 20 | void io::keyboard::keyboard_event_subscribe(void (*subscriber_function)(struct keyboard_packet kbpacket)) 21 | { 22 | keyboard_event_subscriber[keyboard_subscribers] = subscriber_function; 23 | keyboard_subscribers++; 24 | } 25 | 26 | void io::keyboard::keyboard_event_unsubscribe(void (*subscriber_function)(struct keyboard_packet kbpacket)) 27 | { 28 | int function_index = 0; 29 | 30 | for (int i = 0; i < keyboard_subscribers; i++) 31 | { 32 | if (keyboard_event_subscriber[i] == subscriber_function) 33 | { 34 | keyboard_event_subscriber[i] = nullptr; 35 | keyboard_subscribers--; 36 | function_index = i; 37 | break; 38 | } 39 | } 40 | 41 | for (int i = function_index; i < 64; i++) 42 | { 43 | keyboard_event_subscriber[i] = keyboard_event_subscriber[i + 1]; 44 | } 45 | } 46 | 47 | extern "C" void kbd_irq_handler() 48 | { 49 | word scan_code = io::inb(0x60); 50 | if (scan_code == 0xE0) 51 | { 52 | scan_code <<= 8; 53 | scan_code |= io::inb(0x60); 54 | } 55 | 56 | struct io::keyboard::keyboard_packet kbpacket; 57 | 58 | if ((scan_code >> 8) == 0xE0) 59 | { 60 | scan_code &= 0x00FF; 61 | scan_code -= 0x10; 62 | if (scan_code < 0x80) 63 | { 64 | kbpacket.release_or_press = 1; 65 | } 66 | else 67 | { 68 | kbpacket.release_or_press = 0; 69 | scan_code -= 0x80; 70 | } 71 | scan_code += 0x60; 72 | kbpacket.key_code = (scan_code & 0x00FF); 73 | } 74 | else 75 | { 76 | if (scan_code < 0x80) 77 | { 78 | kbpacket.release_or_press = 1; 79 | kbpacket.key_code = scan_code; 80 | } 81 | else 82 | { 83 | kbpacket.release_or_press = 0; 84 | kbpacket.key_code = scan_code - 0x80; 85 | } 86 | } 87 | 88 | if (kbpacket.key_code == 0x1D || kbpacket.key_code == 0x8D) 89 | io::keyboard::ctrl_down = kbpacket.release_or_press; 90 | 91 | if (kbpacket.key_code == 0x38 || kbpacket.key_code == 0xA8) 92 | io::keyboard::alt_down = kbpacket.release_or_press; 93 | 94 | if (kbpacket.key_code == 0x2A || kbpacket.key_code == 0x36) 95 | io::keyboard::shifted = kbpacket.release_or_press; 96 | 97 | if (kbpacket.key_code == 0x3A && kbpacket.release_or_press) 98 | io::keyboard::caps_lock =! io::keyboard::caps_lock; 99 | 100 | if (kbpacket.key_code == 0x45 && kbpacket.release_or_press) 101 | io::keyboard::num_lock =! io::keyboard::num_lock; 102 | 103 | if (kbpacket.key_code == 0x46 && kbpacket.release_or_press) 104 | io::keyboard::scroll_lock =! io::keyboard::scroll_lock; 105 | 106 | kbpacket.alt_down = io::keyboard::alt_down; 107 | kbpacket.ctrl_down = io::keyboard::ctrl_down; 108 | kbpacket.fn_down = io::keyboard::fn_down; 109 | kbpacket.shifted = io::keyboard::shifted; 110 | kbpacket.caps_lock = io::keyboard::caps_lock; 111 | kbpacket.num_lock = io::keyboard::num_lock; 112 | kbpacket.scroll_lock = io::keyboard::scroll_lock; 113 | 114 | io::keyboard::keyboard_event_publisher(kbpacket); 115 | } 116 | 117 | bool io::keyboard::shifted; 118 | bool io::keyboard::ctrl_down; 119 | bool io::keyboard::alt_down; 120 | bool io::keyboard::fn_down; 121 | bool io::keyboard::caps_lock; 122 | bool io::keyboard::scroll_lock; 123 | bool io::keyboard::num_lock; 124 | 125 | void io::keyboard::init() 126 | { 127 | io::keyboard::num_lock = false; 128 | io::keyboard::caps_lock = false; 129 | io::keyboard::scroll_lock = false; 130 | io::keyboard::alt_down = false; 131 | io::keyboard::ctrl_down = false; 132 | io::keyboard::fn_down = false; 133 | io::pic::irq_unmask(1); 134 | } 135 | -------------------------------------------------------------------------------- /kernel/src/drivers/kbd/kbd.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by rizet on 10/19/20. 3 | // 4 | #pragma once 5 | #include "types.h" 6 | 7 | 8 | namespace io { 9 | namespace keyboard { 10 | void init(); 11 | void keyboard_event_publisher(struct keyboard_packet kbpacket); 12 | void keyboard_event_subscribe(void (*subscriber_function)(struct keyboard_packet kbpacket)); 13 | void keyboard_event_unsubscribe(void (*subscriber_function)(struct keyboard_packet kbpacket)); 14 | struct keyboard_packet { 15 | unsigned char key_code : 8; 16 | bool release_or_press : 1; // release = 0, press = 1 17 | bool shifted : 1; 18 | bool ctrl_down : 1; 19 | bool alt_down : 1; 20 | bool fn_down : 1; 21 | bool caps_lock : 1; 22 | bool scroll_lock : 1; 23 | bool num_lock : 1; 24 | } __attribute__((packed)); 25 | extern bool shifted; 26 | extern bool ctrl_down; 27 | extern bool alt_down; 28 | extern bool fn_down; 29 | extern bool caps_lock; 30 | extern bool scroll_lock; 31 | extern bool num_lock; 32 | 33 | enum key_code { 34 | null, 35 | escape, 36 | one, 37 | two, 38 | three, 39 | four, 40 | five, 41 | six, 42 | seven, 43 | eight, 44 | nine, 45 | zero, 46 | dash, 47 | equal, 48 | backspace, 49 | tab, 50 | q, 51 | w, 52 | e, 53 | r, 54 | t, 55 | y, 56 | u, 57 | i, 58 | o, 59 | p, 60 | open_bracket, 61 | close_bracket, 62 | enter, 63 | left_ctrl, 64 | a, 65 | s, 66 | d, 67 | f, 68 | g, 69 | h, 70 | j, 71 | k, 72 | l, 73 | semicolon, 74 | apostrophe, 75 | backtick, 76 | left_shift, 77 | backslash, 78 | z, 79 | x, 80 | c, 81 | v, 82 | b, 83 | n, 84 | m, 85 | comma, 86 | period, 87 | slash, 88 | right_shift, 89 | keypad_star, 90 | left_alt, 91 | space, 92 | caps, 93 | f1, 94 | f2, 95 | f3, 96 | f4, 97 | f5, 98 | f6, 99 | f7, 100 | f8, 101 | f9, 102 | f10, 103 | number_lock, 104 | scrl_lock, 105 | keypad_seven, 106 | keypad_eight, 107 | keypad_nine, 108 | keypad_dash, 109 | keypad_four, 110 | keypad_five, 111 | keypad_six, 112 | keypad_plus, 113 | keypad_one, 114 | keypad_two, 115 | keypad_three, 116 | keypad_zero, 117 | keypad_period 118 | }; 119 | } 120 | } -------------------------------------------------------------------------------- /kernel/src/drivers/tty/printf.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "util/kutil.h" 6 | #include "memory/operations.h" 7 | #include "memory/heap.h" 8 | #include "tty.h" 9 | 10 | 11 | char* __int_str(intmax_t i, char b[], int base, bool plusSignIfNeeded, bool spaceSignIfNeeded, 12 | int paddingNo, bool justify, bool zeroPad) { 13 | 14 | char digit[32] = {0}; 15 | memory::operations::memset(digit, 0, 32); 16 | util::strcpy(digit, "0123456789"); 17 | 18 | if (base == 16) { 19 | util::strcat(digit, "ABCDEF"); 20 | } else if (base == 17) { 21 | util::strcat(digit, "abcdef"); 22 | base = 16; 23 | } 24 | 25 | char* p = b; 26 | if (i < 0) { 27 | *p++ = '-'; 28 | i *= -1; 29 | } else if (plusSignIfNeeded) { 30 | *p++ = '+'; 31 | } else if (!plusSignIfNeeded && spaceSignIfNeeded) { 32 | *p++ = ' '; 33 | } 34 | 35 | intmax_t shifter = i; 36 | do { 37 | ++p; 38 | shifter = shifter / base; 39 | } while (shifter); 40 | 41 | *p = '\0'; 42 | do { 43 | *--p = digit[i % base]; 44 | i = i / base; 45 | } while (i); 46 | 47 | int padding = paddingNo - (int)util::strlen(b); 48 | if (padding < 0) padding = 0; 49 | 50 | if (justify) { 51 | while (padding--) { 52 | if (zeroPad) { 53 | b[util::strlen(b)] = '0'; 54 | } else { 55 | b[util::strlen(b)] = ' '; 56 | } 57 | } 58 | 59 | } else { 60 | char a[256] = {0}; 61 | while (padding--) { 62 | if (zeroPad) { 63 | a[util::strlen(a)] = '0'; 64 | } else { 65 | a[util::strlen(a)] = ' '; 66 | } 67 | } 68 | util::strcat(a, b); 69 | util::strcpy(b, a); 70 | } 71 | 72 | return b; 73 | } 74 | 75 | void displayCharacter(char c, int* a) { 76 | io::tty::put_char(c, 15); 77 | *a += 1; 78 | } 79 | 80 | void displayString(char* c, int* a) { 81 | for (int i = 0; c[i]; ++i) { 82 | displayCharacter(c[i], a); 83 | } 84 | } 85 | 86 | int vprintf (const char* format, va_list list) 87 | { 88 | int chars = 0; 89 | char intStrBuffer[256] = {0}; 90 | 91 | for (int i = 0; format[i]; ++i) { 92 | 93 | char specifier = '\0'; 94 | char length = '\0'; 95 | 96 | int lengthSpec = 0; 97 | int precSpec = 0; 98 | bool leftJustify = false; 99 | bool zeroPad = false; 100 | bool spaceNoSign = false; 101 | bool altForm = false; 102 | bool plusSign = false; 103 | bool emode = false; 104 | int expo = 0; 105 | 106 | if (format[i] == '%') { 107 | ++i; 108 | 109 | bool extBreak = false; 110 | while (1) { 111 | 112 | switch (format[i]) { 113 | case '-': 114 | leftJustify = true; 115 | ++i; 116 | break; 117 | 118 | case '+': 119 | plusSign = true; 120 | ++i; 121 | break; 122 | 123 | case '#': 124 | altForm = true; 125 | ++i; 126 | break; 127 | 128 | case ' ': 129 | spaceNoSign = true; 130 | ++i; 131 | break; 132 | 133 | case '0': 134 | zeroPad = true; 135 | ++i; 136 | break; 137 | 138 | default: 139 | extBreak = true; 140 | break; 141 | } 142 | 143 | if (extBreak) break; 144 | } 145 | 146 | while (util::isdigit(format[i])) { 147 | lengthSpec *= 10; 148 | lengthSpec += format[i] - 48; 149 | ++i; 150 | } 151 | 152 | if (format[i] == '*') { 153 | lengthSpec = va_arg(list, int); 154 | ++i; 155 | } 156 | 157 | if (format[i] == '.') { 158 | ++i; 159 | while (util::isdigit(format[i])) { 160 | precSpec *= 10; 161 | precSpec += format[i] - 48; 162 | ++i; 163 | } 164 | 165 | if (format[i] == '*') { 166 | precSpec = va_arg(list, int); 167 | ++i; 168 | } 169 | } else { 170 | precSpec = 6; 171 | } 172 | 173 | if (format[i] == 'h' || format[i] == 'l' || format[i] == 'j' || 174 | format[i] == 'z' || format[i] == 't' || format[i] == 'L') { 175 | length = format[i]; 176 | ++i; 177 | if (format[i] == 'h') { 178 | length = 'H'; 179 | } else if (format[i] == 'l') { 180 | length = 'q'; 181 | ++i; 182 | } 183 | } 184 | specifier = format[i]; 185 | 186 | memory::operations::memset(intStrBuffer, 0, 256); 187 | 188 | int base = 10; 189 | if (specifier == 'o') { 190 | base = 8; 191 | specifier = 'u'; 192 | if (altForm) { 193 | displayString((char *)"0", &chars); 194 | } 195 | } 196 | if (specifier == 'p') { 197 | base = 16; 198 | length = 'z'; 199 | specifier = 'u'; 200 | } 201 | switch (specifier) { 202 | case 'X': 203 | base = 16; 204 | case 'x': 205 | base = base == 10 ? 17 : base; 206 | if (altForm) { 207 | displayString((char *)"0x", &chars); 208 | } 209 | 210 | case 'u': 211 | { 212 | switch (length) { 213 | case 0: 214 | { 215 | unsigned int integer = va_arg(list, unsigned int); 216 | __int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad); 217 | displayString(intStrBuffer, &chars); 218 | break; 219 | } 220 | case 'H': 221 | { 222 | unsigned char integer = (unsigned char) va_arg(list, unsigned int); 223 | __int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad); 224 | displayString(intStrBuffer, &chars); 225 | break; 226 | } 227 | case 'h': 228 | { 229 | unsigned short int integer = va_arg(list, unsigned int); 230 | __int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad); 231 | displayString(intStrBuffer, &chars); 232 | break; 233 | } 234 | case 'l': 235 | { 236 | unsigned long integer = va_arg(list, unsigned long); 237 | __int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad); 238 | displayString(intStrBuffer, &chars); 239 | break; 240 | } 241 | case 'q': 242 | { 243 | unsigned long long integer = va_arg(list, unsigned long long); 244 | __int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad); 245 | displayString(intStrBuffer, &chars); 246 | break; 247 | } 248 | case 'j': 249 | { 250 | uintmax_t integer = va_arg(list, uintmax_t); 251 | __int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad); 252 | displayString(intStrBuffer, &chars); 253 | break; 254 | } 255 | case 'z': 256 | { 257 | size_t integer = va_arg(list, size_t); 258 | __int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad); 259 | displayString(intStrBuffer, &chars); 260 | break; 261 | } 262 | case 't': 263 | { 264 | ptrdiff_t integer = va_arg(list, ptrdiff_t); 265 | __int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad); 266 | displayString(intStrBuffer, &chars); 267 | break; 268 | } 269 | default: 270 | break; 271 | } 272 | break; 273 | } 274 | 275 | case 'd': 276 | case 'i': 277 | { 278 | switch (length) { 279 | case 0: 280 | { 281 | int integer = va_arg(list, int); 282 | __int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad); 283 | displayString(intStrBuffer, &chars); 284 | break; 285 | } 286 | case 'H': 287 | { 288 | signed char integer = (signed char) va_arg(list, int); 289 | __int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad); 290 | displayString(intStrBuffer, &chars); 291 | break; 292 | } 293 | case 'h': 294 | { 295 | short int integer = va_arg(list, int); 296 | __int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad); 297 | displayString(intStrBuffer, &chars); 298 | break; 299 | } 300 | case 'l': 301 | { 302 | long integer = va_arg(list, long); 303 | __int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad); 304 | displayString(intStrBuffer, &chars); 305 | break; 306 | } 307 | case 'q': 308 | { 309 | long long integer = va_arg(list, long long); 310 | __int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad); 311 | displayString(intStrBuffer, &chars); 312 | break; 313 | } 314 | case 'j': 315 | { 316 | intmax_t integer = va_arg(list, intmax_t); 317 | __int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad); 318 | displayString(intStrBuffer, &chars); 319 | break; 320 | } 321 | case 'z': 322 | { 323 | size_t integer = va_arg(list, size_t); 324 | __int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad); 325 | displayString(intStrBuffer, &chars); 326 | break; 327 | } 328 | case 't': 329 | { 330 | ptrdiff_t integer = va_arg(list, ptrdiff_t); 331 | __int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad); 332 | displayString(intStrBuffer, &chars); 333 | break; 334 | } 335 | default: 336 | break; 337 | } 338 | break; 339 | } 340 | 341 | case 'c': 342 | { 343 | if (length == 'l') { 344 | displayCharacter(va_arg(list, int64_t), &chars); 345 | } else { 346 | displayCharacter(va_arg(list, int), &chars); 347 | } 348 | 349 | break; 350 | } 351 | 352 | case 's': 353 | { 354 | displayString(va_arg(list, char*), &chars); 355 | break; 356 | } 357 | 358 | case 'n': 359 | { 360 | switch (length) { 361 | case 'H': 362 | *(va_arg(list, signed char*)) = chars; 363 | break; 364 | case 'h': 365 | *(va_arg(list, short int*)) = chars; 366 | break; 367 | 368 | case 0: { 369 | int* a = va_arg(list, int*); 370 | *a = chars; 371 | break; 372 | } 373 | 374 | case 'l': 375 | *(va_arg(list, long*)) = chars; 376 | break; 377 | case 'q': 378 | *(va_arg(list, long long*)) = chars; 379 | break; 380 | case 'j': 381 | *(va_arg(list, intmax_t*)) = chars; 382 | break; 383 | case 'z': 384 | *(va_arg(list, size_t*)) = chars; 385 | break; 386 | case 't': 387 | *(va_arg(list, ptrdiff_t*)) = chars; 388 | break; 389 | default: 390 | break; 391 | } 392 | break; 393 | } 394 | 395 | case 'e': 396 | case 'E': 397 | emode = true; 398 | 399 | case 'f': 400 | case 'F': 401 | case 'g': 402 | case 'G': 403 | { 404 | double floating = va_arg(list, double); 405 | 406 | while (emode && floating >= 10) { 407 | floating /= 10; 408 | ++expo; 409 | } 410 | 411 | int form = lengthSpec - precSpec - expo - (precSpec || altForm ? 1 : 0); 412 | if (emode) { 413 | form -= 4; // 'e+00' 414 | } 415 | if (form < 0) { 416 | form = 0; 417 | } 418 | 419 | __int_str(floating, intStrBuffer, base, plusSign, spaceNoSign, form, \ 420 | leftJustify, zeroPad); 421 | 422 | displayString(intStrBuffer, &chars); 423 | 424 | floating -= (int) floating; 425 | 426 | for (int i = 0; i < precSpec; ++i) { 427 | floating *= 10; 428 | } 429 | intmax_t decPlaces = (intmax_t) (floating + 0.5); 430 | 431 | if (precSpec) { 432 | displayCharacter('.', &chars); 433 | __int_str(decPlaces, intStrBuffer, 10, false, false, 0, false, false); 434 | intStrBuffer[precSpec] = 0; 435 | displayString(intStrBuffer, &chars); 436 | } else if (altForm) { 437 | displayCharacter('.', &chars); 438 | } 439 | 440 | break; 441 | } 442 | 443 | 444 | case 'a': 445 | case 'A': 446 | //ACK! Hexadecimal floating points... 447 | break; 448 | 449 | default: 450 | break; 451 | } 452 | 453 | if (specifier == 'e') { 454 | displayString((char *)"e+", &chars); 455 | } else if (specifier == 'E') { 456 | displayString((char *)"E+", &chars); 457 | } 458 | 459 | if (specifier == 'e' || specifier == 'E') { 460 | __int_str(expo, intStrBuffer, 10, false, false, 2, false, true); 461 | displayString(intStrBuffer, &chars); 462 | } 463 | 464 | } else { 465 | displayCharacter(format[i], &chars); 466 | } 467 | } 468 | 469 | return chars; 470 | } 471 | 472 | __attribute__ ((format (printf, 1, 2))) int printf (const char* format, ...) 473 | { 474 | va_list list; 475 | va_start (list, format); 476 | int i = vprintf (format, list); 477 | va_end (list); 478 | return i; 479 | 480 | } -------------------------------------------------------------------------------- /kernel/src/drivers/tty/tty.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "types.h" 4 | #include "tty.h" 5 | #include "memory/pmm.h" 6 | #include "memory/operations.h" 7 | #include "drivers/io.h" 8 | #include "drivers/uart/serial.h" 9 | #include "util/kutil.h" 10 | 11 | // This terminal emulates a dynamically-sized text mode 12 | 13 | 14 | uint io::tty::vga_width; 15 | uint io::tty::vga_height; 16 | uint io::tty::row; 17 | uint io::tty::column; 18 | word* io::tty::text_buffer; 19 | 20 | #define check_vga_color(farbe) \ 21 | if (util::strcomp(#farbe, colorCode)) \ 22 | color = VGA_COLOR_##farbe; 23 | 24 | void io::tty::initialize() 25 | { 26 | row = 0; 27 | column = 0; 28 | 29 | gfx::shapes::dimensions size = get_optimal_size(gfx::shapes::dims(gfx::gop.framebuffer_width, gfx::gop.framebuffer_height)); 30 | 31 | vga_width = size.w; 32 | vga_height = size.h; 33 | 34 | text_buffer = (word *)memory::pmm::request_page(); 35 | 36 | memory::operations::memset((void *)text_buffer, 0, size.h * size.w * 2); 37 | memory::operations::memset((void *)gfx::buffer, 0, gfx::gop.framebuffer_width * gfx::gop.framebuffer_height * (gfx::gop.framebuffer_bpp / 8)); 38 | memory::operations::memset((void *)gfx::gop.framebuffer_addr, 0, gfx::gop.framebuffer_width * gfx::gop.framebuffer_height * (gfx::gop.framebuffer_bpp / 8)); 39 | 40 | io::serial::serial_msg("text buffer at "); 41 | io::serial::serial_msg(util::itoa((address)text_buffer, 16)); 42 | } 43 | 44 | void io::tty::clear() 45 | { 46 | for (unsigned int y = 0; y < vga_height; y++) 47 | for (unsigned int x = 0; x < vga_width; x++) 48 | put_entry_at(' ', 0x0, x, y); 49 | 50 | set_cursor(0, 0); 51 | } 52 | 53 | void io::tty::put_entry_at(char c, byte vcolor, size_t xpos, size_t ypos) 54 | { 55 | if (xpos > vga_width) 56 | return; 57 | 58 | if (ypos > vga_height) 59 | return; 60 | 61 | text_buffer[(ypos * vga_width + xpos)] = vga_entry(c, vcolor); 62 | 63 | render_entry_at(xpos, ypos); 64 | } 65 | 66 | dword io::tty::convert_vga_to_pix(byte vcolor) 67 | { 68 | dword color = 0; 69 | switch (vcolor) 70 | { 71 | case VGA_COLOR_BLACK: 72 | color = 0x000000; 73 | break; 74 | 75 | case VGA_COLOR_WHITE: 76 | color = 0xFFFFFF; 77 | break; 78 | 79 | case VGA_COLOR_RED: 80 | color = 0xFF0000; 81 | break; 82 | 83 | case VGA_COLOR_BLUE: 84 | color = 0x2222FF; 85 | break; 86 | 87 | case VGA_COLOR_GREEN: 88 | color = 0x22FF22; 89 | break; 90 | 91 | case VGA_COLOR_CYAN: 92 | color = 0x11FFFF; 93 | break; 94 | 95 | case VGA_COLOR_MAGENTA: 96 | color = 0xFF01AA; 97 | break; 98 | 99 | case VGA_COLOR_BROWN: 100 | color = 0xFFEBCD; 101 | break; 102 | 103 | case VGA_COLOR_LIGHT_GREY: 104 | color = 0xDDDDDD; 105 | break; 106 | 107 | case VGA_COLOR_DARK_GREY: 108 | color = 0x555555; 109 | break; 110 | 111 | case VGA_COLOR_LIGHT_BLUE: 112 | color = 0x01AAFF; 113 | break; 114 | 115 | case VGA_COLOR_LIGHT_GREEN: 116 | color = 0x01FF01; 117 | break; 118 | 119 | case VGA_COLOR_LIGHT_CYAN: 120 | color = 0x01DDFF; 121 | break; 122 | 123 | case VGA_COLOR_LIGHT_RED: 124 | color = 0xFF2222; 125 | break; 126 | 127 | case VGA_COLOR_LIGHT_MAGENTA: 128 | color = 0xFF0077; 129 | break; 130 | 131 | case VGA_COLOR_LIGHT_BROWN: 132 | color = 0x8B4513; 133 | break; 134 | } 135 | 136 | return color; 137 | } 138 | 139 | void io::tty::render_entry_at(uint16 xpos, uint16 ypos) 140 | { 141 | dword fg_color; 142 | dword bg_color; 143 | 144 | word entry = text_buffer[(ypos * vga_width + xpos)]; 145 | 146 | byte vga_color_fg = (entry & 0x0f00) >> 8; 147 | byte vga_color_bg = (entry >> 12); 148 | 149 | char c = entry ^ 0b1111111100000000; 150 | 151 | fg_color = convert_vga_to_pix(vga_color_fg); 152 | bg_color = convert_vga_to_pix(vga_color_bg); 153 | 154 | qword font_selector = gfx::fonts::get_character_font(c); 155 | 156 | byte bits[64]; 157 | 158 | for (uint08 i = 1; i <= 64; i++) { 159 | bits[i - 1] = util::get_bit(font_selector, i); 160 | } 161 | 162 | for (uint y = 0, yy = (ypos * 9); y < 8; y++, yy++) { 163 | for (uint x = 0, xx = (xpos * 8); x < 8; x++, xx++) { 164 | if (bits[(8 * y) + x]) { 165 | gfx::screen::plot_pixel(gfx::shapes::pos(xx, yy), fg_color); 166 | } else { 167 | gfx::screen::plot_pixel(gfx::shapes::pos(xx, yy), bg_color); 168 | } 169 | } 170 | } 171 | } 172 | 173 | void io::tty::render_entry_at_buffer(uint16 xpos, uint16 ypos) 174 | { 175 | dword fg_color; 176 | dword bg_color; 177 | 178 | word entry = text_buffer[(ypos * vga_width + xpos)]; 179 | 180 | byte vga_color_fg = (entry & 0x0f00) >> 8; 181 | byte vga_color_bg = (entry >> 12); 182 | 183 | char c = entry ^ 0b1111111100000000; 184 | 185 | fg_color = convert_vga_to_pix(vga_color_fg); 186 | bg_color = convert_vga_to_pix(vga_color_bg); 187 | 188 | qword font_selector = gfx::fonts::get_character_font(c); 189 | 190 | byte bits[64]; 191 | 192 | for (uint08 i = 1; i <= 64; i++) { 193 | bits[i - 1] = util::get_bit(font_selector, i); 194 | } 195 | 196 | for (uint y = 0, yy = (ypos * 9); y < 8; y++, yy+=2) { 197 | for (uint x = 0, xx = (xpos * 8); x < 8; x++, xx+=2) { 198 | if (bits[(8 * y) + x]) { 199 | gfx::screen::plot_pixel_buffer(gfx::shapes::pos(xx, yy), fg_color); 200 | } else { 201 | gfx::screen::plot_pixel_buffer(gfx::shapes::pos(xx, yy), bg_color); 202 | } 203 | } 204 | } 205 | } 206 | 207 | void io::tty::render_buffer() 208 | { 209 | for (uint16 ypos = 0; ypos < vga_height; ypos++) 210 | { 211 | for (uint16 xpos = 0; xpos < vga_width; xpos++) 212 | { 213 | render_entry_at(xpos, ypos); 214 | } 215 | } 216 | 217 | // gfx::screen::buff(); 218 | } 219 | 220 | void io::tty::shift() 221 | { 222 | for (size_t i = 0; i < vga_width; i++) 223 | { 224 | text_buffer[i] = vga_entry(0, 0); 225 | } 226 | 227 | for (size_t i = 0; i < vga_width; i++) 228 | { 229 | for (size_t j = 0; j < (vga_height * vga_width); j++) { 230 | text_buffer[j] = text_buffer[j + 1]; // shift text buffer to the left 231 | } 232 | } 233 | row--; 234 | 235 | render_buffer(); 236 | } 237 | 238 | void io::tty::put_char(char c, byte color) 239 | { 240 | if (c == 0) 241 | return; 242 | 243 | if (c == '\t') 244 | { 245 | column = (column / 4 + 1) * 4; 246 | return; 247 | } 248 | 249 | if (c == '\b') 250 | { 251 | if (column == 0) 252 | { 253 | if (row != 0) 254 | { 255 | column = (vga_width - 1); 256 | row--; 257 | } 258 | } 259 | else 260 | column--; 261 | 262 | put_entry_at(' ', 0x0, column, row); 263 | return; 264 | } 265 | 266 | if (c != '\n') 267 | put_entry_at(c, color, column, row); 268 | 269 | if (++column >= vga_width) 270 | { 271 | column = 0; 272 | if (++row >= vga_height) 273 | { 274 | shift(); 275 | } 276 | } 277 | if (c == '\n') 278 | { 279 | if (++row >= vga_height) 280 | { 281 | shift(); 282 | } 283 | column = 0; 284 | } 285 | } 286 | 287 | void io::tty::write(const char *data) 288 | { 289 | byte color = VGA_COLOR_LIGHT_GREY; 290 | char colorCode[15]; 291 | 292 | if (util::strcomp(data, terminal_line)) 293 | { 294 | for (uint i = 0; i < vga_width; i++) 295 | { 296 | if (!(i % 2)) 297 | put_char('-', 0x0F); 298 | else 299 | put_char('=', 0x0F); 300 | } 301 | return; 302 | } 303 | 304 | for (; *data != '\0'; data++) 305 | { 306 | if (*data == '$') 307 | { 308 | int iter = 0; 309 | data++; 310 | while (true) 311 | { 312 | if (*data != '!') 313 | { 314 | colorCode[iter] = *data; 315 | iter++; 316 | data++; 317 | } 318 | else 319 | { 320 | data++; 321 | break; 322 | } 323 | } 324 | colorCode[iter + 1] = 0; 325 | check_vga_color(BLACK) 326 | check_vga_color(BLUE) 327 | check_vga_color(GREEN) 328 | check_vga_color(CYAN) 329 | check_vga_color(RED) 330 | check_vga_color(MAGENTA) 331 | check_vga_color(BROWN) 332 | check_vga_color(LIGHT_GREY) 333 | check_vga_color(DARK_GREY) 334 | check_vga_color(LIGHT_BLUE) 335 | check_vga_color(LIGHT_GREEN) 336 | check_vga_color(LIGHT_CYAN) 337 | check_vga_color(LIGHT_RED) 338 | check_vga_color(LIGHT_MAGENTA) 339 | check_vga_color(LIGHT_BROWN) 340 | check_vga_color(WHITE) 341 | } 342 | put_char(*data, color); 343 | } 344 | } 345 | 346 | void io::tty::set_cursor(size_t columnc, size_t rowc) 347 | { 348 | column = columnc; 349 | row = rowc; 350 | } 351 | 352 | void io::tty::write_line(const char *data) 353 | { 354 | write(data); 355 | write("\n"); 356 | } 357 | 358 | gfx::shapes::dimensions io::tty::get_optimal_size(gfx::shapes::dimensions screen_res) { 359 | gfx::shapes::dimensions term_size; 360 | 361 | term_size.w = (screen_res.w / 8); 362 | term_size.h = (screen_res.h / 9); 363 | 364 | return term_size; 365 | } 366 | 367 | extern "C" void puts(char* data) 368 | { 369 | printf("%s\n", data); 370 | } -------------------------------------------------------------------------------- /kernel/src/drivers/tty/tty.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "types.h" 5 | #include "drivers/gfx/gop/gop.h" 6 | 7 | #define status_pend "$WHITE![$LIGHT_BLUE!-$WHITE!] $LIGHT_GREY!\0" 8 | #define status_good "$WHITE![$LIGHT_GREEN!+$WHITE!] $LIGHT_GREY!\0" 9 | #define status_fail "$WHITE![$RED!X$WHITE!] $LIGHT_GREY!\0" 10 | #define status_eol "\n\0" 11 | #define terminal_line "$TERM_LINE!\0" 12 | 13 | namespace io { 14 | namespace tty { 15 | extern uint vga_width; 16 | extern uint vga_height; 17 | extern uint row; 18 | extern uint column; 19 | extern word* text_buffer; 20 | 21 | static inline word vga_entry(byte uc, byte color) 22 | { return (word)uc | (word)color << 8; } 23 | static inline byte vga_entry_color(byte fg, byte bg) 24 | { return fg | bg << 4; } 25 | void put_entry_at(char c, byte vcolor, size_t x, size_t y); 26 | void put_char(char c, byte color); 27 | void write(const char* data); 28 | void write_line(const char* data = ""); 29 | void shift(); 30 | void clear(); 31 | dword convert_vga_to_pix(byte vcolor); 32 | void set_cursor(size_t columnc, size_t rowc); 33 | gfx::shapes::dimensions get_optimal_size(gfx::shapes::dimensions screen_res); 34 | void render_buffer(); 35 | void render_entry_at(uint16 xpos, uint16 ypos); 36 | void render_entry_at_buffer(uint16 xpos, uint16 ypos); 37 | void initialize(); 38 | 39 | 40 | enum vga_color 41 | { 42 | VGA_COLOR_BLACK = 0, 43 | VGA_COLOR_BLUE = 1, 44 | VGA_COLOR_GREEN = 2, 45 | VGA_COLOR_CYAN = 3, 46 | VGA_COLOR_RED = 4, 47 | VGA_COLOR_MAGENTA = 5, 48 | VGA_COLOR_BROWN = 6, 49 | VGA_COLOR_LIGHT_GREY = 7, 50 | VGA_COLOR_DARK_GREY = 8, 51 | VGA_COLOR_LIGHT_BLUE = 9, 52 | VGA_COLOR_LIGHT_GREEN = 10, 53 | VGA_COLOR_LIGHT_CYAN = 11, 54 | VGA_COLOR_LIGHT_RED = 12, 55 | VGA_COLOR_LIGHT_MAGENTA = 13, 56 | VGA_COLOR_LIGHT_BROWN = 14, 57 | VGA_COLOR_WHITE = 15 58 | }; 59 | 60 | } 61 | } 62 | 63 | extern "C" void puts(char* data); 64 | extern "C" int printf(const char* __restrict format, ...); -------------------------------------------------------------------------------- /kernel/src/drivers/uart/serial.cpp: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "util/kutil.h" 3 | #include "serial.h" 4 | #include "../io.h" 5 | #include "../8259/pic.h" 6 | 7 | char serial_buffer[512]; 8 | int buffer_index = 0; 9 | 10 | void read_command() 11 | { 12 | if (util::strcomp(serial_buffer, "test-commands")) 13 | { 14 | io::serial::serial_msg("We read you, loud and clear, sergeant!\n"); 15 | } 16 | } 17 | 18 | extern "C" void io::serial::serial_msg(const char *val) { 19 | for (uint i = 0; i < util::strlen(val); i++) { 20 | serial_byte(val[i]); 21 | } 22 | } 23 | 24 | void prompt() 25 | { 26 | io::serial::serial_msg("\nkernel-console> "); 27 | } 28 | 29 | void clear_buffer() 30 | { 31 | for (int i = 0; i < 512; i++) 32 | { 33 | serial_buffer[i] = '\0'; 34 | } 35 | } 36 | 37 | void io::serial::console::init() 38 | { 39 | outb(0x3F9, 0b00000001); // set the interrupt enable register 40 | // interrupt when data available 41 | 42 | io::pic::irq_unmask(4); // unmask the COM1 port IRQ line, therefore accepting generated interrupts from COM1 43 | clear_buffer(); 44 | prompt(); 45 | } 46 | 47 | void io::serial::console::read_character() // interrupt 4 will call this function 48 | { 49 | serial_buffer[buffer_index] = inb(0x3F8); 50 | 51 | if (serial_buffer[buffer_index] == '\n') 52 | { 53 | serial_buffer[buffer_index] = '\0'; 54 | io::serial::serial_msg("\r\n"); 55 | read_command(); 56 | clear_buffer(); 57 | buffer_index = 0; 58 | prompt(); 59 | io::serial::serial_byte(serial_buffer[buffer_index]); 60 | } 61 | else 62 | { 63 | io::serial::serial_byte(serial_buffer[buffer_index]); 64 | buffer_index++; 65 | } 66 | } 67 | 68 | 69 | -------------------------------------------------------------------------------- /kernel/src/drivers/uart/serial.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../io.h" 3 | 4 | namespace io { 5 | namespace serial { 6 | extern "C" void serial_msg(const char *val); 7 | static inline void serial_byte(byte val) { 8 | io::outb(0x3F8, val); 9 | } 10 | 11 | namespace console { 12 | void init(); 13 | void read_character(); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /kernel/src/fs/gpt/gpt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.h" 3 | #include "util/guid.h" 4 | 5 | namespace sys { 6 | namespace fs { 7 | namespace gpt { 8 | struct parition_table_header { 9 | uint08 signature[8]; 10 | uint32 revision; 11 | uint32 size; 12 | uint32 header_checksum; 13 | uint32 pad; 14 | uint64 this_lba; 15 | uint64 alt_lba; 16 | uint64 first_usable_block; 17 | uint64 last_usable_block; 18 | guid disk_guid; 19 | uint64 partition_table_lba; 20 | uint32 partition_table_entries; 21 | uint32 partition_table_entry_size; 22 | uint32 partition_table_checksum; 23 | uint08 pad_ex[0x200 - 0x5C]; 24 | } __attribute__((packed)); 25 | 26 | struct partition_table_entry { 27 | guid partition_type_guid; 28 | guid partition_guid; 29 | uint64 start_lba; 30 | uint64 end_lba; 31 | uint64 attributes; 32 | // UNICODE16-LE encoded 33 | uint16 signature[36]; 34 | } __attribute__((packed)); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /kernel/src/memory/heap.cpp: -------------------------------------------------------------------------------- 1 | #include "heap.h" 2 | #include "pmm.h" 3 | 4 | void* heap_start; 5 | void* heap_end; 6 | 7 | void memory::heap::initialize_heap(void* heap_address, uint64 heap_length) { 8 | heap_start = heap_address; 9 | heap_end = (void*)((uint64)heap_start + heap_length); 10 | heap_segment_header* start_segment = (heap_segment_header*)heap_address; 11 | start_segment->length = heap_length - sizeof(heap_segment_header); 12 | start_segment->last = NULL; 13 | start_segment->next = NULL; 14 | start_segment->free = true; 15 | } 16 | 17 | void* memory::heap::malloc(uint64 size) { 18 | if (size == 0) return nullptr; 19 | if (size % 0x10 != 0) size = size % 0x10 + 0x10; //Make sure to round up to 0x10 20 | 21 | heap_segment_header* current_segment = (heap_segment_header*)heap_start; 22 | while (true) { 23 | if (current_segment->free) { 24 | 25 | if (current_segment->length > size) { 26 | current_segment->split(size); 27 | current_segment->free = false; 28 | return current_segment; 29 | } 30 | if (current_segment->length == size ) { 31 | current_segment->free = false; 32 | return current_segment; 33 | } 34 | } 35 | if (current_segment->next == NULL) break; 36 | current_segment = current_segment->next; 37 | } 38 | return nullptr; 39 | } 40 | 41 | void memory::heap::free(void* addr) { 42 | heap_segment_header* current_segment = (heap_segment_header*)addr; 43 | current_segment->free = true; 44 | if (current_segment->next != NULL && current_segment->next->free)current_segment->combine_forward(); 45 | if (current_segment->last != NULL && current_segment->last->free)current_segment->combine_backward(); 46 | } 47 | 48 | memory::heap::heap_segment_header* memory::heap::heap_segment_header::split(uint64 split_length) { 49 | if (split_length < 0x10) return NULL; 50 | uint64 splitSegLength = length - split_length - (sizeof(heap_segment_header) * 2); 51 | if (splitSegLength< 0x10) return NULL; 52 | heap_segment_header* new_split_header = (heap_segment_header*) ((uint64)this + split_length + sizeof(heap_segment_header)); 53 | next->last = new_split_header; // Set the next segment's last segment to our new segment 54 | new_split_header->next = next; // Set the new segment's next segment to our original next segment 55 | next = new_split_header; // Set our next segment to our new segment 56 | new_split_header->last = this; // Set our new segment's last segment to the currect segment 57 | new_split_header->length = splitSegLength; 58 | new_split_header->free = free; // Make sure the new segment is as free as the original 59 | length = split_length; 60 | return new_split_header; 61 | } 62 | 63 | void memory::heap::heap_segment_header::combine_forward() { 64 | if (next == NULL) return; 65 | if (!next->free) return; 66 | 67 | if (next->next != NULL) 68 | next->next->last = this; 69 | 70 | length = length + next->length + sizeof(heap_segment_header); 71 | 72 | next = next->next; 73 | } 74 | 75 | void memory::heap::heap_segment_header::combine_backward() { 76 | if (last != NULL) last->combine_forward(); 77 | } 78 | -------------------------------------------------------------------------------- /kernel/src/memory/heap.h: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "boot/boot.h" 3 | 4 | namespace memory { 5 | namespace heap { 6 | struct heap_segment_header { 7 | uint64 length; 8 | heap_segment_header* next; 9 | heap_segment_header* last; 10 | bool free; 11 | void combine_forward(); 12 | void combine_backward(); 13 | heap_segment_header* split(uint64 split_length); 14 | }; 15 | 16 | void* malloc(uint64 bytes); 17 | void free(void* data); 18 | void initialize_heap(void* heap_address, uint64 heap_length); 19 | } 20 | } -------------------------------------------------------------------------------- /kernel/src/memory/operations.cpp: -------------------------------------------------------------------------------- 1 | #include "operations.h" 2 | 3 | void *memory::operations::memcpy(void *__restrict dst, const void *__restrict src, uint64 count) 4 | { 5 | asm volatile ("cld; rep movsb" : "+c" (count), "+S" (src), "+D" (dst) :: "memory"); 6 | return dst; 7 | } 8 | 9 | void* memory::operations::memset(void* bufptr, byte value, uint64 size) { 10 | byte* buf = (byte *) bufptr; 11 | for (uint64 i = 0; i < size; i++) 12 | buf[i] = value; 13 | return bufptr; 14 | } -------------------------------------------------------------------------------- /kernel/src/memory/operations.h: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | 3 | namespace memory { 4 | namespace operations { 5 | void* memcpy(void* __restrict dst, const void* __restrict src, uint64 size); 6 | void* memset(void* dst, byte value, uint64 size); 7 | } 8 | } -------------------------------------------------------------------------------- /kernel/src/memory/paging.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by rizet on 1/26/21. 3 | // 4 | #include "types.h" 5 | #include "boot/kconf.h" 6 | #include "memory/pmm.h" 7 | #include "memory/paging.h" 8 | #include "memory/operations.h" 9 | #include "boot/boot.h" 10 | #include "drivers/io.h" 11 | #include "util/kutil.h" 12 | #include "util/bitmap.h" 13 | 14 | memory::paging::page_table* memory::paging::pml_4; 15 | 16 | memory::paging::page_map_indexer::page_map_indexer(uint64 virtual_address) { 17 | 18 | virtual_address >>= 12; 19 | p_i = virtual_address & 0x1ff; 20 | virtual_address >>= 9; 21 | pt_i = virtual_address & 0x1ff; 22 | virtual_address >>= 9; 23 | pd_i = virtual_address & 0x1ff; 24 | virtual_address >>= 9; 25 | pdp_i = virtual_address & 0x1ff; 26 | } 27 | 28 | void memory::paging::map_memory(void *virtual_memory, void *physical_memory, bool quickwrite) 29 | { 30 | page_map_indexer indexer = page_map_indexer((uint64)virtual_memory); 31 | page_directory_entry pde; 32 | 33 | pde = pml_4->entries[indexer.pdp_i]; 34 | page_table* pdp; 35 | if (!pde.get_flag(pt_flag::present)) { 36 | 37 | pdp = (page_table*)pmm::request_page(); 38 | memory::operations::memset(pdp, 0, 0x1000); 39 | pde.set_address((uint64)pdp >> 12); 40 | pde.set_flag(pt_flag::present, true); 41 | pde.set_flag(pt_flag::read_write, true); 42 | pml_4->entries[indexer.pdp_i] = pde; 43 | memory::paging::map_memory((void *)pdp, (void *)pdp, false); 44 | } 45 | else 46 | pdp = (page_table*)((uint64)pde.get_address() << 12); 47 | 48 | 49 | pde = pdp->entries[indexer.pd_i]; 50 | page_table* pd; 51 | if (!pde.get_flag(pt_flag::present)) { 52 | 53 | pd = (page_table*)pmm::request_page(); 54 | memory::operations::memset(pd, 0, 0x1000); 55 | pde.set_address((uint64)pd >> 12); 56 | pde.set_flag(pt_flag::present, true); 57 | pde.set_flag(pt_flag::read_write, true); 58 | pdp->entries[indexer.pd_i] = pde; 59 | memory::paging::map_memory((void *)pd, (void *)pd, false); 60 | } 61 | else 62 | pd = (page_table*)((uint64)pde.get_address() << 12); 63 | 64 | pde = pd->entries[indexer.pt_i]; 65 | page_table* pt; 66 | if (!pde.get_flag(pt_flag::present)) { 67 | 68 | pt = (page_table*)pmm::request_page(); 69 | memory::operations::memset(pt, 0, 0x1000); 70 | pde.set_address((uint64)pt >> 12); 71 | pde.set_flag(pt_flag::present, true); 72 | pde.set_flag(pt_flag::read_write, true); 73 | pd->entries[indexer.pt_i] = pde; 74 | memory::paging::map_memory((void *)pt, (void *)pt, false); 75 | } 76 | else 77 | pt = (page_table*)((uint64)pde.get_address() << 12); 78 | 79 | 80 | pde = pt->entries[indexer.p_i]; 81 | pde.set_address((uint64)physical_memory >> 12); 82 | pde.set_flag(pt_flag::present, true); 83 | pde.set_flag(pt_flag::read_write, true); 84 | pde.set_pat(quickwrite); 85 | pt->entries[indexer.p_i] = pde; 86 | } 87 | 88 | void* memory::paging::get_physical_address(void* virtual_address) 89 | { 90 | page_map_indexer indexer = page_map_indexer((uint64)virtual_address); 91 | page_directory_entry pde; 92 | 93 | uint16 address_offset = (uint16)(uint64)virtual_address & 0xFFF; 94 | virtual_address = (void *)~(uint64)virtual_address; 95 | 96 | pde = pml_4->entries[indexer.pdp_i]; 97 | page_table* pdp; 98 | 99 | if (!pde.get_flag(pt_flag::present)) 100 | return (void *)-1; 101 | 102 | pdp = (page_table*)((uint64)pde.get_address() << 12); 103 | 104 | 105 | pde = pdp->entries[indexer.pd_i]; 106 | page_table* pd; 107 | 108 | if (!pde.get_flag(pt_flag::present)) 109 | return (void *)-1; 110 | 111 | pd = (page_table*)((uint64)pde.get_address() << 12); 112 | 113 | pde = pd->entries[indexer.pt_i]; 114 | page_table* pt; 115 | 116 | if (!pde.get_flag(pt_flag::present)) 117 | return (void *)-1; 118 | 119 | pt = (page_table*)((uint64)pde.get_address() << 12); 120 | 121 | pde = pt->entries[indexer.p_i]; 122 | 123 | if (!pde.get_flag(present)) 124 | return (void *)-1; 125 | 126 | return (void *)((pde.get_address() << 12) | address_offset); 127 | } 128 | 129 | extern "C" void memory::paging::donate_to_userspace(void* virtual_address) 130 | { 131 | page_map_indexer indexer = page_map_indexer((uint64)virtual_address); 132 | page_directory_entry pde; 133 | pde = pml_4->entries[indexer.pdp_i]; 134 | pml_4->entries[indexer.pdp_i].set_flag(pt_flag::user_super, 1); 135 | page_table* pdp = (page_table*)((uint64)pde.get_address() << 12); 136 | pdp->entries[indexer.pd_i].set_flag(pt_flag::user_super, 1); 137 | pde = pdp->entries[indexer.pd_i]; 138 | page_table* pd = (page_table*)((uint64)pde.get_address() << 12); 139 | pd->entries[indexer.pt_i].set_flag(pt_flag::user_super, 1); 140 | pde = pd->entries[indexer.pt_i]; 141 | page_table* pt = (page_table*)((uint64)pde.get_address() << 12); 142 | pt->entries[indexer.p_i].set_flag(pt_flag::user_super, 1); 143 | } 144 | 145 | void memory::paging::page_directory_entry::set_flag(pt_flag flag, bool enabled) { 146 | 147 | uint64 bit_selector = (uint64)1 << flag; 148 | value &= ~bit_selector; 149 | if (enabled) 150 | value |= bit_selector; 151 | } 152 | 153 | bool memory::paging::page_directory_entry::get_flag(pt_flag flag) { 154 | 155 | uint64 bit_selector = (uint64)1 << flag; 156 | return (value & bit_selector) > 0 ? true : false; 157 | } 158 | 159 | uint64 memory::paging::page_directory_entry::get_address() { 160 | 161 | return (value & 0x000ffffffffff000) >> 12; 162 | } 163 | 164 | void memory::paging::page_directory_entry::set_address(address paddress) { 165 | 166 | paddress &= 0x000000ffffffffff; 167 | value &= 0xfff0000000000fff; 168 | value |= (paddress << 12); 169 | } 170 | 171 | void memory::paging::page_directory_entry::set_pat(uint08 index) { 172 | 173 | index &= 0b111; 174 | set_flag(pt_flag::write_through, index & 1); 175 | index >>= 1; 176 | set_flag(pt_flag::cache_disabled, index & 1); 177 | index >>= 1; 178 | set_flag(pt_flag::larger_pages, index & 1); 179 | } -------------------------------------------------------------------------------- /kernel/src/memory/paging.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.h" 3 | #include 4 | #include "boot/boot.h" 5 | #include "util/kutil.h" 6 | #include "drivers/io.h" 7 | 8 | namespace memory { 9 | namespace paging { 10 | enum pt_flag { 11 | present = 0, 12 | read_write = 1, 13 | user_super = 2, 14 | write_through = 3, 15 | cache_disabled = 4, 16 | accessed = 5, 17 | larger_pages = 7, 18 | custom_0 = 9, 19 | custom_1 = 10, 20 | custom_2 = 11, 21 | nx = 63 // only if supported 22 | }; 23 | struct page_directory_entry { 24 | uint64 value; 25 | void set_flag(pt_flag flag, bool enabled); 26 | bool get_flag(pt_flag flag); 27 | void set_pat(uint08 index); 28 | void set_address(uint64 address); 29 | uint64 get_address(); 30 | }; 31 | 32 | struct page_table { 33 | page_directory_entry entries [512]; 34 | }__attribute__((aligned(0x1000))); 35 | 36 | class page_map_indexer { 37 | public: 38 | page_map_indexer(uint64 virtual_address); 39 | uint64 pdp_i; 40 | uint64 pd_i; 41 | uint64 pt_i; 42 | uint64 p_i; 43 | }; 44 | 45 | extern page_table* pml_4; 46 | 47 | void map_memory(void* virtual_memory, void* physical_memory, bool quickwrite); 48 | extern "C" void donate_to_userspace(void* virtual_address); 49 | void* get_physical_address(void* virtual_address); 50 | } 51 | } -------------------------------------------------------------------------------- /kernel/src/memory/pat.asm: -------------------------------------------------------------------------------- 1 | global configure_pat:function (configure_pat.end - configure_pat) 2 | 3 | configure_pat: 4 | push rbp 5 | mov rbp, rsp 6 | xor rax, rax 7 | mov al, 6 8 | mov ah, 1 9 | mov bl, 0 10 | shl bl, 16 11 | or eax, ebx 12 | mov cx, 0x277 13 | wrmsr 14 | pop rbp 15 | ret 16 | .end: -------------------------------------------------------------------------------- /kernel/src/memory/pmm.cpp: -------------------------------------------------------------------------------- 1 | #include "pmm.h" 2 | #include "util/kutil.h" 3 | #include "util/bitmap.h" 4 | #include "drivers/uart/serial.h" 5 | #include "boot/kconf.h" 6 | #include "paging.h" 7 | 8 | uint memory::pmm::free_memory_size; 9 | uint memory::pmm::used_memory_size; 10 | uint memory::pmm::total_memory_size; 11 | uint memory::pmm::reserved_memory_size; 12 | util::bitmap page_bitmap_map; 13 | bool initialized = false; 14 | 15 | const char *memory_types(uint16 type) 16 | { 17 | switch (type) 18 | { 19 | case 1: return (const char *)"Conventional memory"; 20 | case 2: return (const char *)"Reserved memory"; 21 | case 3: return (const char *)"Reclaimable ACPI memory"; 22 | case 4: return (const char *)"ACPI NVS memory"; 23 | case 5: return (const char *)"Faulty memory"; 24 | case 10: return (const char *)"Kernel memory"; 25 | case 4096: return (const char *)"Reclaimable bootloader memory"; 26 | default: return (const char *)"Unidentified memory"; 27 | } 28 | return nullptr; 29 | } 30 | 31 | void init_bitmap(uint64 bitmap_size, void* addr) 32 | { 33 | page_bitmap_map.size = bitmap_size; 34 | page_bitmap_map.buffer = (byte*)addr; 35 | for (uint64 i = 0; i < bitmap_size; i++) 36 | *(byte *)(page_bitmap_map.buffer + i) = 0; 37 | } 38 | 39 | uint memory::pmm::get_total_memory_size(stivale_memory_map* memory_map, uint64 map_size, uint64 desc_size) 40 | { 41 | static uint64 memory_size_bytes = 0; 42 | if (memory_size_bytes > 0) return memory_size_bytes; 43 | 44 | uint64 map_entries = map_size / desc_size; 45 | 46 | for (uint i = 0; i < map_entries; i++) { 47 | stivale_mmap_entry* desc = (stivale_mmap_entry *)((address)memory_map->memory_map_addr + (i * desc_size)); 48 | 49 | if (desc->type == 1) 50 | memory_size_bytes = desc->base + desc->length; 51 | } 52 | 53 | memory_size_bytes /= 0x100000; ////////// 54 | memory_size_bytes *= 0x100000; //// account for inaccuracies 55 | 56 | return memory_size_bytes; 57 | } 58 | 59 | extern "C" void reserve_pages(void* vaddress, uint64 page_count); 60 | 61 | void memory::pmm::initialize(stivale_memory_map* memory_map, uint64 map_size, uint64 desc_size) 62 | { 63 | if (initialized) return; 64 | 65 | initialized = true; 66 | 67 | uint map_entries = map_size / desc_size; 68 | 69 | void* largest_free_memory_segment = NULL; 70 | uint largest_free_memory_segment_size = 0; 71 | 72 | for (uint i = 0; i < map_entries; i++) { 73 | stivale_mmap_entry* desc = (stivale_mmap_entry *)((address)memory_map->memory_map_addr + (i * desc_size)); 74 | if (desc->type == 1) { // usable memory 75 | if ((desc->length / 0x1000) * 4096 > largest_free_memory_segment_size) 76 | { 77 | largest_free_memory_segment = (void *)desc->base; 78 | largest_free_memory_segment_size = (desc->length / 0x1000) * 4096; 79 | } 80 | } 81 | 82 | io::serial::serial_msg("@ 0x"); 83 | io::serial::serial_msg(util::itoa(desc->base, 16)); 84 | io::serial::serial_msg(": "); 85 | io::serial::serial_msg(memory_types(desc->type)); 86 | io::serial::serial_msg(", for "); 87 | io::serial::serial_msg(util::itoa((desc->length / 0x1000), 10)); 88 | io::serial::serial_msg(" pages\n"); 89 | } 90 | 91 | uint memory_size = get_total_memory_size(memory_map, map_size, desc_size); 92 | total_memory_size = memory_size; 93 | free_memory_size = memory_size; 94 | uint bitmap_size = memory_size / 4096 / 8 + 1; 95 | 96 | io::serial::serial_msg("Memory size (MiB): "); 97 | io::serial::serial_msg(util::itoa(memory_size / 0x100000, 10)); 98 | io::serial::serial_msg("\nBitmap size (B): "); 99 | io::serial::serial_msg(util::itoa(bitmap_size, 10)); 100 | io::serial::serial_msg("\n"); 101 | 102 | init_bitmap(bitmap_size, largest_free_memory_segment); 103 | 104 | for (uint i = 0; i < map_entries; i++) { 105 | stivale_mmap_entry* desc = (stivale_mmap_entry *)((address)memory_map->memory_map_addr + (i * desc_size)); 106 | if (desc->type != 1 && desc->base < memory_size) // not conventional memory 107 | reserve_pages((void *)desc->base, (desc->length / 0x1000)); 108 | } 109 | 110 | lock_pages(page_bitmap_map.buffer, page_bitmap_map.size / 4096 + 1); 111 | 112 | reserve_pages((void *)0x0, 0x100000 / 0x1000); 113 | reserve_pages((void *)&sys::config::__kernel_start, sys::config::__kernel_pages); 114 | } 115 | 116 | void unreserve_page(void* vaddress) { 117 | 118 | uint64 index = (uint64)vaddress / 4096; 119 | 120 | if (page_bitmap_map[index] == false) 121 | return; 122 | 123 | page_bitmap_map.set(index, false); 124 | memory::pmm::free_memory_size += 4096; 125 | memory::pmm::reserved_memory_size -= 4096; 126 | } 127 | 128 | void unreserve_pages(void* vaddress, uint64 pageCount) { 129 | 130 | for (uint t = 0; t < pageCount; t++) 131 | unreserve_page((void*)((uint64)vaddress + (t * 4096))); 132 | } 133 | 134 | extern "C" void reserve_page(void* vaddress) 135 | { 136 | uint64 index = (uint64)vaddress / 4096; 137 | 138 | if (page_bitmap_map[index] == true) 139 | return; 140 | 141 | page_bitmap_map.set(index, true); 142 | memory::pmm::free_memory_size -= 4096; 143 | memory::pmm::reserved_memory_size += 4096; 144 | } 145 | 146 | extern "C" void reserve_pages(void* vaddress, uint64 pageCount) { 147 | 148 | for (uint t = 0; t < pageCount; t++) 149 | reserve_page((void*)((address)vaddress + (t * 4096))); 150 | } 151 | 152 | extern "C" void* memory::pmm::request_page() { 153 | 154 | for (uint index = 0; index < page_bitmap_map.size * 8; index++) { 155 | 156 | if (page_bitmap_map[index] == true) 157 | continue; 158 | /* 159 | io::serial::serial_msg("requested page, located @paddr-0x"); 160 | io::serial::serial_msg(util::itoa(index * 4096, 16)); 161 | io::serial::serial_msg("\n"); 162 | */ 163 | memory::pmm::lock_page((void*)(index * 4096)); 164 | 165 | return (void*)(index * 4096); 166 | } 167 | 168 | return nullptr; 169 | } 170 | 171 | extern "C" void* memory::pmm::request_pages(uint64 page_count) 172 | { 173 | if (page_count <= 1) 174 | return nullptr; 175 | 176 | void* start_ptr = request_page(); 177 | page_count--; 178 | 179 | paging::map_memory(start_ptr, start_ptr, false); 180 | 181 | for (uint i = 1; i <= page_count; i++) 182 | { 183 | void* page_ptr = request_page(); 184 | paging::map_memory((void *)((uint64)start_ptr + (i * 0x1000)), page_ptr, false); 185 | } 186 | 187 | return start_ptr; 188 | } 189 | 190 | extern "C" void memory::pmm::free_page(void* vaddress) { 191 | 192 | uint index = (uint64)vaddress / 4096; 193 | if (page_bitmap_map[index] == false) return; 194 | page_bitmap_map.set(index, false); 195 | free_memory_size += 4096; 196 | used_memory_size -= 4096; 197 | } 198 | 199 | extern "C" void memory::pmm::free_pages(void* vaddress, uint64 page_count) { 200 | 201 | for (uint64 t = 0; t < page_count; t++) 202 | memory::pmm::free_page((void*)((address)vaddress + (t * 4096))); 203 | } 204 | 205 | extern "C" void memory::pmm::lock_page(void* vaddress) { 206 | uint index = (uint64)vaddress / 4096; 207 | if (page_bitmap_map[index] == true) return; 208 | page_bitmap_map.set(index, true); 209 | free_memory_size -= 4096; 210 | used_memory_size += 4096; 211 | } 212 | 213 | extern "C" void memory::pmm::lock_pages(void* vaddress, uint64 page_count) { 214 | 215 | for (uint t = 0; t < page_count; t++) 216 | memory::pmm::lock_page((void*)((uint64)vaddress + (t * 4096))); 217 | } 218 | -------------------------------------------------------------------------------- /kernel/src/memory/pmm.h: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "boot/boot.h" 3 | 4 | namespace memory { 5 | namespace pmm { 6 | extern uint free_memory_size; 7 | extern uint used_memory_size; 8 | extern uint total_memory_size; 9 | extern uint reserved_memory_size; 10 | 11 | void initialize(stivale_memory_map* memory_map, uint64 map_size, uint64 desc_size); 12 | uint get_total_memory_size(stivale_memory_map* memory_map, uint64 map_size, uint64 desc_size); 13 | 14 | extern "C" void free_page(void* address); 15 | extern "C" void free_pages(void* address, uint64 page_count); 16 | extern "C" void lock_page(void* address); 17 | extern "C" void lock_pages(void* address, uint64 page_count); 18 | extern "C" void* request_page(); 19 | extern "C" void* request_pages(uint64 page_count); 20 | } 21 | } -------------------------------------------------------------------------------- /kernel/src/mnk.lds: -------------------------------------------------------------------------------- 1 | ENTRY(mnkentry) 2 | 3 | SECTIONS 4 | { 5 | . = 2M; 6 | 7 | __kernel_start = .; 8 | 9 | .stivalehdr : 10 | { 11 | KEEP(*(.stivalehdr)) 12 | } 13 | 14 | . = ALIGN(4K); 15 | 16 | .text : 17 | { 18 | *(.text) 19 | . = ALIGN(4K); 20 | uentry = .; 21 | *(.userspace) 22 | *(.data.userspace) 23 | *(.rodata.userspace) 24 | } 25 | 26 | . = ALIGN(4k); 27 | 28 | .data : 29 | { 30 | *(.rodata .rodata.*) 31 | *(.data.rel.ro.local*) *(.data.rel.ro .data.rel.ro.*) *(.data.*) 32 | } 33 | 34 | . = ALIGN(4K); 35 | 36 | .bss : 37 | { 38 | *(.bss .bss.*) 39 | } 40 | 41 | . = ALIGN(4K); 42 | 43 | __kernel_end = .; 44 | } -------------------------------------------------------------------------------- /kernel/src/scheduling/sleep.asm: -------------------------------------------------------------------------------- 1 | global sleep 2 | extern ms_clock 3 | 4 | default rel 5 | 6 | sleep: 7 | push rbp 8 | mov rbp, rsp 9 | push rax 10 | mov rax, 0 11 | mov qword [ms_clock], rax 12 | xor rax, rax 13 | mov eax, edi 14 | .loop: 15 | cli 16 | mov rbx, qword [ms_clock] 17 | cmp rbx, rax 18 | jg .done 19 | sti 20 | nop 21 | nop 22 | nop 23 | nop 24 | nop 25 | nop 26 | nop 27 | jmp .loop 28 | .done: 29 | sti 30 | pop rax 31 | pop rbp 32 | ret 33 | -------------------------------------------------------------------------------- /kernel/src/scheduling/timer.cpp: -------------------------------------------------------------------------------- 1 | #include "scheduling/timer.h" 2 | #include "drivers/8259/pic.h" 3 | 4 | uint16 io::pit::divisor = 0; 5 | uint32 io::pit::frequency_hz = 0; 6 | uint16 io::pit::c2_divisor = 0; 7 | uint32 io::pit::c2_frequency_hz = 0; 8 | 9 | void io::pit::pit_init() 10 | { 11 | io::pic::irq_unmask(0); 12 | } 13 | 14 | void io::pit::set_c0_frequency(uint32 hz) 15 | { 16 | asm volatile ("cli"); 17 | frequency_hz = hz; 18 | divisor = 1193182 / hz; /* Calculate our divisor */ 19 | io::outb(0x43, 0x34); /* Set our command byte 0x34 */ 20 | io::outb(0x40, divisor & 0xFF); /* Set low byte of divisor */ 21 | io::outb(0x40, divisor >> 8); /* Set high byte of divisor */ 22 | asm volatile ("sti"); 23 | } 24 | 25 | void io::pit::set_c2_frequency(uint32 hz) 26 | { 27 | asm volatile ("cli"); 28 | c2_frequency_hz = hz; 29 | c2_divisor = 1193182 / hz; /* Calculate our divisor */ 30 | io::outb(0x43, 0xB6); /* Set our command byte 0x34 */ 31 | io::outb(0x42, divisor & 0xFF); /* Set low byte of divisor */ 32 | io::outb(0x42, divisor >> 8); /* Set high byte of divisor */ 33 | asm volatile ("sti"); 34 | } 35 | 36 | uint64 sys::chrono::ms_clock = 0; -------------------------------------------------------------------------------- /kernel/src/scheduling/timer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "drivers/io.h" 4 | 5 | namespace io { 6 | namespace pit { 7 | void pit_init(); 8 | void set_c0_frequency(uint32 hz); 9 | void set_c2_frequency(uint32 hz); 10 | extern uint32 frequency_hz; 11 | extern uint16 divisor; 12 | extern uint32 c2_frequency_hz; 13 | extern uint16 c2_divisor; 14 | } 15 | } 16 | 17 | namespace sys { 18 | namespace chrono { 19 | extern "C" uint ms_clock; 20 | extern "C" void sleep(uint ms); 21 | } 22 | } -------------------------------------------------------------------------------- /kernel/src/symbols.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | typedef struct { 6 | address addr; 7 | char* name; 8 | } symbol; -------------------------------------------------------------------------------- /kernel/src/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | typedef __UINT8_TYPE__ byte; 5 | typedef __UINT16_TYPE__ word; 6 | typedef __UINT32_TYPE__ dword; 7 | typedef __UINT64_TYPE__ qword; 8 | typedef __uint128_t oword; 9 | 10 | typedef __UINT8_TYPE__ uint08; 11 | typedef __UINT16_TYPE__ uint16; 12 | typedef __UINT32_TYPE__ uint32; 13 | typedef __UINT64_TYPE__ uint64; 14 | typedef __uint128_t uint128; 15 | 16 | typedef __INT8_TYPE__ sint08; 17 | typedef __INT16_TYPE__ sint16; 18 | typedef __INT32_TYPE__ sint32; 19 | typedef __INT64_TYPE__ sint64; 20 | typedef __int128_t sint128; 21 | 22 | typedef sint64 sint; 23 | typedef uint64 uint; 24 | 25 | typedef uint64 address; -------------------------------------------------------------------------------- /kernel/src/userspace/entry/cpuid.cpp: -------------------------------------------------------------------------------- 1 | #include "ecpuid.h" 2 | 3 | __attribute__((section(".userspace"))) 4 | bool cpuid_get_field(CPUID_REGISTER reg, CPUID_FIELD field) 5 | { 6 | unsigned int eax, ebx, ecx, edx; 7 | __cpuid(1, eax, ebx, ecx, edx); 8 | 9 | switch (reg) 10 | { 11 | case ECX: 12 | return ecx & field; 13 | 14 | case EDX: 15 | return edx & field; 16 | 17 | default: 18 | return 0; 19 | } 20 | } -------------------------------------------------------------------------------- /kernel/src/userspace/entry/ecpuid.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | enum CPUID_FIELD { 5 | CPUID_FEAT_ECX_SSE3 = 1 << 0, 6 | CPUID_FEAT_ECX_PCLMUL = 1 << 1, 7 | CPUID_FEAT_ECX_DTES64 = 1 << 2, 8 | CPUID_FEAT_ECX_MONITOR = 1 << 3, 9 | CPUID_FEAT_ECX_DS_CPL = 1 << 4, 10 | CPUID_FEAT_ECX_VMX = 1 << 5, 11 | CPUID_FEAT_ECX_SMX = 1 << 6, 12 | CPUID_FEAT_ECX_EST = 1 << 7, 13 | CPUID_FEAT_ECX_TM2 = 1 << 8, 14 | CPUID_FEAT_ECX_SSSE3 = 1 << 9, 15 | CPUID_FEAT_ECX_CID = 1 << 10, 16 | CPUID_FEAT_ECX_FMA = 1 << 12, 17 | CPUID_FEAT_ECX_CX16 = 1 << 13, 18 | CPUID_FEAT_ECX_ETPRD = 1 << 14, 19 | CPUID_FEAT_ECX_PDCM = 1 << 15, 20 | CPUID_FEAT_ECX_PCIDE = 1 << 17, 21 | CPUID_FEAT_ECX_DCA = 1 << 18, 22 | CPUID_FEAT_ECX_SSE4_1 = 1 << 19, 23 | CPUID_FEAT_ECX_SSE4_2 = 1 << 20, 24 | CPUID_FEAT_ECX_x2APIC = 1 << 21, 25 | CPUID_FEAT_ECX_MOVBE = 1 << 22, 26 | CPUID_FEAT_ECX_POPCNT = 1 << 23, 27 | CPUID_FEAT_ECX_AES = 1 << 25, 28 | CPUID_FEAT_ECX_XSAVE = 1 << 26, 29 | CPUID_FEAT_ECX_OSXSAVE = 1 << 27, 30 | CPUID_FEAT_ECX_AVX = 1 << 28, 31 | 32 | CPUID_FEAT_EDX_FPU = 1 << 0, 33 | CPUID_FEAT_EDX_VME = 1 << 1, 34 | CPUID_FEAT_EDX_DE = 1 << 2, 35 | CPUID_FEAT_EDX_PSE = 1 << 3, 36 | CPUID_FEAT_EDX_TSC = 1 << 4, 37 | CPUID_FEAT_EDX_MSR = 1 << 5, 38 | CPUID_FEAT_EDX_PAE = 1 << 6, 39 | CPUID_FEAT_EDX_MCE = 1 << 7, 40 | CPUID_FEAT_EDX_CX8 = 1 << 8, 41 | CPUID_FEAT_EDX_APIC = 1 << 9, 42 | CPUID_FEAT_EDX_SEP = 1 << 11, 43 | CPUID_FEAT_EDX_MTRR = 1 << 12, 44 | CPUID_FEAT_EDX_PGE = 1 << 13, 45 | CPUID_FEAT_EDX_MCA = 1 << 14, 46 | CPUID_FEAT_EDX_CMOV = 1 << 15, 47 | CPUID_FEAT_EDX_PAT = 1 << 16, 48 | CPUID_FEAT_EDX_PSE36 = 1 << 17, 49 | CPUID_FEAT_EDX_PSN = 1 << 18, 50 | CPUID_FEAT_EDX_CLF = 1 << 19, 51 | CPUID_FEAT_EDX_DTES = 1 << 21, 52 | CPUID_FEAT_EDX_ACPI = 1 << 22, 53 | CPUID_FEAT_EDX_MMX = 1 << 23, 54 | CPUID_FEAT_EDX_FXSR = 1 << 24, 55 | CPUID_FEAT_EDX_SSE = 1 << 25, 56 | CPUID_FEAT_EDX_SSE2 = 1 << 26, 57 | CPUID_FEAT_EDX_SS = 1 << 27, 58 | CPUID_FEAT_EDX_HTT = 1 << 28, 59 | CPUID_FEAT_EDX_TM1 = 1 << 29, 60 | CPUID_FEAT_EDX_IA64 = 1 << 30, 61 | CPUID_FEAT_EDX_PBE = 1 << 31 62 | }; 63 | 64 | enum CPUID_REGISTER { 65 | EAX, 66 | EBX, 67 | ECX, 68 | EDX 69 | }; 70 | 71 | bool cpuid_get_field(CPUID_REGISTER reg, CPUID_FIELD field); -------------------------------------------------------------------------------- /kernel/src/userspace/entry/kcascii.cpp: -------------------------------------------------------------------------------- 1 | #include "keyboard.h" 2 | 3 | __attribute__((section(".data.userspace"))) 4 | const char kbdus[] 5 | { 6 | 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 7 | '-', '=', '\b', '\t', 8 | 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 9 | '[', ']', '\n', 0, 10 | 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 11 | '`', 0, '\\', 12 | 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, '*', 0, 13 | ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14 | '7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.' 15 | }; 16 | 17 | __attribute__((section(".data.userspace"))) 18 | const char kbdus_c[] 19 | { 20 | 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 21 | '-', '=', '\b', '\t', 22 | 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', 23 | '[', ']', '\n', 0, 24 | 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '\'', 25 | '`', 0, '\\', 26 | 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', 0, '*', 0, 27 | ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28 | '7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.' 29 | }; 30 | 31 | __attribute__((section(".data.userspace"))) 32 | const char kbdus_s[] 33 | { 34 | 0, 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', 35 | '_', '+', '\b', '\t', 36 | 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', 37 | '{', '}', '\n', 0, 38 | 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '\'', 39 | '~', 0, '|', 40 | 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, '*', 0, 41 | ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42 | '7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.' 43 | }; 44 | 45 | __attribute__((section(".data.userspace"))) 46 | const char kbdus_sc[] 47 | { 48 | 0, 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', 49 | '_', '+', '\b', '\t', 50 | 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 51 | '{', '}', '\n', 0, 52 | 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 53 | '~', 0, '|', 54 | 'z', 'x', 'c', 'v', 'b', 'n', 'm', '<', '>', '?', 0, '*', 0, 55 | ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56 | '7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.' 57 | }; 58 | 59 | __attribute__((section(".userspace"))) 60 | char kcascii(unsigned char kc, bool shift, bool caps) 61 | { 62 | if (kc > keypad_period) 63 | return 0; 64 | 65 | if (!shift && !caps) 66 | return kbdus[kc]; 67 | 68 | if (shift && !caps) 69 | return kbdus_s[kc]; 70 | 71 | if (shift && caps) 72 | return kbdus_sc[kc]; 73 | 74 | return 0; 75 | } -------------------------------------------------------------------------------- /kernel/src/userspace/entry/keyboard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | __attribute__((section(".userspace"))) 4 | char kcascii(unsigned char kc, bool shift, bool caps); 5 | 6 | struct keyboard_event_args { 7 | unsigned char key_code : 8; 8 | bool release_or_press : 1; 9 | bool shifted : 1; 10 | bool ctrl_down : 1; 11 | bool alt_down : 1; 12 | bool fn_down : 1; 13 | bool caps_lock : 1; 14 | bool scroll_lock : 1; 15 | bool num_lock : 1; 16 | } __attribute__((packed)); 17 | 18 | enum key_code { 19 | null, 20 | escape, 21 | one, 22 | two, 23 | three, 24 | four, 25 | five, 26 | six, 27 | seven, 28 | eight, 29 | nine, 30 | zero, 31 | dash, 32 | equal, 33 | backspace, 34 | tab, 35 | q, 36 | w, 37 | e, 38 | r, 39 | t, 40 | y, 41 | u, 42 | i, 43 | o, 44 | p, 45 | open_bracket, 46 | close_bracket, 47 | enter, 48 | left_ctrl, 49 | a, 50 | s, 51 | d, 52 | f, 53 | g, 54 | h, 55 | j, 56 | k, 57 | l, 58 | semicolon, 59 | apostrophe, 60 | backtick, 61 | left_shift, 62 | backslash, 63 | z, 64 | x, 65 | c, 66 | v, 67 | b, 68 | n, 69 | m, 70 | comma, 71 | period, 72 | slash, 73 | right_shift, 74 | keypad_star, 75 | left_alt, 76 | space, 77 | caps, 78 | f1, 79 | f2, 80 | f3, 81 | f4, 82 | f5, 83 | f6, 84 | f7, 85 | f8, 86 | f9, 87 | f10, 88 | number_lock, 89 | scrl_lock, 90 | keypad_seven, 91 | keypad_eight, 92 | keypad_nine, 93 | keypad_dash, 94 | keypad_four, 95 | keypad_five, 96 | keypad_six, 97 | keypad_plus, 98 | keypad_one, 99 | keypad_two, 100 | keypad_three, 101 | keypad_zero, 102 | keypad_period 103 | }; -------------------------------------------------------------------------------- /kernel/src/userspace/entry/uentry.asm: -------------------------------------------------------------------------------- 1 | extern request_page 2 | extern donate_to_userspace 3 | extern setup_syscalls 4 | extern userspace_debug_catch 5 | extern umain 6 | 7 | default rel 8 | 9 | enter_userspace: 10 | 11 | push rbp 12 | mov rbp, rsp 13 | 14 | lea r14, [rel request_page] 15 | call r14 16 | mov rbx, rax 17 | add rbx, 0x1000 18 | mov rdi, rax 19 | lea r14, [rel donate_to_userspace] 20 | call r14 21 | 22 | lea r14, [rel setup_syscalls] 23 | call r14 24 | 25 | mov rax, 0x1B ; Selector 0x18 (User Data) + RPL 3 26 | mov ds, ax 27 | mov es, ax 28 | 29 | pop rbp 30 | 31 | push rax ; Selector 0x18 (User Data) + RPL 3 32 | push rbx ; User space stack 33 | push 0x202 ; rflags = interrupt enable + reserved bit 34 | push 0x23 ; Selector 0x20 (User Code) + RPL 3 35 | lea r14, [rel uentry] 36 | push r14 ; Entry point in user space 37 | 38 | iretq 39 | global enter_userspace:function ($ - enter_userspace) 40 | 41 | section .userspace 42 | uentry: 43 | xor rbp, rbp 44 | push rbp 45 | mov rbp, rsp 46 | 47 | lea r14, [rel umain] 48 | call umain 49 | 50 | jmp $ 51 | global uentry:function ($ - uentry) -------------------------------------------------------------------------------- /kernel/src/userspace/entry/umain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "keyboard.h" 3 | #include "ecpuid.h" 4 | 5 | // TEMPORARY: These syscalls only exist for v0.6, and will be changed many times before v1.0 6 | enum syscall { 7 | copy_framebuffer, 8 | allocate_page, 9 | write_tty, 10 | subscribe_kbd_event, 11 | get_info 12 | }; 13 | 14 | enum info_field { 15 | total_ram, 16 | free_ram 17 | }; 18 | 19 | __attribute__((section(".rodata.userspace"))) 20 | const char itoa_characters[] = "0123456789abcdef"; 21 | 22 | __attribute__((section(".data.userspace"))) 23 | char itoa_buf[64] = { 0 }; 24 | 25 | __attribute__((section(".userspace"))) 26 | char* itoa(long int val, int base) 27 | { 28 | int i = 60; 29 | 30 | for(; val && i ; --i, val /= base) 31 | 32 | itoa_buf[i] = itoa_characters[val % base]; 33 | 34 | return &itoa_buf[i+1]; 35 | } 36 | 37 | __attribute__((section(".userspace"))) 38 | bool $strcmp(const char* lhs, const char *rhs) 39 | { 40 | const char* slhs = lhs; 41 | 42 | for (; *lhs; lhs++) 43 | { 44 | if (*lhs != *rhs) 45 | return false; 46 | 47 | rhs++; 48 | } 49 | 50 | if (!*slhs) return false; 51 | 52 | return true; 53 | } 54 | 55 | __attribute__((section(".userspace"))) 56 | void $print(const char * text) 57 | { 58 | asm volatile ("syscall" : : "a" (write_tty)); 59 | } 60 | 61 | __attribute__((section(".userspace"))) 62 | uint64_t $get_info(uint8_t field) 63 | { 64 | uint64_t rax; 65 | asm volatile ("syscall" : "=a" (rax) : "a" (get_info)); 66 | return rax; 67 | } 68 | 69 | __attribute__((section(".userspace"))) 70 | void $subscribe_keyboard_event(void (*handler)(keyboard_event_args)) 71 | { 72 | asm volatile ("syscall" : : "a" (subscribe_kbd_event)); 73 | } 74 | 75 | __attribute__((section(".data.userspace"))) 76 | int command_buffer_index = 0; 77 | __attribute__((section(".data.userspace"))) 78 | char* $command_buffer; 79 | __attribute__((section(".data.userspace"))) 80 | bool prompt_waiting = false; 81 | __attribute__((section(".data.userspace"))) 82 | bool event_occured = false; 83 | __attribute__((section(".data.userspace"))) 84 | bool unhandled_backspace = false; 85 | 86 | __attribute__((section(".userspace"))) 87 | void* $allocate_page() 88 | { 89 | uint64_t rax = 0; 90 | asm volatile ("syscall" : "=a" (rax) : "a" (allocate_page)); 91 | return (void *)rax; 92 | } 93 | 94 | __attribute__((section(".userspace"))) 95 | void* $memset(void* buffer, unsigned char value, unsigned long count) 96 | { 97 | unsigned char* cbuffer = (unsigned char *)buffer; 98 | for (unsigned long i = 0; i < count; i++) 99 | cbuffer[i] = value; 100 | return buffer; 101 | } 102 | 103 | __attribute__((section(".userspace"))) 104 | void keyboard_event(keyboard_event_args event_args) 105 | { 106 | if (!event_args.release_or_press) 107 | return; 108 | 109 | char character = kcascii(event_args.key_code, event_args.shifted, event_args.caps_lock); 110 | 111 | if (character == '\t') 112 | { 113 | command_buffer_index = (command_buffer_index / 4 + 1) * 4; 114 | return; 115 | } 116 | 117 | if (character == '\b') 118 | { 119 | command_buffer_index--; 120 | $command_buffer[command_buffer_index] = 0; 121 | unhandled_backspace = true; 122 | return; 123 | } 124 | 125 | if (character == '\n') 126 | { 127 | prompt_waiting = false; 128 | return; 129 | } 130 | 131 | if (!character) 132 | return; 133 | 134 | $command_buffer[command_buffer_index] = character; 135 | command_buffer_index++; 136 | 137 | event_occured = true; 138 | 139 | return; 140 | } 141 | 142 | void $perform_command(char* command); 143 | 144 | __attribute__((section(".userspace"))) 145 | void $prompt() 146 | { 147 | $print("$RED!> $LIGHT_BLUE!imnus-cmd $RED!>> "); 148 | prompt_waiting = true; 149 | while (prompt_waiting) 150 | { 151 | if (event_occured) 152 | { 153 | $print(&($command_buffer[command_buffer_index - 1])); 154 | event_occured = false; 155 | } 156 | 157 | if (unhandled_backspace) 158 | { 159 | $print("\b"); 160 | unhandled_backspace = false; 161 | } 162 | } 163 | 164 | $print("\n"); 165 | 166 | $perform_command($command_buffer); 167 | 168 | $memset((void *)$command_buffer, 0, 0x1000); 169 | command_buffer_index = 0; 170 | } 171 | 172 | extern "C" 173 | __attribute__((section(".userspace"))) 174 | void umain() 175 | { 176 | $print("\n\t$CYAN!imnus v1.0$WHITE!\n\n"); 177 | 178 | $subscribe_keyboard_event(keyboard_event); 179 | 180 | $command_buffer = (char *)$allocate_page(); 181 | $memset((void *)$command_buffer, 0, 0x1000); 182 | 183 | while (true) 184 | $prompt(); 185 | } 186 | 187 | __attribute__((section(".rodata.userspace"))) 188 | const char $meminfo[] = "meminfo"; 189 | 190 | __attribute__((section(".rodata.userspace"))) 191 | const char $cpuinfo[] = "cpuinfo"; 192 | 193 | __attribute__((section(".rodata.userspace"))) 194 | const char $help[] = "help"; 195 | 196 | __attribute__((section(".userspace"))) 197 | void $$meminfo() 198 | { 199 | uint64_t total_ram, free_ram, used_ram; 200 | 201 | total_ram = $get_info(info_field::total_ram); 202 | free_ram = $get_info(info_field::free_ram); 203 | used_ram = total_ram - free_ram; 204 | 205 | $print("\n\t$LIGHT_GREY!total ram: "); 206 | $print(itoa(total_ram / 1024 / 1024, 10)); 207 | $print("M\n\t$LIGHT_GREY!free ram: "); 208 | $print(itoa(free_ram / 1024 / 1024, 10)); 209 | $print("M\n\t$LIGHT_GREY!used ram: "); 210 | $print(itoa(used_ram / 1024 / 1024, 10)); 211 | $print("M\n\n"); 212 | } 213 | 214 | __attribute__((section(".userspace"))) 215 | void $$cpu_info() 216 | { 217 | $print("\n\tsupports x64: $GREEN!yes\n"); 218 | $print("\tsupports acpi: $GREEN!yes\n"); 219 | $print("\tsupports apic: "); 220 | $print(cpuid_get_field(ECX, CPUID_FEAT_EDX_APIC) ? "$GREEN!yes\n" : "$RED!no\n"); 221 | $print("\tsupports pae: $GREEN!yes\n"); 222 | $print("\tsupports mmx: $GREEN!yes\n"); 223 | $print("\tsupports sse: $GREEN!yes\n"); 224 | $print("\tsupports sse2: $GREEN!yes\n"); 225 | $print("\tsupports sse3: "); 226 | $print(cpuid_get_field(ECX, CPUID_FEAT_ECX_SSE3) ? "$GREEN!yes\n" : "$RED!no\n"); 227 | $print("\tsupports ssse3: "); 228 | $print(cpuid_get_field(ECX, CPUID_FEAT_ECX_SSSE3) ? "$GREEN!yes\n" : "$RED!no\n"); 229 | $print("\tsupports sse4.1: "); 230 | $print(cpuid_get_field(ECX, CPUID_FEAT_ECX_SSE4_1) ? "$GREEN!yes\n" : "$RED!no\n"); 231 | $print("\tsupports sse4.2: "); 232 | $print(cpuid_get_field(ECX, CPUID_FEAT_ECX_SSE4_2) ? "$GREEN!yes\n" : "$RED!no\n"); 233 | $print("\tsupports avx: "); 234 | $print(cpuid_get_field(ECX, CPUID_FEAT_ECX_AVX) ? "$GREEN!yes\n\n" : "$RED!no\n\n"); 235 | } 236 | 237 | __attribute__((section(".userspace"))) 238 | void $$help() 239 | { 240 | $print("\n\tmeminfo: $LIGHT_GREEN!get info about memory\n"); 241 | $print("\tcpuinfo: $LIGHT_GREEN!get info about the cpu\n"); 242 | $print("\thelp: $LIGHT_GREEN!display this current menu\n\n"); 243 | } 244 | 245 | __attribute__((section(".userspace"))) 246 | void $perform_command(char* command) 247 | { 248 | if ($strcmp(command, $cpuinfo)) 249 | { 250 | $$cpu_info(); 251 | return; 252 | } 253 | 254 | if ($strcmp(command, $meminfo)) 255 | { 256 | $$meminfo(); 257 | return; 258 | } 259 | 260 | if ($strcmp(command, $help)) 261 | { 262 | $$help(); 263 | return; 264 | } 265 | 266 | if (!*$command_buffer) return; 267 | 268 | $print("$RED!error: $WHITE!unknown command\n"); 269 | } -------------------------------------------------------------------------------- /kernel/src/userspace/syscalls.asm: -------------------------------------------------------------------------------- 1 | extern tss_get 2 | 3 | extern sys_keyboard_event_subscribe 4 | extern sys_copy_framebuffer 5 | extern sys_tty_print 6 | extern sys_allocate_page 7 | extern sys_get_info 8 | 9 | default rel 10 | 11 | tss_rsp0: 12 | dq 0 13 | 14 | setup_syscalls: 15 | push rbp 16 | mov rbp, rsp 17 | 18 | lea rax, [rel syscall_handler] 19 | mov r8, rax 20 | shr r8, 0x20 21 | mov rdx, r8 22 | 23 | ; Truncate to 32-bits 24 | mov eax, eax 25 | mov edx, edx 26 | 27 | ; Load handler RIP into LSTAR MSR 28 | mov rcx, 0xc0000082 29 | wrmsr 30 | 31 | ; Enable syscall / sysret instruction 32 | mov rcx, 0xc0000080 33 | rdmsr 34 | or eax, 1 35 | wrmsr 36 | mov rcx, 0xc0000081 37 | rdmsr 38 | mov edx, 0x00100008 39 | wrmsr 40 | 41 | mov rdi, 0 42 | lea r10, [rel tss_get] 43 | call r10 44 | lea r11, [rel tss_rsp0] 45 | mov r10, [rax + 4] 46 | mov [r11], r10 47 | 48 | pop rbp 49 | ret 50 | global setup_syscalls:function ($ - setup_syscalls) 51 | 52 | syscall_handler: 53 | cli 54 | 55 | push rbp 56 | mov rbp, rsp 57 | 58 | mov r11, rsp 59 | lea r10, [rel tss_rsp0] 60 | mov rsp, [r10] 61 | push r11 62 | 63 | push rcx 64 | 65 | lea r10, [rel syscall_table] 66 | lea rax, [r10 + rax * 8] 67 | call [rax] 68 | 69 | pop rcx 70 | pop rsp 71 | pop rbp 72 | o64 sysret 73 | global syscall_handler:function ($ - syscall_handler) 74 | 75 | syscall_table: 76 | dq sys_copy_framebuffer 77 | dq sys_allocate_page 78 | dq sys_tty_print 79 | dq sys_keyboard_event_subscribe 80 | dq sys_get_info -------------------------------------------------------------------------------- /kernel/src/userspace/syscalls.cpp: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "drivers/io.h" 3 | #include "drivers/kbd/kbd.h" 4 | #include "memory/pmm.h" 5 | #include "memory/paging.h" 6 | #include "memory/operations.h" 7 | #include "drivers/gfx/gop/gop.h" 8 | #include "drivers/tty/tty.h" 9 | 10 | extern "C" void sys_keyboard_event_subscribe(void (*handler)(io::keyboard::keyboard_packet)) 11 | { 12 | io::keyboard::keyboard_event_subscribe(handler); 13 | } 14 | 15 | extern "C" void sys_copy_framebuffer(uint32* buffer) 16 | { 17 | memory::operations::memcpy ( 18 | 19 | (void *)gfx::gop.framebuffer_addr, 20 | 21 | buffer, 22 | 23 | gfx::gop.framebuffer_pitch 24 | * gfx::gop.framebuffer_width 25 | * gfx::gop.framebuffer_height 26 | 27 | ); 28 | } 29 | 30 | enum sys_info_field { 31 | total_ram, 32 | free_ram 33 | }; 34 | 35 | extern "C" uint64 sys_get_info(uint08 field) 36 | { 37 | switch (field) 38 | { 39 | case total_ram: 40 | return memory::pmm::total_memory_size; 41 | case free_ram: 42 | return memory::pmm::free_memory_size; 43 | default: 44 | return 0; 45 | } 46 | } 47 | 48 | extern "C" void sys_tty_print(char* text) 49 | { 50 | io::tty::write(text); 51 | } 52 | 53 | extern "C" void* sys_allocate_page() 54 | { 55 | void* page = memory::pmm::request_page(); 56 | memory::paging::donate_to_userspace(page); 57 | return page; 58 | } -------------------------------------------------------------------------------- /kernel/src/util/bitmap.cpp: -------------------------------------------------------------------------------- 1 | #include "util/bitmap.h" 2 | 3 | bool util::bitmap::operator[](uint64 index) { 4 | return get(index); 5 | } 6 | 7 | bool util::bitmap::get(uint64 index) { 8 | 9 | uint byte_index = index / 8; 10 | uint08 bit_index = index % 8; 11 | uint08 bit_indexer = 0b10000000 >> bit_index; 12 | 13 | return (buffer[byte_index] & bit_indexer); 14 | } 15 | 16 | void util::bitmap::set(uint64 index, bool value) { 17 | 18 | uint64 byte_index = index / 8; 19 | uint08 bit_index = index % 8; 20 | uint08 bit_indexer = 0b10000000 >> bit_index; 21 | buffer[byte_index] &= ~bit_indexer; 22 | 23 | if (value) 24 | buffer[byte_index] |= bit_indexer; 25 | } -------------------------------------------------------------------------------- /kernel/src/util/bitmap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.h" 3 | 4 | namespace util { 5 | class bitmap { 6 | public: 7 | uint size; 8 | byte* buffer; 9 | bool operator[](uint64 index); 10 | bool get(uint64 index); 11 | void set(uint64 index, bool value); 12 | }; 13 | } -------------------------------------------------------------------------------- /kernel/src/util/guid.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.h" 3 | 4 | typedef struct { 5 | uint64 data1; 6 | uint16 data2; 7 | uint16 data3; 8 | uint08 data4[8]; 9 | } guid; -------------------------------------------------------------------------------- /kernel/src/util/kutil.cpp: -------------------------------------------------------------------------------- 1 | #include "util/kutil.h" 2 | #include "drivers/tty/tty.h" 3 | #include "drivers/io.h" 4 | 5 | char* util::itoa(long int val, int base) 6 | { 7 | static char buf[64] = {0}; 8 | 9 | sint i = 60; 10 | 11 | for(; val && i ; --i, val /= base) 12 | 13 | buf[i] = "0123456789abcdef"[val % base]; 14 | 15 | return &buf[i+1]; 16 | } 17 | 18 | 19 | bool util::strcomp(const char* lhs, const char *rhs) 20 | { 21 | for (; *lhs; lhs++) 22 | { 23 | if (*lhs != *rhs) 24 | return false; 25 | 26 | rhs++; 27 | } 28 | return true; 29 | } 30 | 31 | uint util::strlen(const char* str) 32 | { 33 | uint len = 0; 34 | while (str[len] && str[len] != '\0') 35 | len++; 36 | return len; 37 | } 38 | 39 | char* util::strcat(char *dest, const char *src) { 40 | 41 | char * end = dest; 42 | while (*end != '\0') { 43 | ++end; 44 | } 45 | while (*src) { 46 | *end = *src; 47 | end++; 48 | src++; 49 | } 50 | *end = '\0'; 51 | return dest; 52 | } 53 | 54 | char* util::strcpy(char * __restrict dst, const char * __restrict src) { 55 | 56 | char * out = dst; 57 | for (; (*dst=*src); src++, dst++); 58 | return out; 59 | } 60 | 61 | int util::isdigit(char c) { 62 | 63 | return (c >= '0' && c <= '9'); 64 | } -------------------------------------------------------------------------------- /kernel/src/util/kutil.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.h" 3 | 4 | namespace util 5 | { 6 | char* itoa(long int val, int base); 7 | static inline uint08 get_bit(uint64 source, uint08 bit) 8 | { 9 | return (source >> bit) & 1; 10 | } 11 | uint strlen(const char* str); 12 | bool strcomp(const char* lhs, const char *rhs); 13 | char * strcpy(char * __restrict dst, const char * __restrict src); 14 | char * strcat(char *dest, const char *src); 15 | int isdigit(char c); 16 | } -------------------------------------------------------------------------------- /res/GenerateImage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Remove existing images 4 | rm -rf img 5 | 6 | # Make the directories 7 | mkdir -p img 8 | mkdir -p iso 9 | mkdir -p iso/EFI 10 | mkdir -p iso/EFI/BOOT 11 | mkdir -p iso/sys 12 | mkdir -p iso/sys/core 13 | mkdir -p iso/sys/res 14 | 15 | # Copy the bootloader/boot config 16 | cp res/limine.efi iso/EFI/BOOT/BOOTX64.EFI 17 | cp res/limine.cfg iso/limine.cfg 18 | 19 | # Copy the kernel 20 | cp bin/kernel/mnk.elf iso/sys/core/mnk.elf 21 | 22 | # Generate the FAT image 23 | res/dir2fat32.sh img/microNET.fat 260 iso 24 | 25 | # Generate the ISO 26 | xorriso -as mkisofs -R -f -no-emul-boot -o stdio:img/microNET.iso iso 27 | 28 | # Clean up 29 | rm -rf iso -------------------------------------------------------------------------------- /res/OVMF.fd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austanss/micron/8bf10e0290cec6d2ef6ed50c79e0dc58b8e67ae2/res/OVMF.fd -------------------------------------------------------------------------------- /res/dir2fat32.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create a FAT32 disk image from the contents of a directory. 4 | # 5 | # This tool requires the following to be available on the host system: 6 | # 7 | # - util-linux 8 | # - dosfstools 9 | # - mtools 10 | # 11 | # Copyright 2016 Othernet Inc 12 | # Some rights reserved. 13 | # 14 | # This program is free software: you can redistribute it and/or modify it under 15 | # the terms of the GNU General Public License as published by the Free Software 16 | # Foundation, either version 3 of the License, or (at your option) any later 17 | # version. 18 | # 19 | # This program is distributed in the hope that it will be useful, but WITHOUT 20 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 21 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 22 | # details. 23 | # 24 | # You should have received a copy of the GNU General Public License along with 25 | # this program. If not, see 26 | # 27 | 28 | set -e 29 | 30 | VERSION=2.0 31 | 32 | usage() { 33 | echo "Usage: $(basename $0) [-h -f] OUTPUT SIZE SOURCE" 34 | echo 35 | echo "Arguments:" 36 | echo " OUTPUT name of the image file" 37 | echo " SIZE size of the FAT32 partition in MiB (1024 based)" 38 | echo " SOURCE source directory" 39 | echo 40 | echo "Options:" 41 | echo " -f overwrite existing image file (if any)" 42 | echo " -h show this message and exit" 43 | echo 44 | echo "NOTE: the image size is always 8 MiB larger than the partition size" 45 | echo "to account for the partition offset. The partition size itself should" 46 | echo "ideally be a multiple of 8 MiB." 47 | echo 48 | echo "dir2fat32 v$VERSION" 49 | echo "Copyright 2016 Othernet Inc" 50 | echo "Some rights reserved." 51 | echo 52 | echo "This program is free software released under GNU GPLv3 license." 53 | echo "See for more information." 54 | echo 55 | } 56 | 57 | relpath() { 58 | full=$1 59 | if [ "$full" == "$SOURCE" ]; then 60 | echo "" 61 | else 62 | base=${SOURCE%%/}/ 63 | echo "${full##$base}" 64 | fi 65 | } 66 | 67 | mkcontainer() { 68 | dd if=/dev/zero bs=512 count=0 seek=$(expr 2048 + ${SIZE} '*' 2048 + 33) "of=$OUTPUT" 69 | parted -s "$OUTPUT" mklabel gpt 70 | parted -s "$OUTPUT" mkpart primary 2048s $(expr 2048 + ${SIZE} '*' 2048 - 1)s 71 | } 72 | 73 | mkpartition() { 74 | dd if=/dev/zero bs=512 count=0 seek=$(expr ${SIZE} '*' 2048) of="$PARTITION" 75 | mkfs.fat -F32 "$PARTITION" >/dev/null 76 | } 77 | 78 | copyfiles() { 79 | find "$SOURCE" -type d | while read dir; do 80 | target=$(relpath "$dir") 81 | [ -z "$target" ] && continue 82 | echo " Creating $target" 83 | mmd -i "$PARTITION" "::$target" 84 | done 85 | find $SOURCE -type f | while read file; do 86 | target=$(relpath "$file") 87 | echo " Copying $target" 88 | mcopy -i "$PARTITION" "$file" "::$target" 89 | done 90 | } 91 | 92 | insertpart() { 93 | dd if="$PARTITION" of="$OUTPUT" bs=1M seek=1 conv=notrunc 94 | } 95 | 96 | # Parse options 97 | while getopts "hfS:" opt; do 98 | case "$opt" in 99 | h) 100 | usage 101 | exit 0 102 | ;; 103 | f) 104 | FORCE=1 105 | ;; 106 | *) 107 | echo "Unrecognized option $opt" 108 | exit 109 | esac 110 | done 111 | 112 | # Parse remaining positional arguments 113 | OUTPUT=${@:$OPTIND:1} 114 | SIZE=${@:$OPTIND+1:1} 115 | SOURCE=${@:$OPTIND+2:1} 116 | 117 | if [ -z "$OUTPUT" ] || [ -z "$SIZE" ] || [ -z "$SOURCE" ]; then 118 | echo "ERROR: Missing required arguments, please see usage instructions" 119 | usage 120 | exit 0 121 | fi 122 | 123 | [ $FORCE ] && (rm -f $OUTPUT 2>/dev/null || true) 124 | 125 | if [ -e "$OUTPUT" ]; then 126 | echo "ERROR: $OUTPUT already exists. Aborting." 127 | exit 1 128 | fi 129 | 130 | PARTITION=${OUTPUT}.partition 131 | 132 | echo "==============================================" 133 | echo "Output file: $OUTPUT" 134 | echo "Partition size: $SIZE MiB" 135 | echo "Source dir: $SOURCE" 136 | echo "==============================================" 137 | echo "===> Creating container image" 138 | mkcontainer 139 | echo "===> Creating FAT32 partition image" 140 | mkpartition 141 | echo "===> Copying files" 142 | copyfiles 143 | echo "===> Copying partition into container" 144 | insertpart 145 | echo "===> Removing partition image file" 146 | rm -f "$PARTITION" 147 | echo "===> DONE" 148 | 149 | -------------------------------------------------------------------------------- /res/limine.cfg: -------------------------------------------------------------------------------- 1 | # Timeout in seconds that Limine will use before automatically booting. 2 | TIMEOUT=0 3 | 4 | :microNET v0.6 "Glassi" 5 | PROTOCOL=stivale 6 | 7 | KERNEL_PATH=boot:///sys/core/mnk.elf 8 | KASLR=y -------------------------------------------------------------------------------- /res/limine.efi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/austanss/micron/8bf10e0290cec6d2ef6ed50c79e0dc58b8e67ae2/res/limine.efi --------------------------------------------------------------------------------