├── .github └── workflows │ ├── documentation.yml │ └── release.yml ├── .gitignore ├── LICENSE ├── Makefile ├── resources ├── fe │ ├── push.fe │ └── reverse.fe ├── foxos.bmp ├── screen_of_death.bmp └── zap-light16.psf └── src ├── Makefile ├── apic ├── apic.cpp ├── madt.cpp ├── stivale2_bootstrap.asm └── trampoline.asm ├── assert.cpp ├── binfile.asm ├── bitmap.cpp ├── cmdline.cpp ├── config.cpp ├── cstr.cpp ├── disassembler.cpp ├── driver ├── cmos.cpp ├── disk │ ├── ahci │ │ ├── ahci.cpp │ │ └── ahci_port.cpp │ ├── ata.cpp │ ├── disk.cpp │ └── virtual_disk.cpp ├── driver.cpp ├── keyboard.cpp ├── mouse.cpp ├── nic │ ├── am79C973.cpp │ ├── e1000.cpp │ └── nic.cpp ├── pc_speaker.cpp └── serial.cpp ├── efi_mem.cpp ├── entry.asm ├── examples ├── disk.cpp ├── examples.h ├── fat32.cpp ├── fat32_old.cpp ├── layer.cpp ├── net.cpp ├── patch.cpp ├── scheduler.cpp ├── sound.cpp ├── syscall.cpp └── vfs.cpp ├── fs ├── fat32 │ ├── diskio.cpp │ ├── fat32_old.cpp │ ├── ff.cpp │ ├── ffsystem.cpp │ ├── ffunicode.cpp │ └── vfs.cpp ├── fd.cpp ├── gpt │ └── gpt.cpp ├── stivale │ └── vfs.cpp └── vfs │ ├── list.cpp │ └── vfs.cpp ├── gdt.cpp ├── include ├── apic │ ├── apic.h │ └── madt.h ├── assert.h ├── bitmap.h ├── bootinfo.h ├── cmdline.h ├── config.h ├── cstr.h ├── disassembler.h ├── driver │ ├── cmos.h │ ├── disk │ │ ├── ahci │ │ │ └── ahci.h │ │ ├── ata.h │ │ ├── disk.h │ │ └── virtual_disk.h │ ├── driver.h │ ├── keyboard.h │ ├── mouse.h │ ├── nic │ │ ├── am79C973.h │ │ ├── e1000.h │ │ └── nic.h │ ├── pc_speaker.h │ └── serial.h ├── efi_mem.h ├── fs │ ├── fat32 │ │ ├── diskio.h │ │ ├── fat32_old.h │ │ ├── ff.h │ │ ├── ffconf.h │ │ └── vfs.h │ ├── fd.h │ ├── gpt │ │ └── gpt.h │ ├── stivale │ │ └── vfs.h │ └── vfs │ │ ├── list.h │ │ └── vfs.h ├── gdt.h ├── init │ └── init_procces.h ├── interrupts │ ├── idt.h │ ├── interrupt_handler.h │ ├── interrupts.h │ └── panic.h ├── kernel_info.h ├── kmod.h ├── memory │ ├── heap.h │ └── memory.h ├── mmio.h ├── net │ ├── arp.h │ ├── dhcp.h │ ├── dns.h │ ├── etherframe.h │ ├── icmp.h │ ├── ipv4.h │ ├── listv2.h │ ├── net_stack.h │ ├── tcp.h │ └── udp.h ├── paging │ ├── page_frame_allocator.h │ ├── page_map_indexer.h │ ├── page_table_manager.h │ └── paging.h ├── pci │ ├── acpi.h │ ├── pci.h │ └── pci_bar.h ├── port.h ├── power.h ├── renderer │ ├── font.h │ ├── font_renderer.h │ ├── framebuffer.h │ ├── layer_renderer.h │ ├── mouse_renderer.h │ ├── point.h │ └── renderer2D.h ├── scheduling │ ├── hpet │ │ └── hpet.h │ ├── pit │ │ └── pit.h │ └── scheduler │ │ ├── atomic.h │ │ ├── elf.h │ │ ├── errno.h │ │ ├── queue.h │ │ ├── scheduler.h │ │ └── signal.h ├── shell │ └── shell.h ├── stdarg.h ├── stdio.h ├── stivale.h ├── stivale2.h ├── string.h └── util.h ├── init └── init_procces.cpp ├── interrupts ├── idt.cpp ├── interrupt_handler.cpp ├── interrupts.cpp ├── interrupts_stub.asm ├── panic.cpp ├── syscall.asm └── syscalls │ ├── close.cpp │ ├── env.cpp │ ├── memory.cpp │ ├── open.cpp │ ├── read.cpp │ ├── resolve_symbol.cpp │ ├── seek_get.cpp │ ├── seek_set.cpp │ ├── spawn.cpp │ └── write.cpp ├── kmod.cpp ├── link.ld ├── list.py ├── load_gdt.asm ├── main.cpp ├── memory ├── fast_mem.asm ├── heap.cpp └── memory.cpp ├── mmio.cpp ├── net ├── arp.cpp ├── dhcp.cpp ├── dns.cpp ├── etherframe.cpp ├── icmp.cpp ├── ipv4.cpp ├── tcp.cpp └── udp.cpp ├── paging ├── page_frame_allocator.cpp ├── page_map_indexer.cpp ├── page_table_manager.cpp └── paging.cpp ├── pci ├── acpi.cpp ├── pci.cpp ├── pci_bar.cpp └── pci_descriptors.cpp ├── port.cpp ├── power.cpp ├── renderer ├── font_renderer.cpp ├── layer_copy.asm ├── layer_renderer.cpp ├── mouse_renderer.cpp ├── redirect_serial_to_screen.asm └── renderer2D.cpp ├── scheduling ├── hpet │ └── hpet.cpp ├── pit │ └── pit.cpp └── scheduler │ ├── atomic.asm │ ├── elf.cpp │ ├── errno.cpp │ ├── fxsr.asm │ ├── queue.cpp │ ├── scheduler.cpp │ ├── signal.cpp │ ├── task_entry.asm │ └── xsave.asm ├── shell └── shell.cpp ├── stivale2.cpp ├── string.cpp └── util.cpp /.github/workflows/documentation.yml: -------------------------------------------------------------------------------- 1 | name: Build the kernel documentation and deploy it to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: [ main, docs ] 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build-docs: 10 | runs-on: [self-hosted, Linux, X64] 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | with: 15 | submodules: recursive 16 | - name: Build the kernel documentation 17 | run: | 18 | rm -rvf doc 19 | make -C src doc WEBPATH=/FoxOS-kernel 20 | 21 | - name: Deploy 22 | uses: peaceiris/actions-gh-pages@v3 23 | with: 24 | github_token: ${{ secrets.GITHUB_TOKEN }} 25 | publish_dir: ./doc/ 26 | 27 | - name: Send request to server 28 | run: curl -X POST -F 'secret=${{ secrets.PHP_UPDATE_SECRET }}' -F 'updatedocs=true' https://theultimatefoxos.dev/kerneldoc-update.php 29 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release the kernel headers as a zip file 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build-headers: 10 | runs-on: [self-hosted, Linux, X64] 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | with: 15 | submodules: recursive 16 | - name: Build the kernel headers 17 | run: | 18 | zip -r kernel-headers.zip src/include/. 19 | 20 | - uses: marvinpinto/action-automatic-releases@latest 21 | with: 22 | repo_token: ${{ secrets.GITHUB_TOKEN }} 23 | automatic_release_tag: "latest" 24 | prerelease: true 25 | title: "Kernel headers" 26 | files: | 27 | kernel-headers.zip 28 | 29 | - name: Delete the zip file 30 | run: | 31 | rm kernel-headers.zip 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /lib/ 3 | 4 | #Mac files 5 | ._* 6 | .DS_Store 7 | ._DS_Strore 8 | 9 | #toolchain build dir 10 | .toolchain 11 | 12 | #documentation build dir 13 | /doc/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 TheUltimateFoxOS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | OBJDIR = lib 2 | BUILDDIR = bin 3 | 4 | build: 5 | make -C src 6 | 7 | setup: 8 | @mkdir $(BUILDDIR) 9 | @mkdir $(OBJDIR) 10 | 11 | clean: 12 | @rm -r $(BUILDDIR) 13 | @rm -r $(OBJDIR) 14 | @mkdir $(BUILDDIR) 15 | @mkdir $(OBJDIR) 16 | 17 | .PHONY: build -------------------------------------------------------------------------------- /resources/fe/push.fe: -------------------------------------------------------------------------------- 1 | (= push (mac (val lst) 2 | (list '= lst (list 'cons val lst)) 3 | )) 4 | 5 | 6 | (= for (mac (item lst . body) 7 | (list 'do 8 | (list 'let 'for-iter lst) 9 | (list 'while 'for-iter 10 | (list 'let item '(car for-iter)) 11 | '(= for-iter (cdr for-iter)) 12 | (cons 'do body) 13 | ) 14 | ) 15 | )) 16 | 17 | 18 | (= items (list "cat" "dog" "fox")) 19 | 20 | (push "owl" items) 21 | (push "cow" items) 22 | 23 | (for x items 24 | (print ">" x) 25 | ) -------------------------------------------------------------------------------- /resources/fe/reverse.fe: -------------------------------------------------------------------------------- 1 | (= reverse (fn (lst) 2 | (let res nil) 3 | (while lst 4 | (= res (cons (car lst) res)) 5 | (= lst (cdr lst)) 6 | ) 7 | res 8 | )) 9 | 10 | (= animals '("cat" "dog" "fox")) 11 | 12 | (print (reverse animals)) -------------------------------------------------------------------------------- /resources/foxos.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheUltimateFoxOS/FoxOS-kernel/0a24a0414fad78155cc43ffef620fe07a89c6c05/resources/foxos.bmp -------------------------------------------------------------------------------- /resources/screen_of_death.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheUltimateFoxOS/FoxOS-kernel/0a24a0414fad78155cc43ffef620fe07a89c6c05/resources/screen_of_death.bmp -------------------------------------------------------------------------------- /resources/zap-light16.psf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheUltimateFoxOS/FoxOS-kernel/0a24a0414fad78155cc43ffef620fe07a89c6c05/resources/zap-light16.psf -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | OBJDIR = ../lib 2 | BUILDDIR = ../bin 3 | DOCDIR = ../doc 4 | 5 | rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d)) 6 | 7 | CPPSRC = $(call rwildcard,./,*.cpp) 8 | ASMSRC = $(call rwildcard,./,*.asm) 9 | OBJS = $(patsubst %.cpp, $(OBJDIR)/%.o, $(CPPSRC)) 10 | OBJS += $(patsubst %.asm, $(OBJDIR)/%_asm.o, $(ASMSRC)) 11 | 12 | HTML_DOC = $(patsubst %.cpp, $(DOCDIR)/%.html, $(CPPSRC)) 13 | HTML_DOC += $(patsubst %.asm, $(DOCDIR)/%_asm.html, $(ASMSRC)) 14 | 15 | TOOLCHAIN_BASE = /usr/local/foxos-x86_64_elf_gcc 16 | 17 | ifeq (,$(wildcard $(TOOLCHAIN_BASE)/bin/foxos-gcc)) 18 | CC = gcc 19 | else 20 | CC = $(TOOLCHAIN_BASE)/bin/foxos-gcc 21 | endif 22 | 23 | ifeq (,$(wildcard $(TOOLCHAIN_BASE)/bin/foxos-nasm)) 24 | ASM = nasm 25 | else 26 | ASM = $(TOOLCHAIN_BASE)/bin/foxos-nasm 27 | endif 28 | 29 | ifeq (,$(wildcard $(TOOLCHAIN_BASE)/bin/foxos-gcc)) 30 | LD = ld 31 | else 32 | LD = $(TOOLCHAIN_BASE)/bin/foxos-ld 33 | endif 34 | 35 | 36 | CFLAGS = -ffreestanding -fshort-wchar -mno-red-zone -Iinclude -fno-use-cxa-atexit -fno-rtti -fno-exceptions -fno-leading-underscore -fno-exceptions -fno-stack-protector -mno-sse -mno-sse2 -mno-3dnow -mno-80387 -g 37 | ASMFLAGS = -f elf64 38 | LDFLAGS = -static -Bsymbolic -nostdlib -Tlink.ld --no-dynamic-linker -zmax-page-size=0x1000 -ztext 39 | 40 | foxkrnl.elf: $(OBJS) 41 | @echo LD $^ 42 | @$(LD) $(LDFLAGS) -o $(BUILDDIR)/$@ $^ 43 | 44 | @echo "\n\nCompiled using asm: $(ASM), cc: $(CC), ld: $(LD)\n\n" 45 | 46 | $(OBJDIR)/%.o: %.cpp 47 | @echo "CPP $^ -> $@" 48 | @mkdir -p $(@D) 49 | @$(CC) $(CFLAGS) -c -o $@ $^ 50 | 51 | $(OBJDIR)/%_asm.o: %.asm 52 | @echo "ASM $^ -> $@" 53 | @mkdir -p $(@D) 54 | @$(ASM) $(ASMFLAGS) -o $@ $^ 55 | 56 | DOC_BUILD_ID = $(shell cat /proc/sys/kernel/random/uuid | sed 's/[-]//g' | head -c 20; echo;) 57 | WEBPATH = "/doc" 58 | 59 | # we need this so that DOC_BUILD_ID is static 60 | doc: 61 | make _doc DOC_BUILD_ID=$(DOC_BUILD_ID) 62 | 63 | _doc: $(HTML_DOC) 64 | @python list.py index $(shell pwd) $(shell pwd)/$(DOCDIR) $(WEBPATH) 65 | 66 | @echo "Generated documentation in $(DOCDIR)" 67 | @echo "Build ID: $(DOC_BUILD_ID)" 68 | 69 | @#echo "Run: \"python list.py summary $(DOC_BUILD_ID)\" to see a sumary of the build!" 70 | @python list.py summary $(DOC_BUILD_ID) 71 | 72 | $(DOCDIR)/%.html: %.cpp 73 | @echo "HTML $^ -> $@" 74 | @mkdir -p $(@D) 75 | @python list.py $^ $@ $(DOC_BUILD_ID) 76 | 77 | 78 | $(DOCDIR)/%_asm.html: %.asm 79 | @echo "HTML $^ -> $@" 80 | @mkdir -p $(@D) 81 | @python list.py $^ $@ $(DOC_BUILD_ID) -------------------------------------------------------------------------------- /src/apic/madt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | uint8_t lapic_ids[256] = {0}; 6 | uint8_t numcore = 0; 7 | uint64_t lapic_ptr = 0; 8 | uint64_t ioapic_ptr = 0; 9 | 10 | //#parse_madt-doc: Used to parse the MADT table. 11 | void parse_madt(uint8_t *ptr) { 12 | uint8_t *ptr2; 13 | uint32_t len; 14 | 15 | lapic_ptr = (uint64_t) (*((uint32_t*) (ptr + 0x24))); 16 | ptr2 = ptr + *((uint32_t*) (ptr + 4)); 17 | 18 | for(ptr += 44; ptr < ptr2; ptr += ptr[1]) { 19 | switch(ptr[0]) { 20 | case 0: // found Processor Local APIC 21 | if(ptr[4] & 1) { 22 | lapic_ids[numcore++] = ptr[3]; 23 | } 24 | break; 25 | 26 | case 1: // found IOAPIC 27 | ioapic_ptr = (uint64_t) *((uint32_t*) (ptr + 4)); 28 | break; 29 | 30 | case 5: // found 64 bit LAPIC 31 | lapic_ptr = *((uint64_t*) (ptr + 4)); 32 | break; 33 | } 34 | } 35 | 36 | driver::global_serial_driver->printf("Found %d cores, IOAPIC 0x%x, LAPIC 0x%x, Processor IDs:", numcore, ioapic_ptr, lapic_ptr); 37 | for(int i = 0; i < numcore; i++) { 38 | driver::global_serial_driver->printf(" %d", lapic_ids[i]); 39 | } 40 | driver::global_serial_driver->printf("\n"); 41 | } -------------------------------------------------------------------------------- /src/apic/stivale2_bootstrap.asm: -------------------------------------------------------------------------------- 1 | [global stivale2_bootstrap] 2 | [global stivale2_data] 3 | [extern start_apic_timer] 4 | [extern load_gdt] 5 | 6 | ;# stivale2_bootstrap-signature: void stivale2_bootstrap(stivale2_struct* bootinfo); 7 | ;# stivale2_bootstrap-doc: The main entry point for aplication processors booted using the stivale2 boot protocol smp tag. 8 | 9 | stivale2_bootstrap: 10 | cli 11 | 12 | xor rax, rax 13 | mov eax, [stivale2_data.pagetable] 14 | mov cr3, rax 15 | 16 | xor rdi, rdi 17 | mov edi, [stivale2_data.gdt] 18 | call load_gdt 19 | 20 | xor rax, rax 21 | mov rax, [stivale2_data.idt] 22 | lidt [rax] 23 | 24 | sti 25 | 26 | ; enable coprocessor (fpu and sse) 27 | mov rax, cr0 28 | and ax, 0xFFFB 29 | or ax, 0x2 30 | mov cr0, rax 31 | 32 | mov rax, cr4 33 | or ax, 3 << 9 34 | mov cr4, rax 35 | 36 | fninit 37 | 38 | mov rax, 1 39 | cpuid 40 | and ecx, 1 << 26 ; check for XSAVE support 41 | test ecx, ecx 42 | je .skip_xsave 43 | 44 | mov rax, cr0 45 | xor rax, 1 << 3 46 | mov cr0, rax 47 | 48 | mov rax, cr4 49 | or eax, 1 << 18 50 | mov cr4, rax 51 | 52 | .skip_xsave: 53 | 54 | mov rbp, rsp ; mark end of stack for stack trace 55 | 56 | ; setup the lapic 57 | ; enable lapic software enabled 58 | mov rax, [stivale2_data.lapic_ptr] 59 | mov ebx, [rax + 0x0f0] 60 | or ebx, 0x1ff 61 | mov [rax + 0x0f0], ebx 62 | 63 | ; calibrate the lapic timer 64 | mov rdi, 1000 65 | call start_apic_timer 66 | 67 | mov [stivale2_data.status], byte 1 68 | 69 | call [stivale2_data.entry] 70 | 71 | jmp $ 72 | 73 | ;# stivale2_data-discard 74 | 75 | stivale2_data: 76 | .status: db 0 77 | .pagetable: dq 0 78 | .idt: dq 0 79 | .gdt: dq 0 80 | .stack_ptr: dq 0 81 | .entry: dq 0 82 | .lapic_ptr: dq 0 83 | 84 | times 4096 - ($ - $$) db 0 -------------------------------------------------------------------------------- /src/apic/trampoline.asm: -------------------------------------------------------------------------------- 1 | [bits 16] 2 | [global ap_trampoline] 3 | [global ap_trampoline_data] 4 | [extern start_apic_timer] 5 | 6 | %define to_target(addr) ((addr - ap_trampoline) + 0x8000) 7 | 8 | ;# ap_trampoline-signature: void ap_trampoline(); 9 | ;# ap_trampoline-doc: The main entry point for the application processor after spinup. 10 | 11 | ap_trampoline: 12 | cli 13 | cld 14 | 15 | mov eax, cr4 16 | or eax, 1 << 5 ; PAE 17 | mov cr4, eax 18 | 19 | mov eax, [to_target(ap_trampoline_data.pagetable)] 20 | mov cr3, eax 21 | 22 | mov ecx, 0xC0000080 ; EFER Model Specific Register 23 | rdmsr 24 | or eax, 1 << 8 25 | wrmsr 26 | 27 | mov eax, cr0 28 | or eax, 0x80000001 ; Paging, Protected Mode 29 | mov cr0, eax 30 | 31 | mov eax, [to_target(ap_trampoline_data.gdt)] 32 | lgdt [eax] 33 | 34 | jmp 0x8:to_target(ap_trampoline_64) 35 | 36 | [bits 64] 37 | 38 | 39 | ;# ap_trampoline_64-signature: void ap_trampoline_64(); 40 | ;# ap_trampoline_64-doc: The 64 bit part of the main entry point for the application processor after spinup. 41 | 42 | ap_trampoline_64: 43 | mov ax, 0x10 44 | mov ds, ax 45 | mov es, ax 46 | mov fs, ax 47 | mov gs, ax 48 | mov ss, ax 49 | 50 | mov rax, [to_target(ap_trampoline_data.stack_ptr)] 51 | mov rsp, rax 52 | 53 | mov rax, [to_target(ap_trampoline_data.idt)] 54 | lidt [rax] 55 | 56 | sti 57 | 58 | ; enable coprocessor (fpu and sse) 59 | mov rax, cr0 60 | and ax, 0xFFFB 61 | or ax, 0x2 62 | mov cr0, rax 63 | 64 | mov rax, cr4 65 | or ax, 3 << 9 66 | mov cr4, rax 67 | 68 | fninit 69 | 70 | mov rax, 1 71 | cpuid 72 | and ecx, 1 << 26 ; check for XSAVE support 73 | test ecx, ecx 74 | 75 | ; why the fuck is here no to_target needed 76 | je .skip_xsave 77 | 78 | mov rax, cr0 79 | xor rax, 1 << 3 80 | mov cr0, rax 81 | 82 | mov rax, cr4 83 | or eax, 1 << 18 84 | mov cr4, rax 85 | 86 | .skip_xsave: 87 | 88 | mov rbp, rsp ; mark end of stack for stack trace 89 | 90 | ; setup the lapic 91 | ; enable lapic software enabled 92 | mov rax, [to_target(ap_trampoline_data.lapic_ptr)] 93 | mov ebx, [rax + 0x0f0] 94 | or ebx, 0x1ff 95 | mov [rax + 0x0f0], ebx 96 | 97 | ; calibrate the lapic timer 98 | mov rdi, 1000 99 | mov rax, start_apic_timer 100 | call rax 101 | 102 | mov [to_target(ap_trampoline_data.status)], byte 1 103 | 104 | call [to_target(ap_trampoline_data.entry)] 105 | 106 | jmp $ 107 | 108 | ;# ap_trampoline_data-discard 109 | 110 | ap_trampoline_data: 111 | .status: db 0 112 | .pagetable: dq 0 113 | .idt: dq 0 114 | .gdt: dq 0 115 | .stack_ptr: dq 0 116 | .entry: dq 0 117 | .lapic_ptr: dq 0 118 | 119 | times 4096 - ($ - $$) db 0 120 | -------------------------------------------------------------------------------- /src/assert.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | //#__assert_fail-doc: Internal function gets called if a assertion witch should panic fails. This function is called by the assert macro. This function causes a kernel panic. 7 | void __assert_fail(const char* __assertion, const char* __file, unsigned int __line) { 8 | char panic_buffer[1024]; 9 | sprintf(panic_buffer, "Assertion failed: \"%s\" in file %s at line %d\n", __assertion, __file, __line); 10 | 11 | interrupts::Panic p = interrupts::Panic(panic_buffer); 12 | p.do_it(NULL); 13 | } 14 | 15 | //#__assert_fail_nopanic-doc: Internal function gets called if a assertion witch should not panic fails. This function is called by the assert macro. 16 | void __assert_fail_nopanic(const char* __assertion, const char* __file, unsigned int __line) { 17 | char panic_buffer[1024]; 18 | sprintf(panic_buffer, "Assertion failed: \"%s\" in file %s at line %d\n", __assertion, __file, __line); 19 | 20 | driver::global_serial_driver->puts(panic_buffer); 21 | } -------------------------------------------------------------------------------- /src/binfile.asm: -------------------------------------------------------------------------------- 1 | %macro inc_bin 2 2 | SECTION .rodata 3 | GLOBAL %1 4 | %1: 5 | incbin %2 6 | db 0 7 | %1_size: dq %1_size - %1 8 | %endmacro 9 | 10 | inc_bin fe_push, "../resources/fe/push.fe" 11 | inc_bin fe_reverse, "../resources/fe/reverse.fe" 12 | 13 | inc_bin default_font, "../resources/zap-light16.psf" 14 | inc_bin logo, "../resources/foxos.bmp" 15 | inc_bin screen_of_death, "../resources/screen_of_death.bmp" 16 | -------------------------------------------------------------------------------- /src/bitmap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //#Bitmap::operator[]-doc: Bitmap operator. 4 | bool Bitmap::operator[](uint64_t index){ 5 | return get(index); 6 | } 7 | 8 | //#Bitmap::get-doc: Get a bit in the bitmap. 9 | bool Bitmap::get(uint64_t index) { 10 | if (index > size * 8) return false; 11 | 12 | uint64_t byteIndex = index / 8; 13 | uint8_t bitIndex = index % 8; 14 | uint8_t bitIndexer = 0b10000000 >> bitIndex; 15 | if ((buffer[byteIndex] & bitIndexer) > 0){ 16 | return true; 17 | } 18 | 19 | return false; 20 | } 21 | 22 | //#Bitmap::set-doc: Set a bit in the bitmap. 23 | bool Bitmap::set(uint64_t index, bool value){ 24 | if (index > size * 8) return false; 25 | 26 | uint64_t byteIndex = index / 8; 27 | uint8_t bitIndex = index % 8; 28 | uint8_t bitIndexer = 0b10000000 >> bitIndex; 29 | buffer[byteIndex] &= ~bitIndexer; 30 | if (value){ 31 | buffer[byteIndex] |= bitIndexer; 32 | } 33 | 34 | return true; 35 | } -------------------------------------------------------------------------------- /src/cmdline.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | //#CmdLineParser::CmdLineParser-doc: Empty constructor. Calles the constructor of list. 6 | CmdLineParser::CmdLineParser() : list(100) { 7 | 8 | } 9 | 10 | //#CmdLineParser::~CmdLineParser-doc: Empty destructor. 11 | CmdLineParser::~CmdLineParser() { 12 | 13 | } 14 | 15 | //#CmdLineParser::add_handler-doc: Registers a handler for a command line option. 16 | void CmdLineParser::add_handler(char* name, cmdline_handler handler) { 17 | this->add_node(name, (void*) handler, 0, 0); 18 | } 19 | 20 | //#find_handler-doc: Helper function to find a handler for a command line argument. 21 | bool find_handler(list_node_t* node, void* d1, void* d2, void* d3, void* d4) { 22 | if(strcmp((char*) node->data1, (char*) d1) == 0) { 23 | return true; 24 | } else { 25 | return false; 26 | } 27 | } 28 | 29 | //#CmdLineParser::parse-doc: Parses the command line and calls the appropriate handler. 30 | void CmdLineParser::parse(char* cmdline) { 31 | char* last_token = cmdline; 32 | 33 | int len = strlen(cmdline); 34 | 35 | if (len == 0) { 36 | return; 37 | } 38 | 39 | for (int i = 0; i < len; i++) { 40 | if (cmdline[i] == ' ') { 41 | cmdline[i] = 0; 42 | 43 | char* starting_asingment = nullptr; 44 | 45 | for (int k = 0; k < strlen(last_token); k++) { 46 | if (last_token[k] == '=') { 47 | last_token[k] = 0; 48 | starting_asingment = &last_token[k + 1]; 49 | break; 50 | } 51 | } 52 | 53 | list_node_t* node = this->find_node(find_handler, last_token, 0, 0, 0); 54 | 55 | if (node == 0) { 56 | renderer::global_font_renderer->printf("%fUnknown command: %s%r\n", 0xffff0000, last_token); 57 | } else { 58 | ((cmdline_handler) node->data2)(starting_asingment); 59 | } 60 | 61 | last_token = &cmdline[i + 1]; 62 | } 63 | } 64 | 65 | char* starting_asingment = nullptr; 66 | 67 | for (int k = 0; k < strlen(last_token); k++) { 68 | if (last_token[k] == '=') { 69 | last_token[k] = 0; 70 | starting_asingment = &last_token[k + 1]; 71 | break; 72 | } 73 | } 74 | 75 | list_node_t* node = this->find_node(find_handler, last_token, 0, 0, 0); 76 | 77 | if (node == 0) { 78 | renderer::global_font_renderer->printf("%fUnknown command: %s%r\n", 0xffff0000, last_token); 79 | } else { 80 | ((cmdline_handler) node->data2)(starting_asingment); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/config.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | bool NO_SMP_SHED = false; 5 | 6 | //#set_no_smp_shed-doc: Configure the kernel to not use SMP threads. 7 | void set_no_smp_shed(char* _) { 8 | NO_SMP_SHED = true; 9 | } 10 | 11 | ElfSymbolResolver* elf_symbol_resolver = nullptr; 12 | 13 | ElfSymbolResolver* resolvers[512]; 14 | int resolver_count = 0; 15 | 16 | void register_symbol_resolver(ElfSymbolResolver* resolver) { 17 | resolvers[resolver_count] = resolver; 18 | resolver_count++; 19 | } 20 | 21 | uint64_t resolve_symbol(char* name) { 22 | uint64_t sym_addr = (uint64_t) elf_symbol_resolver->resolve(name); 23 | if (sym_addr == 0) { 24 | for (int i = 0; i < resolver_count; i++) { 25 | sym_addr = (uint64_t) resolvers[i]->resolve(name); 26 | if (sym_addr != 0) { 27 | break; 28 | } 29 | } 30 | } 31 | 32 | return sym_addr; 33 | } 34 | 35 | //#resolve_symbol-doc: Resolves a symbol from the kernel ELF file. 36 | char* resolve_symbol(uint64_t address) { 37 | char* sym_name = elf_symbol_resolver->resolve((void*) address); 38 | if (strcmp(sym_name, "") == 0) { 39 | for (int i = 0; i < resolver_count; i++) { 40 | sym_name = resolvers[i]->resolve((void*) address); 41 | if (strcmp(sym_name, "") != 0) { 42 | break; 43 | } 44 | } 45 | } 46 | 47 | return sym_name; 48 | } 49 | 50 | //#unwind-doc: Unwind the stack to the previous frames. A callback function is called for each frame. 51 | void unwind(int max, uint64_t rbp, void (*callback)(int frame_num, uint64_t rip)) { 52 | stack_frame_t* stack = (stack_frame_t*) rbp; 53 | for(int i = 0; stack->rbp != 0 && i < max; i++) { 54 | callback(i, stack->rip); 55 | stack = stack->rbp; 56 | } 57 | } 58 | 59 | // db 0x49, 0xbf, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0 ; mov r15, someval 60 | // db 0x41, 0xff, 0xe7 ; jmp r15 61 | 62 | //#patch-doc: Patch a function by replacing the first instruction with a jump to the target address. 63 | patch_t* patch(char* name, uint64_t new_func) { 64 | uint64_t old_func = resolve_symbol(name); 65 | patch_t* patch = (patch_t*) malloc(sizeof(patch_t)); 66 | 67 | if(old_func != (uint64_t) NULL) { 68 | memcpy(patch->old_code, (void*) old_func, 13); 69 | patch->old_addr = (void*) old_func; 70 | 71 | uint8_t* func_mem = (uint8_t*) old_func; 72 | *func_mem = 0x49; 73 | func_mem++; 74 | *func_mem = 0xbf; 75 | func_mem++; 76 | uint64_t* func_mem2 = (uint64_t*) func_mem; 77 | *func_mem2 = new_func; 78 | 79 | uint8_t* jmp = (uint8_t*) (old_func + 10); 80 | *jmp = 0x41; 81 | jmp++; 82 | *jmp = 0xff; 83 | jmp++; 84 | *jmp = 0xe7; 85 | } 86 | return patch; 87 | } 88 | 89 | //#unpatch-doc: Revert a previously patched function. 90 | void unpatch(patch_t* patch) { 91 | memcpy(patch->old_addr, patch->old_code, 13); 92 | free(patch); 93 | } -------------------------------------------------------------------------------- /src/driver/cmos.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace driver; 4 | 5 | //#driver::cmos_read-doc: Read from the CMOS. 6 | uint8_t driver::cmos_read(uint8_t address) { 7 | Port8Bit port_0x70(0x70); 8 | Port8Bit port_0x71(0x71); 9 | 10 | if (address < 10){ 11 | port_0x70.Write(0xa); 12 | 13 | while((port_0x71.Read() & (1 << 7)) != 0) { 14 | asm volatile("nop"); 15 | } 16 | } 17 | 18 | port_0x70.Write(address); 19 | return port_0x71.Read(); 20 | } 21 | 22 | //#driver::convert-doc: Convert "cmos_read" output. 23 | static uint8_t driver::convert(uint8_t num) { 24 | if((cmos_read(0xb) & (1 << 2)) == 0){ 25 | return (num & 0xf) + ((num >> 4) & 0xf) * 10; 26 | } else { 27 | return num; 28 | } 29 | } 30 | 31 | //#driver::cmos-doc: Run a CMOS command. 32 | int driver::cmos(uint8_t function) { 33 | int temp = cmos_read(function); 34 | return convert(temp); 35 | } 36 | 37 | //#driver::get_fattime-doc: Get a valid fat32 timestamp. 38 | uint32_t driver::get_fattime() { 39 | int sec = cmos(CMOS_READ_SEC) / 2; 40 | int min = cmos(CMOS_READ_MIN); 41 | int hour = cmos(CMOS_READ_HOUR); 42 | int day = cmos(CMOS_READ_DAY); 43 | int month = cmos(CMOS_READ_MONTH); 44 | int century = cmos(CMOS_READ_CENTURY); 45 | int year = cmos(CMOS_READ_YEAR) + (century * 100); 46 | 47 | return ((uint32_t) (year - 1980) << 25) 48 | | ((uint32_t) month << 21) 49 | | ((uint32_t) day << 16) 50 | | ((uint32_t) hour << 11) 51 | | ((uint32_t) min << 5) 52 | | ((uint32_t) sec >> 1); 53 | } -------------------------------------------------------------------------------- /src/driver/disk/ahci/ahci.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #define HBA_PORT_DEV_PRESENT 0x3 9 | #define HBA_PORT_IPM_ACTIVE 0x1 10 | #define SATA_SIG_ATAPI 0xEB140101 11 | #define SATA_SIG_ATA 0x00000101 12 | #define SATA_SIG_SEMB 0xC33C0101 13 | #define SATA_SIG_PM 0x96690101 14 | 15 | using namespace driver; 16 | 17 | //#check_port_type-doc: Check the port type for a ahci port. 18 | port_type_t check_port_type(HBA_port* port) { 19 | uint32_t sataStatus = port->sata_status; 20 | 21 | uint8_t interfacePowerManagement = (sataStatus >> 8) & 0b111; 22 | uint8_t deviceDetection = sataStatus & 0b111; 23 | 24 | if (deviceDetection != HBA_PORT_DEV_PRESENT) return port_type_t::None; 25 | if (interfacePowerManagement != HBA_PORT_IPM_ACTIVE) return port_type_t::None; 26 | 27 | switch (port->signature){ 28 | case SATA_SIG_ATAPI: 29 | return port_type_t::SATAPI; 30 | case SATA_SIG_ATA: 31 | return port_type_t::SATA; 32 | case SATA_SIG_PM: 33 | return port_type_t::PM; 34 | case SATA_SIG_SEMB: 35 | return port_type_t::SEMB; 36 | default: 37 | return port_type_t::None; 38 | } 39 | } 40 | 41 | //#AHCI::probe_ports-doc: Probe the ports for a ahci controller. 42 | void AHCI::probe_ports() { 43 | uint32_t portsImplemented = AHCI::ABAR->ports_implemented; 44 | for (int i = 0; i < 32; i++){ 45 | if (portsImplemented & (1 << i)) { 46 | port_type_t port_type = check_port_type(&AHCI::ABAR->ports[i]); 47 | 48 | if (port_type == port_type_t::SATA || port_type == port_type_t::SATAPI) { 49 | ports[port_count] = new AHCI_port(); 50 | ports[port_count]->port_type = port_type; 51 | ports[port_count]->hba_port = &ABAR->ports[i]; 52 | ports[port_count]->port_number = port_count; 53 | port_count++; 54 | } 55 | } 56 | } 57 | } 58 | 59 | //#AHCI::AHCI-doc: Constructor for the AHCI driver. Configures the controller and every port. 60 | AHCI::AHCI(pci::pci_device_header_t* pci_base_address) { 61 | driver::global_serial_driver->printf("AHCI driver instance initialized.\n"); 62 | this->pci_base_address = pci_base_address; 63 | 64 | AHCI::ABAR = (HBA_memory*)(uint64_t)((pci::pci_header_0_t*)pci_base_address)->BAR5; 65 | 66 | g_page_table_manager.map_memory(AHCI::ABAR, AHCI::ABAR); 67 | 68 | port_count = 0; 69 | probe_ports(); 70 | 71 | for (int i = 0; i < port_count; i++) { 72 | AHCI_port* port = ports[i]; 73 | 74 | port->configure(); 75 | 76 | port->buffer = (uint8_t*)global_allocator.request_page(); 77 | memset(port->buffer, 0, 0x1000); 78 | } 79 | } 80 | 81 | //#AHCI::~AHCI-doc: Empty destructor for the AHCI driver. 82 | AHCI::~AHCI() { 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/driver/disk/disk.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | using namespace driver; 7 | using namespace driver::disk; 8 | 9 | DiskManager* driver::disk::global_disk_manager; 10 | 11 | //#Disk::Disk-doc: Empty constructor. 12 | Disk::Disk() { 13 | 14 | } 15 | 16 | //#Disk::~Disk-doc: Empty destructor. 17 | Disk::~Disk() { 18 | 19 | } 20 | 21 | //#Disk::read-doc: Empty virtual function to be overriden. 22 | void Disk::read(uint64_t sector, uint32_t sector_count, void* buffer) { 23 | 24 | } 25 | 26 | //#Disk::write-doc: Empty virtual function to be overriden. 27 | void Disk::write(uint64_t sector, uint32_t sector_count, void* buffer) { 28 | 29 | } 30 | 31 | //#DiskManager::DiskManager-doc: DiskManager constructor. 32 | DiskManager::DiskManager() { 33 | this->num_disks = 0; 34 | } 35 | 36 | //#DiskManager::add_disk-doc: Add a disk to the disk manager. 37 | void DiskManager::add_disk(Disk* disk) { 38 | this->disks[this->num_disks] = disk; 39 | driver::global_serial_driver->printf("Adding new disk at idx %d!\n", this->num_disks); 40 | this->num_disks++; 41 | } 42 | 43 | //#DiskManager::read-doc: Read from a disk using a given ID. 44 | void DiskManager::read(int disk_num, uint64_t sector, uint32_t sector_count, void* buffer) { 45 | this->disks[disk_num]->read(sector, sector_count, buffer); 46 | } 47 | 48 | //#DiskManager::write-doc: Read from a disk using a given ID. 49 | void DiskManager::write(int disk_num, uint64_t sector, uint32_t sector_count, void* buffer) { 50 | this->disks[disk_num]->write(sector, sector_count, buffer); 51 | } -------------------------------------------------------------------------------- /src/driver/disk/virtual_disk.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace driver; 4 | 5 | //#VirtualDisk::VirtualDisk-doc: This class is used to split a physical disk into multiple virtual disks using a sector offset. Currently used to split a disk into multiple partitions. 6 | VirtualDisk::VirtualDisk(disk::Disk* disk, uint64_t lba_offset) { 7 | this->disk = disk; 8 | this->lba_offset = lba_offset; 9 | } 10 | 11 | //#VirtualDisk::~VirtualDisk-doc: Empty destructor. 12 | VirtualDisk::~VirtualDisk() { 13 | } 14 | 15 | //#VirtualDisk::read-doc: This function is used to override the default function from the Drive base class. 16 | void VirtualDisk::read(uint64_t sector, uint32_t sector_count, void* buffer) { 17 | uint64_t lba = sector + lba_offset; 18 | disk->read(lba, sector_count, buffer); 19 | } 20 | 21 | //#VirtualDisk::write-doc: This function is used to override the default function from the Drive base class. 22 | void VirtualDisk::write(uint64_t sector, uint32_t sector_count, void* buffer) { 23 | uint64_t lba = sector + lba_offset; 24 | disk->write(lba, sector_count, buffer); 25 | } -------------------------------------------------------------------------------- /src/driver/driver.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | using namespace driver; 7 | 8 | DriverManager* driver::global_driver_manager; 9 | 10 | //#Driver::Driver-doc: Empty constructor. 11 | Driver::Driver() { 12 | 13 | } 14 | 15 | //#Driver::~Driver-doc: Empty destructor. 16 | Driver::~Driver() { 17 | 18 | } 19 | 20 | //#Driver::activate-doc: Virtual function to be overridden. Activate the driver. 21 | void Driver::activate() { 22 | 23 | } 24 | 25 | //#Driver::is_presend-doc: Virtual function to be overridden. Get if is pre send. 26 | bool Driver::is_presend() { 27 | return true; 28 | } 29 | 30 | //#Driver::get_name-doc: Virtual function to be overridden. Get the driver's name. 31 | char* Driver::get_name() { 32 | return (char*) "default"; 33 | } 34 | 35 | //#DriverManager::DriverManager-doc: DriverManager constructor. 36 | DriverManager::DriverManager() { 37 | this->num_drivers = 0; 38 | } 39 | 40 | //#DriverManager::add_driver-doc: Add a driver to the driver manager. 41 | void DriverManager::add_driver(Driver* driver) { 42 | this->drivers[this->num_drivers] = driver; 43 | this->num_drivers++; 44 | } 45 | 46 | //#DriverManager::set_status-doc: Print the device status onto the screen. 47 | void DriverManager::set_status(char* status, uint64_t color) { 48 | renderer::global_font_renderer->cursor_position.x = renderer::global_font_renderer->target_frame_buffer->width - 8 * (strlen(status) + 4); 49 | renderer::global_font_renderer->printf("[%f%s%r]\n", color, status); 50 | } 51 | 52 | //#DriverManager::activate_driver-doc: Activate a driver. 53 | void DriverManager::activate_driver(bool force, Driver* driver) { 54 | if(force) { 55 | driver->activate(); 56 | this->set_status((char*) "force", 0xffaa00ff); 57 | } else { 58 | if(driver->is_presend()) { 59 | driver->activate(); 60 | this->set_status((char*) "ok", 0xff00ff00); 61 | } else { 62 | this->set_status((char*) "no device", 0xff787878); 63 | } 64 | } 65 | } 66 | 67 | //#DriverManager::activate_all-doc: Activate all drivers. 68 | void DriverManager::activate_all(bool force) { 69 | for(int i = 0; i < this->num_drivers; i++) { 70 | renderer::global_font_renderer->printf("Loading driver for device: %s", this->drivers[i]->get_name()); 71 | activate_driver(force, this->drivers[i]); 72 | } 73 | } 74 | 75 | //#DriverManager::find_driver_by_name-doc: Find a driver by name. 76 | Driver* DriverManager::find_driver_by_name(char* name) { 77 | for (int i = 0; i < num_drivers; i++) { 78 | if(strcmp(drivers[i]->get_name(), name) == 0) { 79 | return drivers[i]; 80 | } 81 | } 82 | return nullptr; 83 | } -------------------------------------------------------------------------------- /src/driver/mouse.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace driver; 4 | 5 | //#MouseEventHandler::MouseEventHandler-doc: Empty constructor. 6 | MouseEventHandler::MouseEventHandler() { 7 | 8 | } 9 | 10 | //#MouseEventHandler::OnMouseDown-doc: Virtual function to be overridden. Gets called when a mouse button is pressed. 11 | void MouseEventHandler::OnMouseDown(uint8_t button) { 12 | 13 | } 14 | 15 | //#MouseEventHandler::OnMouseMove-doc: Virtual function to be overridden. Gets called when the mouse moves. 16 | void MouseEventHandler::OnMouseMove(uint8_t mouse_packet[4]) { 17 | 18 | } 19 | 20 | //#MouseDriver::MouseDriver-doc: Mouse driver constructor. 21 | MouseDriver::MouseDriver(MouseEventHandler* handler) : interrupts::InterruptHandler(0x2C), dataport(0x60), commandport(0x64) { 22 | this->handler = handler; 23 | } 24 | 25 | 26 | //#MouseDriver::MouseWait-doc: Wait for mouse to be ready for the next command. 27 | void MouseDriver::MouseWait() { 28 | uint32_t timeout = 1000; 29 | while (timeout--){ 30 | if ((commandport.Read() & 0b10) == 0){ 31 | return; 32 | } 33 | } 34 | } 35 | 36 | //#MouseDriver::MouseWaitInput-doc: Wait for mouse input. 37 | void MouseDriver::MouseWaitInput() { 38 | uint32_t timeout = 1000; 39 | while (timeout--){ 40 | if (commandport.Read() & 0b1){ 41 | return; 42 | } 43 | } 44 | } 45 | 46 | //#MouseDriver::MouseWrite-doc: Write to the mouse IO port. 47 | void MouseDriver::MouseWrite(uint8_t value) { 48 | MouseWait(); 49 | commandport.Write(0xD4); 50 | MouseWait(); 51 | dataport.Write(value); 52 | } 53 | 54 | //#MouseDriver::MouseRead-doc: Read from the mouse IO port. 55 | uint8_t MouseDriver::MouseRead() { 56 | MouseWaitInput(); 57 | return dataport.Read(); 58 | } 59 | 60 | //#MouseDriver::activate-doc: Activate the mouse driver. 61 | void MouseDriver::activate() { 62 | commandport.Write(0xa8); 63 | MouseWait(); 64 | commandport.Write(0x20); 65 | MouseWaitInput(); 66 | uint8_t status = dataport.Read(); 67 | status |= 0b10; 68 | MouseWait(); 69 | commandport.Write(0x60); 70 | MouseWait(); 71 | dataport.Write(status); 72 | MouseWrite(0xf6); 73 | MouseRead(); 74 | MouseWrite(0xf4); 75 | MouseRead(); 76 | } 77 | 78 | //#MouseDriver::is_presend-doc: Get if is pre send. 79 | bool MouseDriver::is_presend() { 80 | return true; 81 | } 82 | 83 | //#MouseDriver::handle-doc: Mouse event interrupt handler. 84 | void MouseDriver::handle() { 85 | uint8_t data = MouseRead(); 86 | static bool skip = true; 87 | if (skip) { 88 | skip = false; 89 | return; 90 | } 91 | 92 | switch(mouse_cycle) { 93 | case 0: 94 | if ((data & 0b00001000) == 0) 95 | break; 96 | mouse_packet[0] = data; 97 | mouse_cycle++; 98 | break; 99 | case 1: 100 | mouse_packet[1] = data; 101 | mouse_cycle++; 102 | break; 103 | case 2: 104 | mouse_packet[2] = data; 105 | mouse_packet_ready = true; 106 | mouse_cycle = 0; 107 | break; 108 | } 109 | 110 | if(!mouse_packet_ready) 111 | return; 112 | 113 | if(handler != 0) { 114 | handler->OnMouseMove(mouse_packet); 115 | 116 | if(mouse_packet[0] & 1) { 117 | handler->OnMouseDown(LeftButton); 118 | } 119 | 120 | if((mouse_packet[0] >> 1) & 1) { 121 | handler->OnMouseDown(RightButton); 122 | } 123 | 124 | if((mouse_packet[0] >> 2) & 1) { 125 | handler->OnMouseDown(MiddleButton); 126 | } 127 | 128 | } 129 | 130 | mouse_packet_ready = false; 131 | } 132 | 133 | //#MouseDriver::get_name-doc: Get the driver name. 134 | char* MouseDriver::get_name() { 135 | return (char*) "mouse"; 136 | } -------------------------------------------------------------------------------- /src/driver/nic/nic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | using namespace driver; 9 | using namespace driver::nic; 10 | 11 | NicManager* driver::nic::global_nic_manager; 12 | 13 | //#Nic::Nic-doc: Empty constructor. 14 | Nic::Nic() { 15 | 16 | } 17 | 18 | //#Nic::~Nic-doc: Empty destructor. 19 | Nic::~Nic() { 20 | 21 | } 22 | 23 | //#Nic::send-doc: Virtual function to be overridden. Send data with the nic. 24 | void Nic::send(uint8_t* data, int32_t size) { 25 | 26 | } 27 | 28 | //#Nic::register_nic_data_manager-doc: Virtual function to be overridden. Register a nic data manager. 29 | void Nic::register_nic_data_manager(NicDataManager* nic_data_manager) { 30 | this->nic_data_manager = nic_data_manager; 31 | nic_data_manager->nic = this; 32 | } 33 | 34 | //#Nic::get_mac-doc: Virtual function to be overridden. Get the nic's MAC address. 35 | uint64_t Nic::get_mac() { 36 | return 0; 37 | } 38 | 39 | //#Nic::get_ip-doc: Virtual function to be overridden. Get the nic's IP address. 40 | uint32_t Nic::get_ip() { 41 | return 0; 42 | } 43 | 44 | //#Nic::set_ip-doc: Virtual function to be overridden. Set the nic's IP address. 45 | void Nic::set_ip(uint32_t ip) { 46 | 47 | } 48 | 49 | void Nic::load_network_stack(net::net_stack_t* network_stack) { 50 | this->network_stack = network_stack; 51 | 52 | driver::global_serial_driver->printf("[NIC] Network stack loaded.\n"); 53 | driver::global_serial_driver->printf(" etherframe: %x\n", network_stack->ether); 54 | driver::global_serial_driver->printf(" arp: %x\n", network_stack->arp); 55 | driver::global_serial_driver->printf(" ipv4: %x\n", network_stack->ipv4); 56 | driver::global_serial_driver->printf(" icmp: %x\n", network_stack->icmp); 57 | driver::global_serial_driver->printf(" udp: %x\n", network_stack->udp); 58 | driver::global_serial_driver->printf(" tcp: %x\n", network_stack->tcp); 59 | driver::global_serial_driver->printf(" dns: %x\n", network_stack->dns); 60 | } 61 | 62 | 63 | //#NicDataManager::NicDataManager-doc: NicDataManager constructor. 64 | NicDataManager::NicDataManager(int id) { 65 | this->nic_id = id; 66 | global_nic_manager->get_nic(id)->register_nic_data_manager(this); 67 | driver::global_serial_driver->printf("NicDataManager created for nic id %d\n", id); 68 | } 69 | 70 | //#NicDataManager::~NicDataManager-doc: NicDataManager destructor. 71 | NicDataManager::~NicDataManager() { 72 | 73 | } 74 | 75 | //#NicDataManager::send-doc: Send data with the nic. 76 | void NicDataManager::send(uint8_t* data, int32_t size) { 77 | this->nic->send(data, size); 78 | } 79 | 80 | //#NicDataManager::recv-doc: Virtual function to be overridden. This is called when data is recieved. 81 | bool NicDataManager::recv(uint8_t* data, int32_t size) { 82 | driver::global_serial_driver->printf("Received unhandled package!\n"); 83 | return false; 84 | } 85 | 86 | //#NicManager::NicManager-doc: NicManager constructor. 87 | NicManager::NicManager() { 88 | this->num_Nics = 0; 89 | } 90 | 91 | //#NicManager::add_Nic-doc: Add a nic to the nic manager. 92 | void NicManager::add_Nic(Nic* Nic) { 93 | this->Nics[this->num_Nics] = Nic; 94 | driver::global_serial_driver->printf("Adding new Nic at idx %d!\n", this->num_Nics); 95 | this->num_Nics++; 96 | } 97 | 98 | //#NicManager::get_nic-doc: Get a nic by ID.: 99 | Nic* NicManager::get_nic(int nic_id) { 100 | return this->Nics[nic_id]; 101 | } -------------------------------------------------------------------------------- /src/driver/pc_speaker.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace driver; 7 | 8 | //#PcSpeakerDriver::PcSpeakerDriver-doc: Empty constructor. 9 | PcSpeakerDriver::PcSpeakerDriver() { 10 | } 11 | 12 | //#PcSpeakerDriver::~PcSpeakerDriver-doc: Empty destructor. 13 | PcSpeakerDriver::~PcSpeakerDriver() { 14 | } 15 | 16 | //#PcSpeakerDriver::activate-doc: This function is used to override the default function from the Driver base class. 17 | void PcSpeakerDriver::activate() { 18 | // that just takes more time too boot and is useless 19 | /*play_note((1 << 4) | 1); 20 | if (hpet::is_available()) { 21 | hpet::sleep_d(0.5); 22 | } else { 23 | PIT::sleep_d(0.5); 24 | } 25 | turn_off();*/ 26 | } 27 | 28 | //#PcSpeakerDriver::is_presend-doc: This function is used to override the default function from the Driver base class. 29 | bool PcSpeakerDriver::is_presend() { 30 | return true; 31 | } 32 | 33 | //#PcSpeakerDriver::get_name-doc: This function is used to override the default function from the Driver base class. 34 | char* PcSpeakerDriver::get_name() { 35 | return (char*) "pc speaker"; 36 | } 37 | 38 | //#PcSpeakerDriver::turn_on-doc: This function is used to turn on the pc speaker. 39 | void PcSpeakerDriver::turn_on() { 40 | outb(0x61, (inb(0x61) | 3)); 41 | } 42 | 43 | //#PcSpeakerDriver::turn_off-doc: This function is used to turn off the pc speaker. 44 | void PcSpeakerDriver::turn_off() { 45 | outb(0x61, (inb(0x61) & 0xFC)); 46 | } 47 | 48 | //#PcSpeakerDriver::set_frequency-doc: This function is used to set the frequency of the pc speaker. 49 | void PcSpeakerDriver::set_frequency(uint16_t frequency) { 50 | outb(0x43, 0xB6); 51 | outb(0x42, (uint8_t) frequency); 52 | outb(0x42, (uint8_t) (frequency >> 8)); 53 | } 54 | 55 | //#PcSpeakerDriver::play-doc: This function is used to set the frequency of the pc speaker and then automatically starts playing. 56 | void PcSpeakerDriver::play(uint16_t frequency) { 57 | set_frequency(frequency); 58 | turn_on(); 59 | } 60 | 61 | 62 | uint16_t notes[7][12] = { 63 | { 36485, 34437, 32505, 30680, 28958, 27333, 25799, 24351, 22984, 21694, 20477, 19327 }, 64 | { 18243, 17219, 16252, 15340, 14479, 13666, 12899, 12175, 11492, 10847, 10238, 9664 }, 65 | { 9121, 8609, 8126, 7670, 7240, 6833, 6450, 6088, 5746, 5424, 5119, 4832 }, 66 | { 4561, 4305, 4063, 3835, 3620, 3417, 3225, 3044, 2873, 2712, 2560, 2416 }, 67 | { 2280, 2152, 2032, 1918, 1810, 1708, 1612, 1522, 1437, 1356, 1280, 1208 }, 68 | { 1140, 1076, 1016, 959, 905, 854, 806, 761, 718, 678, 640, 604}, 69 | { 570, 538, 508, 479, 452, 427, 403, 380, 359, 339, 320, 302 } 70 | }; 71 | 72 | //#PcSpeakerDriver::play_note-doc: This function is used to play a note. The note is encoded with the following format: (octave << 4) | note. 73 | void PcSpeakerDriver::play_note(uint8_t note) { 74 | play(notes[note >> 4][note & 0xf]); 75 | } 76 | -------------------------------------------------------------------------------- /src/driver/serial.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace driver; 4 | 5 | Serial* driver::global_serial_driver; 6 | 7 | //#Serial::Serial-doc: Constructor for the serial class. Configures the given port. 8 | Serial::Serial(uint16_t port_n) : port(port_n) { 9 | port.offset = 1; 10 | port.Write(0x00); 11 | port.offset = 3; 12 | port.Write(0x80); 13 | port.offset = 0; 14 | port.Write(0x03); 15 | port.offset = 1; 16 | port.Write(0x00); 17 | port.offset = 3; 18 | port.Write(0x03); 19 | port.offset = 2; 20 | port.Write(0xc7); 21 | port.offset = 4; 22 | port.Write(0x0b); 23 | 24 | } 25 | 26 | //#Serial::serial_recieved-doc: Check if we recieved something on the serial port. 27 | int Serial::serial_recieved() { 28 | port.offset = 5; 29 | return port.Read() & 1; 30 | } 31 | 32 | //#Serial::is_transmit_empty-doc: Check if we can send the next byte. 33 | int Serial::is_transmit_empty() { 34 | port.offset = 5; 35 | return port.Read() & 0x20; 36 | } 37 | 38 | //#Serial::read_serial-doc: Read a byte from the serial port. Waits until a byte is recieved. 39 | char Serial::read_serial() { 40 | while(serial_recieved() == 0); 41 | port.offset = 0; 42 | return port.Read(); 43 | } 44 | 45 | //#Serial::write_serial-doc: Write a byte or string to the serial port. 46 | void Serial::write_serial(char a) { 47 | while(is_transmit_empty() == 0); 48 | port.offset = 0; 49 | port.Write(a); 50 | } 51 | 52 | void Serial::write_serial(const char* str) { 53 | char* chr = (char*)str; 54 | 55 | while(*chr != 0){ 56 | write_serial(*chr); 57 | chr++; 58 | } 59 | } 60 | 61 | //#Serial::putc-doc: Writes a char to the serial console. 62 | void Serial::putc(char c){ 63 | 64 | 65 | this->write_serial(c); 66 | 67 | if (c == '\n') { 68 | this->write_serial('\r'); 69 | return; 70 | } 71 | } 72 | 73 | //#Serial::puts-doc: Writes a string to the serial console. 74 | void Serial::puts(const char *s){ 75 | while(*s){ 76 | this->putc(*s++); 77 | } 78 | } 79 | 80 | //#Serial::putn-doc: Writes a number to the serial console. 81 | void Serial::putn(unsigned long x, int base){ 82 | char buf[65]; 83 | const char* digits = "0123456789abcdefghijklmnopqrstuvwxyz"; 84 | char* p; 85 | 86 | if(base > 36) return; 87 | 88 | p = buf + 64; 89 | *p = '\0'; 90 | do { 91 | *--p = digits[x % base]; 92 | x /= base; 93 | } while (x); 94 | 95 | this->puts(p); 96 | 97 | } 98 | 99 | //#Serial::printf-doc: Writes a formatted string to the serial console. The following formats are supported: %s, %c, %d, %u, %x, %p. 100 | void Serial::printf(const char* fmt, ...){ 101 | va_list ap; 102 | const char* s; 103 | unsigned long n; 104 | 105 | va_start(ap, fmt); 106 | while (*fmt) { 107 | if (*fmt == '%') { 108 | fmt++; 109 | switch (*fmt) { 110 | case 's': 111 | s = va_arg(ap, char*); 112 | this->puts(s); 113 | break; 114 | case 'c': 115 | n = va_arg(ap, int); 116 | this->putc(n); 117 | break; 118 | case 'd': 119 | case 'u': 120 | n = va_arg(ap, unsigned long int); 121 | this->putn(n, 10); 122 | break; 123 | case 'x': 124 | case 'p': 125 | n = va_arg(ap, unsigned long int); 126 | this->putn(n, 16); 127 | break; 128 | case '%': 129 | this->putc('%'); 130 | break; 131 | case '\0': 132 | goto out; 133 | default: 134 | this->putc('%'); 135 | this->putc(*fmt); 136 | break; 137 | } 138 | } else { 139 | this->putc(*fmt); 140 | } 141 | 142 | fmt++; 143 | } 144 | 145 | out: 146 | va_end(ap); 147 | } -------------------------------------------------------------------------------- /src/efi_mem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const char* efi_memory_type_strings[] { 4 | "EfiReservedMemoryType", 5 | "EfiLoaderCode", 6 | "EfiLoaderData", 7 | "EfiBootServicesCode", 8 | "EfiBootServicesData", 9 | "EfiRuntimeServicesCode", 10 | "EfiRuntimeServicesData", 11 | "EfiConventionalMemory", 12 | "EfiUnusableMemory", 13 | "EfiACPIReclaimMemory", 14 | "EfiACPIMemoryNVS", 15 | "EfiMemoryMappedIO", 16 | "EfiMemoryMappedIOPortSpace", 17 | "EfiPalCode", 18 | }; -------------------------------------------------------------------------------- /src/entry.asm: -------------------------------------------------------------------------------- 1 | [global _start] 2 | [global cpu_init] 3 | [extern kernel_main] 4 | 5 | ; This is here to mark the end of the stack trace. 6 | ; The boot loader passes the bootinfo struct just dont touch it and call kernel_main 7 | 8 | ;# _start-signature: void _start() 9 | ;# _start-doc: The absolute main entry point of the kernel. 10 | 11 | _start: 12 | mov rbp, 0 13 | call cpu_init 14 | call kernel_main 15 | 16 | ;# cpu_init-signature: void cpu_init() 17 | ;# cpu_init-doc: Initialize the needed cpu features like the fpu and sse. 18 | 19 | cpu_init: 20 | push rbp 21 | mov rbp, rsp 22 | push rbx 23 | 24 | ; enable coprocessor (fpu and sse) 25 | mov rax, cr0 26 | and ax, 0xFFFB 27 | or ax, 0x2 28 | mov cr0, rax 29 | 30 | mov rax, cr4 31 | or ax, 3 << 9 32 | mov cr4, rax 33 | 34 | fninit 35 | 36 | pop rbx 37 | pop rbp 38 | ret 39 | -------------------------------------------------------------------------------- /src/examples/disk.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | //#disk_test-doc: Test reading the disk. 8 | void disk_test(char* _) { 9 | char* buffer = (char*) global_allocator.request_page(); //Request a page from the page frame allocator to store the data read by the disk manager 10 | driver::disk::global_disk_manager->read(0, 0, 1, buffer);//Read raw data from the disk of ID 0 into the buffer 11 | 12 | for (int t = 0; t < 512; t++){ 13 | driver::global_serial_driver->printf("%c", buffer[t]); //Print part of the buffer's contents 14 | } 15 | driver::global_serial_driver->printf("\n"); 16 | 17 | global_allocator.free_page(buffer); //Free the requested page 18 | } 19 | -------------------------------------------------------------------------------- /src/examples/examples.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void syscall_test(char* _); 6 | void test_patch(char* _); 7 | void test_scheduler(char* _); 8 | void disk_test(char* _); 9 | void font_renderer_test(char* _); 10 | void fat32_old_test(char* _); 11 | void fat32_test(char* _); 12 | void vfs_test(char* _); 13 | void layer_test(char* _); 14 | void test_sound(char* _); 15 | void test_net(char* _); -------------------------------------------------------------------------------- /src/examples/fat32.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | //#fat32_test-doc: Test the fat32 driver. 8 | void fat32_test(char* _) { 9 | FATFS fs; 10 | FIL fp; 11 | UINT btr, br; 12 | FRESULT fr; 13 | 14 | f_mount(&fs, "", 0); //Mount the filesystem 15 | 16 | fr = f_open(&fp, "/startup.nsh", FA_READ); //Open file 17 | if (fr == FR_OK) { //Check for errors 18 | btr = f_size(&fp); //Get the size of the file 19 | void* file_contents = global_allocator.request_pages(btr / 0x1000 + 1); //Request pages to store the file contents in 20 | 21 | f_read(&fp, file_contents, btr, &br); //Read the file contents into the buffer 22 | f_close(&fp); //Close the file 23 | 24 | renderer::global_font_renderer->printf("%s", file_contents); //Print the file's contents from the buffer 25 | 26 | global_allocator.free_pages(file_contents, btr / 0x1000 + 1); //Free the requested pages 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/examples/fat32_old.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | //#fat32_old_test-doc: Test the OLD fat32 driver. 8 | void fat32_old_test(char* _) { 9 | fat32_old::disk_id = 0; //Set to the first disk 10 | uint8_t fs_buf[512]; 11 | fat32_old::fs_info_t fs_info = fat32_old::read_info(fs_buf); //Read file system info 12 | show_info(fs_info); //Print the info to the serial console 13 | 14 | 15 | fat32_old::sector_buffer_t sector_buffer; 16 | fat32_old::file_info_t fp; 17 | fat32_old::fopen("/STARTUP.NSH", "r", &fp, fs_info, §or_buffer); //Open file 18 | 19 | uint8_t* buffer = (uint8_t*) global_allocator.request_page(); //Request a page to store data 20 | 21 | fat32_old::fread(buffer, 4096, &fp, fs_info, §or_buffer); //Read 4096 bytes from the file into the buffer 22 | fat32_old::fclose(&fp, §or_buffer); 23 | 24 | driver::global_serial_driver->printf("%s", buffer); //Print the file's contents onto the serial console 25 | 26 | global_allocator.free_page(buffer); //Free the requested page 27 | } 28 | -------------------------------------------------------------------------------- /src/examples/layer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | extern uint8_t logo[]; 10 | 11 | #define RAND_MAX 32767 12 | unsigned long next = 1; 13 | 14 | //#rand-doc: Get a random number. 15 | int rand(){ 16 | next = next * 1103515245 + 12345; 17 | return (uint32_t) (next / 65536) % RAND_MAX + 1; 18 | } 19 | 20 | uint8_t buffer[1000][1000] = {0}; 21 | uint8_t resets[1000] = {0}; 22 | 23 | //#frame-doc: Render a frame of the layer test. 24 | void frame() { 25 | int rows = renderer::global_font_renderer->target_frame_buffer->height / 16; 26 | int columns = renderer::global_font_renderer->target_frame_buffer->width / 8; 27 | 28 | renderer::global_font_renderer->color = 0x00000000; 29 | renderer::global_font_renderer->clear(); 30 | renderer::global_font_renderer->color = 0xffffffff; 31 | 32 | 33 | for (int i = 0; i < rows; i++) { 34 | for (int j = 0; j < columns; j++) { 35 | if (i == 0) { 36 | buffer[i][j] = (buffer[i][j] + 1) % (resets[j] + 2); 37 | 38 | if(buffer[i][j] == 0) { 39 | resets[j] = (rand() % rows); 40 | } 41 | 42 | } else { 43 | if(buffer[i - 1][j] != 0) { 44 | if(buffer[i - 1][j] - 1 > 0) { 45 | buffer[i][j] = buffer[i - 1][j] - 1; 46 | } else { 47 | buffer[i][j] = 0; 48 | } 49 | } else { 50 | buffer[i][j] = 0; 51 | } 52 | } 53 | } 54 | } 55 | 56 | for (int i = 0; i < rows; i++) { 57 | for (int j = 0; j < columns; j++) { 58 | renderer::global_font_renderer->color = 0xff000000 | ((0xff - buffer[i][j]) << 12); 59 | 60 | renderer::global_font_renderer->cursor_position.y = i * 16; 61 | renderer::global_font_renderer->cursor_position.x = j * 8; 62 | renderer::global_font_renderer->putc(buffer[i][j] ? 'X' : ' '); 63 | } 64 | } 65 | } 66 | 67 | 68 | extern framebuffer_t default_framebuffer; 69 | 70 | //#layer_test-doc: Test the layer renderer. 71 | void layer_test(char* _) { 72 | renderer::layer_t* l1 = renderer::allocate_layer_matching(&default_framebuffer); 73 | renderer::layer_t* l2 = renderer::allocate_layer_matching(&default_framebuffer); 74 | 75 | renderer::layer_renderer* lr1 = new renderer::layer_renderer(&default_framebuffer); 76 | 77 | 78 | renderer::Renderer2D* r2d = new renderer::Renderer2D(l1); 79 | 80 | renderer::global_font_renderer->target_frame_buffer = l2; 81 | renderer::global_renderer2D->target_frame_buffer = l2; 82 | renderer::global_font_renderer->cursor_position = { 0, 0 }; 83 | 84 | int frames_to_render = 100; 85 | 86 | 87 | while (true) { 88 | 89 | frame(); 90 | 91 | r2d->load_bitmap(logo, 0); 92 | 93 | 94 | lr1->render_layer(l1, true); 95 | lr1->render_layer(l2, false); 96 | lr1->render(); 97 | 98 | if(--frames_to_render == 0) { 99 | break; 100 | } 101 | 102 | driver::global_serial_driver->printf("frames left: %d\n", frames_to_render); 103 | } 104 | 105 | renderer::destroy_layer(l1); 106 | renderer::destroy_layer(l2); 107 | 108 | renderer::global_font_renderer->target_frame_buffer = &default_framebuffer; 109 | renderer::global_renderer2D->target_frame_buffer = &default_framebuffer; 110 | renderer::global_font_renderer->color = 0xffffffff; 111 | 112 | free(lr1); 113 | free(r2d); 114 | } 115 | -------------------------------------------------------------------------------- /src/examples/net.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | void test_net(char* _) { 7 | new_task((void*) (void_function) []() { 8 | net::net_stack_t* net_stack = driver::nic::global_nic_manager->get_nic(0)->network_stack; 9 | 10 | // resolve discord.com ip and send a ping 11 | driver::nic::ip_u google_ip; 12 | google_ip.ip = net_stack->dns->resolve((char*) "www.google.com"); 13 | 14 | driver::global_serial_driver->printf("Resolved www.google.com to %d.%d.%d.%d\n", google_ip.ip_p[0], google_ip.ip_p[1], google_ip.ip_p[2], google_ip.ip_p[3]); 15 | 16 | char http_request[] = "GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n"; 17 | net::TcpSocket* google_http_socket = net_stack->tcp->connect(google_ip.ip, 80); 18 | google_http_socket->send((uint8_t*)http_request, strlen(http_request)); 19 | }); 20 | } -------------------------------------------------------------------------------- /src/examples/patch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | patch_t* p; 6 | 7 | //#usefull_function-doc: Test function for patching. 8 | void usefull_function() { 9 | driver::global_serial_driver->printf("usefull_function\n"); 10 | } 11 | 12 | //#usefull_function2-doc: Test function for patching. 13 | void usefull_function2() { 14 | driver::global_serial_driver->printf("usefull_function2\n"); 15 | unpatch(p); 16 | } 17 | 18 | //#test_patch-doc: Test patching. 19 | void test_patch(char* _) { 20 | p = patch((char*) "_Z16usefull_functionv", resolve_symbol((char*) "_Z17usefull_function2v")); 21 | usefull_function(); 22 | usefull_function(); 23 | } 24 | -------------------------------------------------------------------------------- /src/examples/scheduler.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | task* task2; 7 | 8 | //#test_scheduler-doc: Test the scheduler. 9 | void test_scheduler(char* _) { 10 | //#new_task-discard 11 | task* task1 = new_task((void*) (void_function) []() { 12 | driver::global_serial_driver->printf("A"); 13 | }); 14 | task2 = new_task((void*) (void_function) []() { 15 | while (true) { 16 | driver::global_serial_driver->printf("B"); 17 | } 18 | }); 19 | task* task3 = new_task((void*) (void_function) []() { 20 | driver::global_serial_driver->printf("C"); 21 | 22 | int x = 10000000; 23 | while(x--); 24 | 25 | task2->kill_me = true; 26 | }); 27 | 28 | //init_sched(); 29 | } 30 | -------------------------------------------------------------------------------- /src/examples/sound.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | //#test_sound-doc: Test the sound driver (very loud). 7 | void test_sound(char* _) { 8 | driver::PcSpeakerDriver* driver = (driver::PcSpeakerDriver*) driver::global_driver_manager->find_driver_by_name((char*) "pc speaker"); 9 | 10 | for (int i = 0; i < 7; i++) { 11 | for (int j = 0; j < 12; j++) { 12 | driver::global_serial_driver->printf("note: %d, octave: %d\n", j, i); 13 | 14 | driver->play_note((i << 4) | j); 15 | PIT::sleep_d(10); 16 | } 17 | } 18 | 19 | driver->turn_off(); 20 | } 21 | -------------------------------------------------------------------------------- /src/examples/syscall.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | //#syscall_test-doc: Syscall test function. 6 | extern "C" void syscall_test(s_registers* regs) { 7 | driver::global_serial_driver->printf("Hello from the syscall %d!\n", regs->rax); 8 | } 9 | 10 | //#syscall_test2-doc: Syscall test function. 11 | extern "C" void syscall_test2(s_registers* regs) { 12 | driver::global_serial_driver->printf("Hello from the syscall %d!\n", regs->rax); 13 | } 14 | 15 | //#syscall_test-doc: Test a syscall. 16 | void syscall_test(char* _) { 17 | asm ("mov $0, %rax; int $0x30; mov $1, %rax; int $0x30"); 18 | } 19 | -------------------------------------------------------------------------------- /src/examples/vfs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | /* ------------------------------------------------------------ 9 | ---- DO NOT TRY TO INITIALISE A DISK TWICE AT THE SAME ID! ---- 10 | ------------------------------------------------------------ */ 11 | 12 | //#vfs_test-doc: Test the virtual file system. DO NOT TRY TO INITIALISE A DISK TWICE AT THE SAME ID! 13 | void vfs_test(char* _) { 14 | vfs_mount* fat_mount = initialise_fat32(0); //Initialise the FAT32 disk at ID 0 15 | mount(fat_mount, (char*) "vfstest"); //Mount the FAT32 disk at vfstest:/ 16 | 17 | FILE* file = fopen("vfstest:/startup.nsh", "r"); //Open file 18 | int file_size = file->size; //Get the file's size 19 | void* buffer = global_allocator.request_pages(file_size / 0x1000 + 1); //Request pages to store the file's contents in 20 | 21 | fread(buffer, file_size, 1, file); //Read the file contents into the buffer 22 | renderer::global_font_renderer->printf("%s", buffer); //Print the file's contents from the buffer 23 | 24 | fclose(file); //Close the file 25 | global_allocator.free_pages(buffer, file_size / 0x1000 + 1); //Free the pages requested for the buffer 26 | } 27 | -------------------------------------------------------------------------------- /src/fs/fd.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define ASSERT_NO_PANIC 5 | #include 6 | 7 | using namespace fd; 8 | 9 | //#FileDescriptor::FileDescriptor-doc: The constructor of the FileDescriptor class. 10 | FileDescriptor::FileDescriptor(int fd) { 11 | this->fd = fd; 12 | this->file = NULL; 13 | } 14 | 15 | //#FileDescriptor::~FileDescriptor-doc: Empty destructor. 16 | FileDescriptor::~FileDescriptor() { 17 | 18 | } 19 | 20 | //#FileDescriptor::close-doc: Closes the file descriptor. 21 | void FileDescriptor::close() { 22 | assert(this->file != NULL); 23 | 24 | fclose(this->file); 25 | return; 26 | 27 | assert_fail: 28 | set_task_errno(VFS_ERROR); 29 | } 30 | 31 | //#FileDescriptor::open-doc: Opens the file descriptor. 32 | void FileDescriptor::open(const char* path, const char* mode) { 33 | assert(this->file == NULL); 34 | 35 | this->file = fopen(path, mode); 36 | return; 37 | 38 | assert_fail: 39 | set_task_errno(VFS_ERROR); 40 | } 41 | 42 | //#FileDescriptor::read-doc: Reads from the file descriptor. 43 | void FileDescriptor::read(void* buffer, size_t size, size_t nmemb) { 44 | assert(this->file != NULL); 45 | 46 | fread(buffer, size, nmemb, this->file); 47 | return; 48 | 49 | assert_fail: 50 | set_task_errno(VFS_ERROR); 51 | } 52 | 53 | //#FileDescriptor::write-doc: Writes to the file descriptor. 54 | void FileDescriptor::write(void* buffer, size_t size, size_t nmemb) { 55 | assert(this->file != NULL); 56 | 57 | fwrite(buffer, size, nmemb, this->file); 58 | return; 59 | 60 | assert_fail: 61 | set_task_errno(VFS_ERROR); 62 | } 63 | 64 | //#FileDescriptorManager::FileDescriptorManager-doc: The constructor of the FileDescriptorManager class. 65 | FileDescriptorManager::FileDescriptorManager() : fds(100) { 66 | this->curr_fd = 10; 67 | } 68 | 69 | //#FileDescriptorManager::~FileDescriptorManager-doc: Empty destructor. 70 | FileDescriptorManager::~FileDescriptorManager() { 71 | 72 | } 73 | 74 | //#FileDescriptorManager::alloc_fd-doc: Allocates a new file descriptor. 75 | int FileDescriptorManager::alloc_fd() { 76 | return ++this->curr_fd; 77 | } 78 | 79 | //#FileDescriptorManager::free_fd-doc: Frees a file descriptor. 80 | void FileDescriptorManager::free_fd(int fd) { 81 | listv2::node* n = this->fds.find([](int _fd, listv2::node* n) { 82 | return _fd == n->data->fd; 83 | }, fd); 84 | 85 | assert(n != NULL); 86 | 87 | this->fds.remove(n); 88 | return; 89 | 90 | assert_fail: 91 | set_task_errno(VFS_ERROR); 92 | } 93 | 94 | //#FileDescriptorManager::register_fd-doc: Registers a FileDescriptor object. 95 | void FileDescriptorManager::register_fd(FileDescriptor* fd_obj) { 96 | this->fds.add(fd_obj); 97 | } 98 | 99 | //#FileDescriptorManager::get_fd-doc: Gets a FileDescriptor object by its file descriptor. 100 | FileDescriptor* FileDescriptorManager::get_fd(int fd) { 101 | listv2::node* n = this->fds.find([](int _fd, listv2::node* n) { 102 | return _fd == n->data->fd; 103 | }, fd); 104 | 105 | assert(n != NULL); 106 | return n->data; 107 | 108 | assert_fail: 109 | set_task_errno(VFS_ERROR); 110 | return NULL; 111 | } 112 | 113 | FileDescriptorManager* fd::fdm; -------------------------------------------------------------------------------- /src/fs/gpt/gpt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace gpt; 12 | 13 | //#gpt::read_gpt-doc: Read the guid partition table from a disk. Returns false if an error occurred. Automaticaly registers a new virtual disk for every partition found. 14 | bool gpt::read_gpt(driver::disk::Disk* disk) { 15 | gpt_header* header = (gpt_header*) global_allocator.request_page(); 16 | disk->read(1, 1, (void*) header); 17 | 18 | if (memcmp(header->signature, "EFI PART", 8) != 0) { 19 | global_allocator.free_page(header); 20 | return false; 21 | } else { 22 | gpt_partition_entry* entries = (gpt_partition_entry*) global_allocator.request_pages(((header->partition_entries_size * header->partition_entries_count) / 4096) + 1); 23 | disk->read(header->partition_entries_startting_lba, ((header->partition_entries_size * header->partition_entries_count) / 512 ) + 1, (void*) entries); 24 | 25 | for (int i = 0; i < header->partition_entries_count; i++) { 26 | if (entries[i].type_guid.data1 == 0) { 27 | continue; 28 | } 29 | 30 | driver::global_serial_driver->printf("Partition guid: %x, index: %d, partition start lba: %d\n", entries[i].type_guid.data3, i, entries[i].first_lba); 31 | 32 | driver::VirtualDisk* vdisk = new driver::VirtualDisk(disk, entries[i].first_lba); 33 | driver::disk::global_disk_manager->add_disk(vdisk); 34 | } 35 | 36 | 37 | global_allocator.free_pages(entries, ((header->partition_entries_size * header->partition_entries_count) / 4096) + 1); 38 | global_allocator.free_page(header); 39 | return true; 40 | } 41 | } -------------------------------------------------------------------------------- /src/fs/stivale/vfs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | //#initialise_stivale_modules-doc: Initialise a new mount point for a stivale module mount. 10 | vfs_mount* initialise_stivale_modules(stivale2_struct* bootinfo) { 11 | vfs_mount* mount = new vfs_mount; 12 | memset(mount, 0, sizeof(mount)); 13 | 14 | stivale2_struct_tag_modules* modules = stivale2_tag_find(bootinfo, STIVALE2_STRUCT_TAG_MODULES_ID); 15 | 16 | mount->data = (void*) modules->modules; 17 | mount->data2 = modules->module_count; 18 | 19 | mount->open = stivale_modules_open; 20 | mount->read = stivale_modules_read; 21 | mount->close = stivale_modules_close; 22 | 23 | mount->seek = stivale_modules_seek; 24 | mount->tell = stivale_modules_tell; 25 | 26 | mount->mount = stivale_modules_mount; 27 | 28 | return mount; 29 | } 30 | 31 | //#stivale_modules_mount-doc: The mount function for a stivale mount point. 32 | void stivale_modules_mount(vfs_mount* node) { 33 | stivale2_module* mod = (stivale2_module*) node->data; 34 | 35 | for (int i = 0; i < node->data2; i++) { 36 | driver::global_serial_driver->printf("Found stivale module %s at 0x%x ending at 0x%x!\n", mod[i].string, mod[i].begin, mod[i].end); 37 | } 38 | 39 | } 40 | 41 | //#stivale_modules_open-doc: The open function for a stivale mount point. 42 | FILE* stivale_modules_open(vfs_mount* node, const char* file, const char* mode) { 43 | FILE* fp = new FILE; 44 | 45 | if (strcmp((char*)mode, (char*)"r") == 0) { 46 | fp->is_readable = 1; 47 | fp->is_writable = 0; 48 | } else if (strcmp((char*)mode, (char*)"w") == 0) { 49 | set_task_errno(VFS_NOT_IMPLEMENTED); 50 | fp->is_error = 1; 51 | return fp; 52 | } else if (strcmp((char*)mode, (char*)"a") == 0) { 53 | set_task_errno(VFS_NOT_IMPLEMENTED); 54 | fp->is_error = 1; 55 | return fp; 56 | } else if (strcmp((char*)mode, (char*)"r+") == 0) { 57 | set_task_errno(VFS_NOT_IMPLEMENTED); 58 | fp->is_error = 1; 59 | return fp; 60 | } else if (strcmp((char*)mode, (char*)"w+") == 0) { 61 | set_task_errno(VFS_NOT_IMPLEMENTED); 62 | fp->is_error = 1; 63 | return fp; 64 | } else if (strcmp((char*)mode, (char*)"a+") == 0) { 65 | set_task_errno(VFS_NOT_IMPLEMENTED); 66 | fp->is_error = 1; 67 | return fp; 68 | } 69 | 70 | stivale2_module* mod = (stivale2_module*) node->data; 71 | 72 | for (int i = 0; i < node->data2; i++) { 73 | if(strcmp(mod[i].string, (char*) file) == 0) { 74 | fp->size = mod[i].end - mod[i].begin; 75 | fp->data = (void*) mod[i].begin; 76 | 77 | goto found; 78 | } 79 | } 80 | 81 | set_task_errno(VFS_FILE_NOT_FOUND); 82 | fp->is_error = 1; 83 | return fp; 84 | 85 | found: 86 | return fp; 87 | } 88 | 89 | //#stivale_modules_close-doc: The close function for a stivale mount point. 90 | int stivale_modules_close(vfs_mount* node, file_t* stream) { 91 | stream->data = NULL; 92 | stream->size = 0; 93 | stream->is_readable = 0; 94 | 95 | return 0; 96 | } 97 | 98 | //#stivale_modules_seek-doc: The seek function for a stivale mount point. 99 | int stivale_modules_seek(vfs_mount*, file_t* file, long int offset, int whence) { 100 | switch (whence) { 101 | case SEEK_SET: 102 | { 103 | file->pos = offset; 104 | } 105 | break; 106 | case SEEK_CUR: 107 | { 108 | file->pos += offset; 109 | } 110 | break; 111 | case SEEK_END: 112 | { 113 | file->pos = file->size + offset; 114 | } 115 | break; 116 | default: 117 | return -1; 118 | } 119 | 120 | return 0; 121 | } 122 | 123 | //#stivale_modules_tell-doc: The tell function for a stivale mount point. 124 | long int stivale_modules_tell(vfs_mount*, file_t* file) { 125 | return file->pos; 126 | } 127 | 128 | //#stivale_modules_read-doc: The read function for a stivale mount point. 129 | size_t stivale_modules_read(vfs_mount* node, void* buffer, size_t size, size_t nmemb, file_t* stream) { 130 | for (int i = 0; i < size; i++) { 131 | *(uint8_t*) ((uint64_t) buffer + i) = *((uint8_t*) stream->data + i + stream->pos); 132 | } 133 | 134 | return size; 135 | } -------------------------------------------------------------------------------- /src/fs/vfs/list.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | //#list::list-doc: Constructor for the list class allocates memory for the list depending on the size of the list. 7 | list::list(int max_len) { 8 | this->node_count = max_len; 9 | this->nodes = (list_node_t*) malloc(sizeof(list_node_t) * max_len); 10 | memset(this->nodes, 0, sizeof(list_node_t) * max_len); 11 | } 12 | 13 | //#list::~list-doc: Destructor for the list class frees the memory allocated for the list. 14 | list::~list() { 15 | free(this->nodes); 16 | } 17 | 18 | //#list::find_node-doc: Finds a node in the list using a comparison function. 19 | list_node_t* list::find_node(search_function f, void* d1, void* d2, void* d3, void* d4) { 20 | for (int i = 0; i < this->node_count; i++) { 21 | if(this->nodes[i].is_taken) { 22 | if(f(&this->nodes[i], d1, d2, d3, d4)) { 23 | return &this->nodes[i]; 24 | } 25 | } 26 | } 27 | return NULL; 28 | } 29 | 30 | //#list::remove_node-doc: Removes a node from the list using a pointer to the node. 31 | void list::remove_node(list_node_t* node) { 32 | for (int i = 0; i < this->node_count; i++) { 33 | if(&this->nodes[i] == node) { 34 | memset(&this->nodes[i], 0, sizeof(list_node_t)); 35 | } 36 | } 37 | } 38 | 39 | //#list::add_node-doc: Adds a node to the list. Returns the pointer to the node. 40 | list_node_t* list::add_node(void* d1, void* d2, void* d3, void* d4) { 41 | for (int i = 0; i < this->node_count; i++) { 42 | if(!this->nodes[i].is_taken) { 43 | memset(&this->nodes[i], 0, sizeof(list_node_t)); 44 | this->nodes[i] = { d1, d2, d3, d4, true }; 45 | return &this->nodes[i]; 46 | } 47 | } 48 | 49 | return NULL; 50 | } -------------------------------------------------------------------------------- /src/gdt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | __attribute__((aligned(0x1000))) 4 | gdt_t default_gdt = { 5 | {0, 0, 0, 0x00, 0x00, 0}, 6 | {0, 0, 0, 0x9a, 0xa0, 0}, 7 | {0, 0, 0, 0x92, 0xa0, 0}, 8 | {0, 0, 0, 0x00, 0x00, 0}, 9 | {0, 0, 0, 0x9a, 0xa0, 0}, 10 | {0, 0, 0, 0x92, 0xa0, 0} 11 | }; -------------------------------------------------------------------------------- /src/include/apic/apic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | typedef void (*void_function)(); 10 | 11 | int run_on_ap(void_function function); 12 | void wait_for_aps(); 13 | 14 | 15 | struct trampoline_data { 16 | uint8_t status; 17 | uint64_t pagetable; 18 | uint64_t idt; 19 | uint64_t gdt; 20 | uint64_t stack_ptr; 21 | uint64_t entry; 22 | uint64_t lapic_ptr; 23 | } __attribute__ ((packed)); 24 | 25 | enum ap_status { 26 | incpp = 1, 27 | init_done, 28 | wait_for_work, 29 | please_work, 30 | running 31 | }; 32 | 33 | 34 | struct cpu { 35 | bool presend; 36 | uint8_t status; 37 | void_function function; 38 | }; 39 | 40 | void start_all_cpus(stivale2_struct* bootinfo); 41 | 42 | extern cpu cpus[256]; 43 | extern uint8_t bspid; -------------------------------------------------------------------------------- /src/include/apic/madt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | extern uint8_t lapic_ids[256]; 7 | extern uint8_t numcore; 8 | extern uint64_t lapic_ptr; 9 | extern uint64_t ioapic_ptr; 10 | 11 | void parse_madt(uint8_t *ptr); -------------------------------------------------------------------------------- /src/include/assert.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //#define ASSERT_NO_PANIC 4 | 5 | void __assert_fail(const char* __assertion, const char* __file, unsigned int __line); 6 | void __assert_fail_nopanic(const char* __assertion, const char* __file, unsigned int __line); 7 | 8 | #ifndef ASSERT_NO_PANIC 9 | #define assert(expr) if(!(expr)) __assert_fail(#expr, __FILE__, __LINE__); 10 | #else 11 | #define assert(expr) if(!(expr)) { __assert_fail_nopanic(#expr, __FILE__, __LINE__); goto assert_fail; } 12 | #endif -------------------------------------------------------------------------------- /src/include/bitmap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Bitmap{ 7 | public: 8 | size_t size; 9 | uint8_t* buffer; 10 | bool operator[](uint64_t index); 11 | bool get(uint64_t index); 12 | bool set(uint64_t index, bool value); 13 | }; -------------------------------------------------------------------------------- /src/include/bootinfo.h: -------------------------------------------------------------------------------- 1 | #ifndef BOOTINFO_H 2 | #define BOOTINFO_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | struct bootinfo_t { 13 | psf1_font_t* font; 14 | framebuffer_t* framebuffer; 15 | efi_memory_descriptor_t* m_map; 16 | uint64_t m_map_size; 17 | uint64_t m_map_desc_size; 18 | pci::acpi::rsdp2_t* rsdp; 19 | }; 20 | 21 | #endif -------------------------------------------------------------------------------- /src/include/cmdline.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | typedef void (*cmdline_handler)(char*); 6 | 7 | class CmdLineParser: public list { 8 | public: 9 | CmdLineParser(); 10 | ~CmdLineParser(); 11 | 12 | void add_handler(char* name, cmdline_handler handler); 13 | void parse(char* cmdline); 14 | }; 15 | -------------------------------------------------------------------------------- /src/include/config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #define VERSION 1 12 | #define RELEASE_T "Alpha" 13 | #define VENDOR "TheUltimateFoxOS" 14 | #define HOSTNAME (char*) "FoxOS" 15 | 16 | #define MAX_FILE_NAME_SIZE 128 17 | #define MAX_VFS_NODES 255 18 | 19 | extern bool NO_SMP_SHED; 20 | #define SEND_SIGNALS 21 | #define USE_STIVALE2_SMP 22 | #define TASK_STACK_PAGES 64 23 | 24 | //#define SERIAL_TO_SCREEN_REDIRECT 25 | 26 | /* Only enable if you know why this is a experimental feature */ 27 | //#define XSAVE_SUPPORT 28 | 29 | #define AUTOEXEC_PATH "root:/bin/terminal.elf" 30 | 31 | struct symbol { 32 | uint64_t addr; 33 | char* name; 34 | }; 35 | 36 | extern ElfSymbolResolver* elf_symbol_resolver; 37 | 38 | void register_symbol_resolver(ElfSymbolResolver* resolver); 39 | 40 | void set_no_smp_shed(char* _); 41 | struct patch_t { 42 | void* old_addr; 43 | uint8_t old_code[13]; 44 | }; 45 | 46 | struct stack_frame_t { 47 | struct stack_frame_t* rbp; 48 | uint64_t rip; 49 | } __attribute__((packed)); 50 | 51 | void unwind(int max, uint64_t rbp, void (*callback)(int frame_num, uint64_t rip)); 52 | 53 | uint64_t resolve_symbol(char* name); 54 | char* resolve_symbol(uint64_t address); 55 | 56 | patch_t* patch(char* name, uint64_t new_func); 57 | void unpatch(patch_t* patch); 58 | #endif 59 | -------------------------------------------------------------------------------- /src/include/cstr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | const char* to_string(uint64_t value); 6 | const char* to_string(int64_t value); 7 | const char* to_hstring(uint64_t value); 8 | const char* to_hstring(uint32_t value); 9 | const char* to_hstring(uint16_t value); 10 | const char* to_hstring(uint8_t value); 11 | const char* to_string(double value, uint8_t decimalPlaces); 12 | const char* to_string(double value); -------------------------------------------------------------------------------- /src/include/disassembler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | unsigned int disassemble(unsigned char *bytes, unsigned int max, int offset, char *output); -------------------------------------------------------------------------------- /src/include/driver/cmos.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #define CMOS_READ_SEC 0x00 7 | #define CMOS_READ_MIN 0x02 8 | #define CMOS_READ_HOUR 0x04 9 | #define CMOD_READ_WEEKDAY 0x06 10 | #define CMOS_READ_DAY 0x07 11 | #define CMOS_READ_MONTH 0x08 12 | #define CMOS_READ_YEAR 0x09 13 | #define CMOS_READ_CENTURY 0x32 14 | 15 | typedef struct { 16 | int function; 17 | } cmos_data_t; 18 | 19 | namespace driver { 20 | uint8_t cmos_read(uint8_t address); 21 | static uint8_t convert(uint8_t num); 22 | int cmos(uint8_t function); 23 | uint32_t get_fattime(); 24 | } -------------------------------------------------------------------------------- /src/include/driver/disk/ahci/ahci.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace driver { 11 | #define ATA_DEV_BUSY 0x80 12 | #define ATA_DEV_DRQ 0x08 13 | #define ATA_CMD_READ_DMA_EX 0x25 14 | #define ATA_CMD_WRITE_DMA_EX 0x35 15 | 16 | #define HBA_PxIS_TFES (1 << 30) 17 | 18 | enum port_type_t { 19 | None = 0, 20 | SATA = 1, 21 | SEMB = 2, 22 | PM = 3, 23 | SATAPI = 4, 24 | }; 25 | 26 | enum FIS_TYPE{ 27 | FIS_TYPE_REG_H2D = 0x27, 28 | FIS_TYPE_REG_D2H = 0x34, 29 | FIS_TYPE_DMA_ACT = 0x39, 30 | FIS_TYPE_DMA_SETUP = 0x41, 31 | FIS_TYPE_DATA = 0x46, 32 | FIS_TYPE_BIST = 0x58, 33 | FIS_TYPE_PIO_SETUP = 0x5F, 34 | FIS_TYPE_DEV_BITS = 0xA1, 35 | }; 36 | 37 | struct HBA_port { 38 | uint32_t command_list_base; 39 | uint32_t command_list_base_upper; 40 | uint32_t fis_base_address; 41 | uint32_t fis_base_address_upper; 42 | uint32_t interrupt_status; 43 | uint32_t interrupt_enable; 44 | uint32_t cmd_sts; 45 | uint32_t rsv0; 46 | uint32_t task_file_data; 47 | uint32_t signature; 48 | uint32_t sata_status; 49 | uint32_t sata_control; 50 | uint32_t sata_error; 51 | uint32_t sata_active; 52 | uint32_t command_issue; 53 | uint32_t sata_notification; 54 | uint32_t fis_switch_control; 55 | uint32_t rsv1[11]; 56 | uint32_t vendor[4]; 57 | }; 58 | 59 | struct HBA_memory { 60 | uint32_t host_capability; 61 | uint32_t global_host_control; 62 | uint32_t interrupt_status; 63 | uint32_t ports_implemented; 64 | uint32_t version; 65 | uint32_t ccc_control; 66 | uint32_t ccc_ports; 67 | uint32_t enclosure_management_location; 68 | uint32_t enclosure_management_control; 69 | uint32_t host_capabilities_extended; 70 | uint32_t bios_handoff_ctrl_sts; 71 | uint8_t rsv0[0x74]; 72 | uint8_t vendor[0x60]; 73 | HBA_port ports[1]; 74 | }; 75 | 76 | struct HBA_command_header { 77 | uint8_t command_fis_length:5; 78 | uint8_t atapi:1; 79 | uint8_t write:1; 80 | uint8_t prefetchable:1; 81 | 82 | uint8_t reset:1; 83 | uint8_t bist:1; 84 | uint8_t clear_busy:1; 85 | uint8_t rsv0:1; 86 | uint8_t port_multiplier:4; 87 | 88 | uint16_t prdt_length; 89 | uint32_t prdb_count; 90 | uint32_t command_table_base_address; 91 | uint32_t command_table_base_address_upper; 92 | uint32_t rsv1[4]; 93 | }; 94 | 95 | struct HBA_PRDT_entry{ 96 | uint32_t data_base_address; 97 | uint32_t data_base_address_upper; 98 | uint32_t rsv0; 99 | 100 | uint32_t byte_count:22; 101 | uint32_t rsv1:9; 102 | uint32_t interrupt_on_completion:1; 103 | }; 104 | 105 | struct HBA_command_table{ 106 | uint8_t command_fis[64]; 107 | 108 | uint8_t atapi_command[16]; 109 | 110 | uint8_t rsv[48]; 111 | 112 | HBA_PRDT_entry prdt_entry[]; 113 | }; 114 | 115 | struct FIS_REG_H2D { 116 | uint8_t fis_type; 117 | 118 | uint8_t port_multiplier:4; 119 | uint8_t rsv0:3; 120 | uint8_t command_control:1; 121 | 122 | uint8_t command; 123 | uint8_t feature_low; 124 | 125 | uint8_t lba0; 126 | uint8_t lba1; 127 | uint8_t lba2; 128 | uint8_t device_register; 129 | 130 | uint8_t lba3; 131 | uint8_t lba4; 132 | uint8_t lba5; 133 | uint8_t feature_high; 134 | 135 | uint8_t count_low; 136 | uint8_t count_high; 137 | uint8_t iso_command_completion; 138 | uint8_t control; 139 | 140 | uint8_t rsv1[4]; 141 | }; 142 | 143 | 144 | class AHCI_port : public disk::Disk { 145 | public: 146 | HBA_port* hba_port; 147 | port_type_t port_type; 148 | uint8_t* buffer; 149 | uint8_t port_number; 150 | 151 | void configure(); 152 | void stop_command(); 153 | void start_command(); 154 | 155 | virtual void read(uint64_t sector, uint32_t sector_count, void* buffer); 156 | virtual void write(uint64_t sector, uint32_t sector_count, void* buffer); 157 | }; 158 | 159 | class AHCI : public Driver { 160 | public: 161 | AHCI(pci::pci_device_header_t* pci_base_address); 162 | ~AHCI(); 163 | 164 | pci::pci_device_header_t* pci_base_address; 165 | HBA_memory* ABAR; 166 | void probe_ports(); 167 | 168 | AHCI_port* ports[32]; 169 | uint8_t port_count; 170 | 171 | }; 172 | } -------------------------------------------------------------------------------- /src/include/driver/disk/ata.h: -------------------------------------------------------------------------------- 1 | #ifndef ATA_H 2 | #define ATA_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace driver { 11 | 12 | class AdvancedTechnologyAttachment: public Driver, public disk::Disk { 13 | private: 14 | bool master; 15 | Port16Bit dataPort; 16 | Port8Bit error_port; 17 | Port8Bit sector_count_port; 18 | Port8Bit lba_low_port; 19 | Port8Bit lba_mid_port; 20 | Port8Bit lba_hi_port; 21 | Port8Bit device_port; 22 | Port8Bit command_port; 23 | Port8Bit control_port; 24 | 25 | uint16_t bytes_per_sector; 26 | 27 | char* name; 28 | 29 | public: 30 | AdvancedTechnologyAttachment(bool master, uint16_t portBase, char* name); 31 | ~AdvancedTechnologyAttachment(); 32 | 33 | 34 | void read28(uint32_t sector, uint8_t* data, int count); 35 | void write28(uint32_t sectorNum, uint8_t* data, uint32_t count); 36 | void flush(); 37 | 38 | virtual void activate(); 39 | virtual bool is_presend(); 40 | virtual char* get_name(); 41 | 42 | virtual void read(uint64_t sector, uint32_t sector_count, void* buffer); 43 | virtual void write(uint64_t sector, uint32_t sector_count, void* buffer); 44 | }; 45 | 46 | } 47 | 48 | #endif -------------------------------------------------------------------------------- /src/include/driver/disk/disk.h: -------------------------------------------------------------------------------- 1 | #ifndef DISK_H 2 | #define DISK_H 3 | 4 | #include 5 | 6 | #define DISK_NUM 265 7 | 8 | namespace driver { 9 | namespace disk { 10 | class Disk { 11 | public: 12 | Disk(); 13 | ~Disk(); 14 | virtual void read(uint64_t sector, uint32_t sector_count, void* buffer); 15 | virtual void write(uint64_t sector, uint32_t sector_count, void* buffer); 16 | }; 17 | 18 | class DiskManager { 19 | private: 20 | Disk* disks[DISK_NUM]; 21 | public: 22 | int num_disks; 23 | DiskManager(); 24 | 25 | void read(int disk_num, uint64_t sector, uint32_t sector_count, void* buffer); 26 | void write(int disk_num, uint64_t sector, uint32_t sector_count, void* buffer); 27 | 28 | void add_disk(Disk* disk); 29 | }; 30 | 31 | extern DiskManager* global_disk_manager; 32 | } 33 | } 34 | 35 | #endif -------------------------------------------------------------------------------- /src/include/driver/disk/virtual_disk.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace driver { 6 | 7 | class VirtualDisk : public disk::Disk { 8 | private: 9 | disk::Disk* disk; 10 | 11 | uint64_t lba_offset; 12 | 13 | public: 14 | VirtualDisk(disk::Disk* disk, uint64_t lba_offset); 15 | ~VirtualDisk(); 16 | 17 | virtual void read(uint64_t sector, uint32_t sector_count, void* buffer); 18 | virtual void write(uint64_t sector, uint32_t sector_count, void* buffer); 19 | }; 20 | } -------------------------------------------------------------------------------- /src/include/driver/driver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define DRIVER_NUM 256 6 | 7 | namespace driver { 8 | 9 | class Driver { 10 | public: 11 | Driver(); 12 | ~Driver(); 13 | 14 | virtual void activate(); 15 | virtual bool is_presend(); 16 | virtual char* get_name(); 17 | }; 18 | 19 | class DriverManager { 20 | private: 21 | Driver* drivers[DRIVER_NUM]; 22 | int num_drivers; 23 | 24 | public: 25 | DriverManager(); 26 | void add_driver(Driver* driver); 27 | void set_status(char* status, uint64_t color); 28 | void activate_driver(bool force, Driver* driver); 29 | void activate_all(bool force); 30 | 31 | Driver* find_driver_by_name(char* name); 32 | }; 33 | 34 | extern DriverManager* global_driver_manager; 35 | } -------------------------------------------------------------------------------- /src/include/driver/keyboard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | namespace driver { 11 | enum keyboard_layout { 12 | keymap_de_e = 0, 13 | keymap_fr_e = 1, 14 | keymap_us_e = 2 15 | }; 16 | 17 | enum special_key { 18 | left_shift, 19 | left_ctrl, 20 | left_alt, 21 | left_gui, 22 | 23 | right_shift, 24 | right_control, 25 | right_alt, 26 | right_gui, 27 | 28 | caps_lock, 29 | num_lock, 30 | scroll_lock, 31 | 32 | up_arrow, 33 | down_arrow, 34 | left_arrow, 35 | right_arrow, 36 | }; 37 | 38 | class KeyboardEventHandler { 39 | public: 40 | KeyboardEventHandler(); 41 | 42 | virtual void KeyDown(char c); 43 | virtual void SpecialKeyDown(special_key key); 44 | virtual void SpecialKeyUp(special_key key); 45 | }; 46 | 47 | class KeyboardDriver : public Driver, public interrupts::InterruptHandler { 48 | private: 49 | Port8Bit dataport; 50 | Port8Bit commandport; 51 | 52 | KeyboardEventHandler* handler; 53 | 54 | public: 55 | KeyboardDriver(KeyboardEventHandler* handler); 56 | ~KeyboardDriver(); 57 | 58 | uint8_t keymap; 59 | 60 | bool l_shift = false; 61 | bool r_shift = false; 62 | bool caps_lock = false; 63 | 64 | bool extended_ascii = false; 65 | 66 | bool debug_mode = false; 67 | 68 | virtual void handle(); 69 | virtual bool is_presend(); 70 | virtual void activate(); 71 | virtual char* get_name(); 72 | }; 73 | } -------------------------------------------------------------------------------- /src/include/driver/mouse.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | #define PS2XSign 0b00010000 11 | #define PS2YSign 0b00100000 12 | #define PS2XOverflow 0b01000000 13 | #define PS2YOverflow 0b10000000 14 | 15 | enum MouseButtons { 16 | LeftButton = 1, 17 | RightButton = 2, 18 | MiddleButton = 3 19 | }; 20 | 21 | namespace driver { 22 | class MouseEventHandler { 23 | public: 24 | MouseEventHandler(); 25 | virtual void OnMouseDown(uint8_t button); 26 | virtual void OnMouseMove(uint8_t mouse_packet[4]); 27 | }; 28 | 29 | class MouseDriver : public Driver, public interrupts::InterruptHandler { 30 | private: 31 | Port8Bit dataport; 32 | Port8Bit commandport; 33 | 34 | MouseEventHandler* handler; 35 | 36 | void MouseWait(); 37 | void MouseWaitInput(); 38 | void MouseWrite(uint8_t value); 39 | uint8_t MouseRead(); 40 | 41 | uint8_t mouse_cycle = 0; 42 | uint8_t mouse_packet[4]; 43 | bool mouse_packet_ready = false; 44 | 45 | public: 46 | MouseDriver(MouseEventHandler* handler); 47 | ~MouseDriver(); 48 | 49 | virtual void handle(); 50 | virtual bool is_presend(); 51 | virtual void activate(); 52 | virtual char* get_name(); 53 | }; 54 | } -------------------------------------------------------------------------------- /src/include/driver/nic/am79C973.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace driver{ 9 | class Am79C973Driver: public Driver, public interrupts::InterruptHandler, public nic::Nic { 10 | 11 | public: 12 | struct initialization_block_t { 13 | uint16_t mode; 14 | unsigned reserved1 : 4; 15 | unsigned numSendBuffers : 4; 16 | unsigned reserved2 : 4; 17 | unsigned numRecvBuffers : 4; 18 | uint64_t physicalAddress : 48; 19 | uint16_t reserved3; 20 | uint64_t logicalAddress; 21 | uint32_t recvBufferDescrAddress; 22 | uint32_t sendBufferDescrAddress; 23 | } __attribute__((packed)); 24 | 25 | struct buffer_descriptor_t { 26 | uint32_t address; 27 | uint32_t flags; 28 | uint32_t flags2; 29 | uint32_t avail; 30 | } __attribute__((packed)); 31 | 32 | Am79C973Driver(pci::pci_header_0_t* header, uint16_t bus, uint16_t device, uint16_t function); 33 | ~Am79C973Driver(); 34 | 35 | virtual void send(uint8_t* data, int32_t len); 36 | virtual uint64_t get_mac(); 37 | 38 | virtual uint32_t get_ip(); 39 | virtual void set_ip(uint32_t ip); 40 | 41 | private: 42 | pci::pci_header_0_t* header; 43 | uint16_t base_port; 44 | 45 | buffer_descriptor_t* sendBufferDescr; 46 | uint8_t* sendBufferDescrMemory; 47 | uint8_t* sendBuffers; 48 | uint8_t currentSendBuffer; 49 | 50 | buffer_descriptor_t* recvBufferDescr; 51 | uint8_t* recvBufferDescrMemory; 52 | uint8_t* recvBuffers; 53 | uint8_t currentRecvBuffer; 54 | 55 | initialization_block_t* init_block; 56 | 57 | virtual void handle(); 58 | virtual void activate(); 59 | virtual char* get_name(); 60 | 61 | void receive(); 62 | }; 63 | } 64 | -------------------------------------------------------------------------------- /src/include/driver/nic/nic.h: -------------------------------------------------------------------------------- 1 | #ifndef Nic_H 2 | #define Nic_H 3 | 4 | #include 5 | // #include 6 | 7 | #define NIC_NUM 265 8 | 9 | typedef void (*nic_recv_handler)(uint8_t* data, uint32_t len); 10 | 11 | 12 | // i cant import net_stack.h here so just a void* 13 | namespace net { 14 | struct net_stack_t; 15 | } 16 | 17 | 18 | namespace driver { 19 | namespace nic { 20 | 21 | union ip_u { 22 | uint8_t ip_p[4]; 23 | uint32_t ip; 24 | }; 25 | 26 | union mac_u { 27 | uint8_t mac_p[6]; 28 | uint64_t mac: 48; 29 | }; 30 | 31 | class Nic; 32 | class NicDataManager { 33 | public: 34 | NicDataManager(int nic_id); 35 | ~NicDataManager(); 36 | 37 | void send(uint8_t* data, int32_t len); 38 | virtual bool recv(uint8_t* data, int32_t len); 39 | 40 | Nic* nic; 41 | int nic_id; 42 | }; 43 | class Nic { 44 | public: 45 | Nic(); 46 | ~Nic(); 47 | virtual void send(uint8_t* data, int32_t len); 48 | 49 | virtual void register_nic_data_manager(NicDataManager* nic_data_manager); 50 | virtual uint64_t get_mac(); 51 | 52 | virtual uint32_t get_ip(); 53 | virtual void set_ip(uint32_t ip); 54 | 55 | NicDataManager* nic_data_manager; 56 | net::net_stack_t* network_stack; 57 | 58 | void load_network_stack(net::net_stack_t* network_stack); 59 | }; 60 | 61 | class NicManager { 62 | private: 63 | Nic* Nics[NIC_NUM]; 64 | public: 65 | int num_Nics; 66 | NicManager(); 67 | 68 | Nic* get_nic(int nic_id); 69 | void add_Nic(Nic* Nic); 70 | }; 71 | 72 | extern NicManager* global_nic_manager; 73 | } 74 | } 75 | 76 | #endif -------------------------------------------------------------------------------- /src/include/driver/pc_speaker.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace driver { 4 | 5 | class PcSpeakerDriver : public Driver { 6 | public: 7 | PcSpeakerDriver(); 8 | ~PcSpeakerDriver(); 9 | 10 | void turn_on(); 11 | void turn_off(); 12 | 13 | void set_frequency(uint16_t frequency); 14 | void play(uint16_t frequency); 15 | 16 | void play_note(uint8_t note); // (octave << 4) | note 17 | 18 | virtual void activate(); 19 | virtual bool is_presend(); 20 | virtual char* get_name(); 21 | }; 22 | } -------------------------------------------------------------------------------- /src/include/driver/serial.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define COM1 0x3f8 8 | 9 | namespace driver { 10 | class Serial { 11 | 12 | private: 13 | Port8Bit port; 14 | 15 | int serial_recieved(); 16 | int is_transmit_empty(); 17 | 18 | public: 19 | Serial(uint16_t port_n); 20 | 21 | char read_serial(); 22 | void write_serial(char a); 23 | void write_serial(const char* str); 24 | 25 | void putc(char c); 26 | void puts(const char *s); 27 | void putn(unsigned long x, int base); 28 | void printf(const char* fmt, ...); 29 | }; 30 | 31 | extern Serial* global_serial_driver; 32 | } -------------------------------------------------------------------------------- /src/include/efi_mem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct efi_memory_descriptor_t { 6 | uint32_t type; 7 | void* phys_addr; 8 | void* virt_addr; 9 | uint64_t num_pages; 10 | uint64_t attribs; 11 | }; 12 | 13 | extern const char* efi_memory_type_strings[]; -------------------------------------------------------------------------------- /src/include/fs/fat32/diskio.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------/ 2 | / FatFs - Generic FAT Filesystem Module Rx.xx / 3 | /-----------------------------------------------------------------------------/ 4 | / 5 | / Copyright (C) 20xx, ChaN, all right reserved. 6 | / 7 | / FatFs module is an open source software. Redistribution and use of FatFs in 8 | / source and binary forms, with or without modification, are permitted provided 9 | / that the following condition is met: 10 | / 11 | / 1. Redistributions of source code must retain the above copyright notice, 12 | / this condition and the following disclaimer. 13 | / 14 | / This software is provided by the copyright holder and contributors "AS IS" 15 | / and any warranties related to this software are DISCLAIMED. 16 | / The copyright owner or contributors be NOT LIABLE for any damages caused 17 | / by use of this software. 18 | /----------------------------------------------------------------------------*/ 19 | 20 | /*-----------------------------------------------------------------------/ 21 | / Low level disk interface modlue include file (C)ChaN, 2019 / 22 | /-----------------------------------------------------------------------*/ 23 | 24 | #ifndef _DISKIO_DEFINED 25 | #define _DISKIO_DEFINED 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | /* Status of Disk Functions */ 32 | typedef BYTE DSTATUS; 33 | 34 | /* Results of Disk Functions */ 35 | typedef enum { 36 | RES_OK = 0, /* 0: Successful */ 37 | RES_ERROR, /* 1: R/W Error */ 38 | RES_WRPRT, /* 2: Write Protected */ 39 | RES_NOTRDY, /* 3: Not Ready */ 40 | RES_PARERR /* 4: Invalid Parameter */ 41 | } DRESULT; 42 | 43 | 44 | /*---------------------------------------*/ 45 | /* Prototypes for disk control functions */ 46 | 47 | 48 | DSTATUS disk_initialize (BYTE pdrv); 49 | DSTATUS disk_status (BYTE pdrv); 50 | DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count); 51 | DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count); 52 | DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); 53 | 54 | 55 | /* Disk Status Bits (DSTATUS) */ 56 | 57 | #define STA_NOINIT 0x01 /* Drive not initialized */ 58 | #define STA_NODISK 0x02 /* No medium in the drive */ 59 | #define STA_PROTECT 0x04 /* Write protected */ 60 | 61 | 62 | /* Command code for disk_ioctrl fucntion */ 63 | 64 | /* Generic command (Used by FatFs) */ 65 | #define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ 66 | #define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ 67 | #define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ 68 | #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ 69 | #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ 70 | 71 | /* Generic command (Not used by FatFs) */ 72 | #define CTRL_POWER 5 /* Get/Set power status */ 73 | #define CTRL_LOCK 6 /* Lock/Unlock media removal */ 74 | #define CTRL_EJECT 7 /* Eject media */ 75 | #define CTRL_FORMAT 8 /* Create physical format on the media */ 76 | 77 | /* MMC/SDC specific ioctl command */ 78 | #define MMC_GET_TYPE 10 /* Get card type */ 79 | #define MMC_GET_CSD 11 /* Get CSD */ 80 | #define MMC_GET_CID 12 /* Get CID */ 81 | #define MMC_GET_OCR 13 /* Get OCR */ 82 | #define MMC_GET_SDSTAT 14 /* Get SD status */ 83 | #define ISDIO_READ 55 /* Read data form SD iSDIO register */ 84 | #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ 85 | #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ 86 | 87 | /* ATA/CF specific ioctl command */ 88 | #define ATA_GET_REV 20 /* Get F/W revision */ 89 | #define ATA_GET_MODEL 21 /* Get model name */ 90 | #define ATA_GET_SN 22 /* Get serial number */ 91 | 92 | #ifdef __cplusplus 93 | } 94 | #endif 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /src/include/fs/fat32/vfs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | vfs_mount* initialise_fat32(int disk_id); 7 | 8 | FILE* fat32_open(vfs_mount* node, const char* file, const char* mode); 9 | int fat32_close(vfs_mount* node, file_t* stream); 10 | 11 | size_t fat32_read(vfs_mount*, void* buffer, size_t size, size_t nmemb, file_t* stream); 12 | size_t fat32_write(vfs_mount*, void* buffer, size_t size, size_t nmemb, file_t* stream); 13 | 14 | void fat32_mount(vfs_mount* node); 15 | void fat32_unmount(vfs_mount* node); 16 | 17 | DIR* fat32_opendir(vfs_mount* node, const char* name); 18 | int fat32_closedir(vfs_mount*, DIR* stream); 19 | struct dirent* fat32_readdir(vfs_mount*, DIR* stream); 20 | void fat32_rewinddir(vfs_mount*, DIR* stream); 21 | 22 | int fat32_seek(vfs_mount*, file_t* file, long int offset, int whence); 23 | long int fat32_tell(vfs_mount*, file_t* file); 24 | 25 | int fat32_mkdir(vfs_mount*, const char* name, uint32_t); 26 | int fat32_unlink(vfs_mount*, const char* name); 27 | int fat32_rename(vfs_mount*, const char* old_name, const char* new_name); 28 | -------------------------------------------------------------------------------- /src/include/fs/fd.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace fd { 7 | class FileDescriptor { 8 | public: 9 | int fd; 10 | 11 | FileDescriptor(int fd); 12 | ~FileDescriptor(); 13 | 14 | void close(); 15 | void open(const char* file, const char* mode); 16 | void read(void* buffer, size_t size, size_t nmemb); 17 | void write(void* buffer, size_t size, size_t nmemb); 18 | 19 | file_t* file; 20 | }; 21 | 22 | class FileDescriptorManager { 23 | public: 24 | FileDescriptorManager(); 25 | ~FileDescriptorManager(); 26 | 27 | listv2 fds; 28 | 29 | int curr_fd = 0; 30 | 31 | int alloc_fd(); 32 | void free_fd(int fd); 33 | void register_fd(FileDescriptor* fd_obj); 34 | FileDescriptor* get_fd(int fd); 35 | }; 36 | 37 | extern FileDescriptorManager* fdm; 38 | } -------------------------------------------------------------------------------- /src/include/fs/gpt/gpt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace gpt { 7 | struct gpt_guid { 8 | uint32_t data1; 9 | uint16_t data2; 10 | uint16_t data3; 11 | uint64_t data4; 12 | } __attribute__((packed)); 13 | 14 | struct gpt_header { 15 | char signature[8]; 16 | uint8_t revision[4]; 17 | uint32_t header_size; 18 | uint32_t crc32; 19 | uint32_t reserved; 20 | uint64_t current_lba; 21 | uint64_t backup_lba; 22 | uint64_t first_usable_lba; 23 | uint64_t last_usable_lba; 24 | gpt_guid guid; 25 | uint64_t partition_entries_startting_lba; 26 | uint32_t partition_entries_count; 27 | uint32_t partition_entries_size; 28 | uint32_t partition_entry_array_crc32; 29 | } __attribute__((packed)); 30 | 31 | struct gpt_partition_entry { 32 | gpt_guid type_guid; 33 | gpt_guid partition_guid; 34 | uint64_t first_lba; 35 | uint64_t last_lba; 36 | uint16_t partition_name[36]; 37 | } __attribute__((packed)); 38 | 39 | bool read_gpt(driver::disk::Disk* disk); 40 | } -------------------------------------------------------------------------------- /src/include/fs/stivale/vfs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | vfs_mount* initialise_stivale_modules(stivale2_struct* bootinfo); 7 | 8 | FILE* stivale_modules_open(vfs_mount* node, const char* file, const char* mode); 9 | int stivale_modules_close(vfs_mount* node, file_t* stream); 10 | 11 | int stivale_modules_seek(vfs_mount*, file_t* file, long int offset, int whence); 12 | long int stivale_modules_tell(vfs_mount*, file_t* file); 13 | 14 | size_t stivale_modules_read(vfs_mount*, void* buffer, size_t size, size_t nmemb, file_t* stream); 15 | 16 | void stivale_modules_mount(vfs_mount* node); 17 | -------------------------------------------------------------------------------- /src/include/fs/vfs/list.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct list_node_t { 4 | void* data1; 5 | void* data2; 6 | void* data3; 7 | void* data4; 8 | 9 | bool is_taken; 10 | }; 11 | 12 | typedef bool (*search_function)(list_node_t* node, void* d1, void* d2, void* d3, void* d4); 13 | 14 | class list { 15 | private: 16 | list_node_t* nodes; 17 | int node_count; 18 | 19 | public: 20 | list(int max_len); 21 | ~list(); 22 | 23 | list_node_t* find_node(search_function f, void* d1, void* d2, void* d3, void* d4); 24 | void remove_node(list_node_t* node); 25 | list_node_t* add_node(void* d1, void* d2, void* d3, void* d4); 26 | }; -------------------------------------------------------------------------------- /src/include/fs/vfs/vfs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | struct file_t; 10 | struct dir_t; 11 | struct dirent; 12 | struct vfs_mount; 13 | 14 | enum seek_type { 15 | SEEK_SET = 1, 16 | SEEK_CUR, 17 | SEEK_END 18 | }; 19 | 20 | typedef file_t* (*open_type_t)(vfs_mount*, const char*, const char*); 21 | typedef int (*close_type_t)(vfs_mount*, file_t*); 22 | typedef size_t (*read_type_t)(vfs_mount*, void*, size_t, size_t, file_t*); 23 | typedef size_t (*write_type_t)(vfs_mount*, void*, size_t, size_t, file_t*); 24 | 25 | typedef int (*seek_type_t)(vfs_mount*, file_t*, long int, int); 26 | typedef long int (*tell_type_t)(vfs_mount*, file_t*); 27 | 28 | typedef dir_t* (*opendir_type_t)(vfs_mount*, const char*); 29 | typedef int (*closedir_type_t)(vfs_mount*, dir_t*); 30 | typedef struct dirent* (*readdir_type_t)(vfs_mount*, dir_t*); 31 | typedef void (*rewinddir_type_t)(vfs_mount*, dir_t*); 32 | 33 | typedef int (*mkdir_type_t)(vfs_mount*, const char*, uint32_t); 34 | typedef int (*unlink_type_t)(vfs_mount*, const char*); 35 | typedef int (*rename_type_t)(vfs_mount*, const char*, const char*); 36 | 37 | typedef void (*mount_type_t)(vfs_mount*); 38 | typedef void (*unmount_type_t)(vfs_mount*); 39 | 40 | 41 | struct vfs_mount { 42 | void* data; 43 | uint64_t data2; 44 | 45 | list_node_t* node; 46 | 47 | read_type_t read; 48 | write_type_t write; 49 | open_type_t open; 50 | close_type_t close; 51 | 52 | opendir_type_t opendir; 53 | closedir_type_t closedir; 54 | readdir_type_t readdir; 55 | rewinddir_type_t rewinddir; 56 | 57 | seek_type_t seek; 58 | tell_type_t tell; 59 | 60 | mkdir_type_t mkdir; 61 | unlink_type_t unlink; 62 | rename_type_t rename; 63 | 64 | mount_type_t mount; 65 | unmount_type_t unmount; 66 | }; 67 | 68 | typedef struct file_t { 69 | int inner_fd; 70 | int is_readable; 71 | int is_writable; 72 | int is_eof; 73 | int is_error; 74 | size_t buffer_base; 75 | size_t bytes_in_buffer; 76 | size_t buffer_i; 77 | char buffer[512]; 78 | 79 | size_t size; 80 | void* data; 81 | vfs_mount* mount; 82 | long int pos; 83 | } FILE; 84 | 85 | typedef struct dir_t { 86 | int is_error; 87 | 88 | void* data; 89 | vfs_mount* mount; 90 | } DIR; 91 | 92 | struct dirent { 93 | char name[MAX_FILE_NAME_SIZE]; 94 | uint32_t ino; 95 | }; 96 | 97 | enum vfs_result { 98 | VFS_OK = 0, //Everyting is ok 99 | VFS_ERROR, //Undefined error 100 | VFS_NOT_IMPLEMENTED, //The action is not implemented 101 | VFS_MOUNT_ERROR, //Unable to mount a node 102 | VFS_NO_NDOE, //The node trying to be accessed is null 103 | VFS_MISSING_FUNCTION, //A VFS driver function is missing 104 | VFS_FILE_NOT_FOUND //A file was not found 105 | }; 106 | 107 | vfs_result mount(vfs_mount* mount, char* name); 108 | char* mount(vfs_mount* node_mount); 109 | vfs_result unmount(char* name); 110 | FILE* fopen(const char* filename, const char* mode); 111 | int fclose(FILE* stream); 112 | size_t fwrite(void* ptr, size_t size, size_t nmemb, FILE* stream); 113 | size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream); 114 | 115 | DIR* opendir(const char* name); 116 | int closedir(DIR* stream); 117 | struct dirent* readdir(DIR* stream); 118 | void rewinddir(DIR* stream); 119 | 120 | int fseek(FILE* stream, long int offset, int whence); 121 | long int ftell(FILE* stream); 122 | 123 | int mkdir(const char* name, uint32_t mode); 124 | int unlink(const char* name); 125 | int rename(const char* old_name, const char* new_name); 126 | int copy(const char* src_name, const char* dest_name); -------------------------------------------------------------------------------- /src/include/gdt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct gdt_descriptor_t { 6 | uint16_t size; 7 | uint64_t offset; 8 | } __attribute__((packed)); 9 | 10 | struct gdt_entry_t { 11 | uint16_t limit0; 12 | uint16_t base0; 13 | uint8_t base1; 14 | uint8_t access_byte; 15 | uint8_t limit1_flags; 16 | uint8_t base2; 17 | }__attribute__((packed)); 18 | 19 | struct gdt_t { 20 | gdt_entry_t null; 21 | gdt_entry_t kernel_code; 22 | gdt_entry_t kernel_data; 23 | gdt_entry_t user_null; 24 | gdt_entry_t user_code; 25 | gdt_entry_t user_data; 26 | } __attribute__((packed)) 27 | __attribute((aligned(0x1000))); 28 | 29 | extern gdt_t default_gdt; 30 | extern "C" void load_gdt(gdt_descriptor_t* gdt_descriptor); 31 | -------------------------------------------------------------------------------- /src/include/init/init_procces.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern "C" void init_procces(); 4 | void set_autoexec(char* path); 5 | -------------------------------------------------------------------------------- /src/include/interrupts/idt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define idt_ta_interrupt_gate 0b10001110 6 | #define idt_ta_call_gate 0b10001100 7 | #define idt_ta_trap_gate 0b10001111 8 | 9 | namespace interrupts { 10 | 11 | struct idt_desc_entry_t { 12 | uint16_t offset0; 13 | uint16_t selector; 14 | uint8_t ist; 15 | uint8_t type_attr; 16 | uint16_t offset1; 17 | uint32_t offset2; 18 | uint32_t ignore; 19 | void set_offset(uint64_t offset); 20 | uint64_t get_offset(); 21 | }; 22 | 23 | struct idt_t { 24 | uint16_t limit; 25 | uint64_t offset; 26 | } __attribute__((packed)); 27 | } -------------------------------------------------------------------------------- /src/include/interrupts/interrupt_handler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | typedef void (*intr_handler_ptr)(uint8_t); 8 | 9 | namespace interrupts { 10 | class InterruptHandler { 11 | protected: 12 | uint8_t int_num; 13 | InterruptHandler(uint8_t int_num); 14 | ~InterruptHandler(); 15 | public: 16 | virtual void handle(); 17 | }; 18 | 19 | extern interrupts::InterruptHandler* handlers[256]; 20 | 21 | extern intr_handler_ptr static_handlers[256]; 22 | 23 | void register_interrupt_handler(uint8_t intr, intr_handler_ptr handler); 24 | } -------------------------------------------------------------------------------- /src/include/interrupts/interrupts.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #define PIC_EOI 0x20 7 | 8 | #define ICW1_INIT 0x10 9 | #define ICW1_ICW4 0x01 10 | #define ICW4_8086 0x01 11 | 12 | struct s_registers { 13 | uint64_t cr4; 14 | uint64_t cr3; 15 | uint64_t cr2; 16 | uint64_t cr0; 17 | uint64_t r15; 18 | uint64_t r14; 19 | uint64_t r13; 20 | uint64_t r12; 21 | uint64_t r11; 22 | uint64_t r10; 23 | uint64_t r9; 24 | uint64_t r8; 25 | uint64_t rdi; 26 | uint64_t rsi; 27 | uint64_t rbp; 28 | uint64_t rbx; 29 | uint64_t rdx; 30 | uint64_t rcx; 31 | uint64_t rax; 32 | uint64_t interrupt_number; 33 | uint64_t error_code; 34 | uint64_t rip; 35 | uint64_t cs; 36 | uint64_t rflags; 37 | uint64_t rsp; 38 | } __attribute__((packed)); 39 | 40 | extern "C" void intr_stub_0(void); 41 | extern "C" void intr_stub_1(void); 42 | extern "C" void intr_stub_2(void); 43 | extern "C" void intr_stub_3(void); 44 | extern "C" void intr_stub_4(void); 45 | extern "C" void intr_stub_5(void); 46 | extern "C" void intr_stub_6(void); 47 | extern "C" void intr_stub_7(void); 48 | extern "C" void intr_stub_8(void); 49 | extern "C" void intr_stub_9(void); 50 | extern "C" void intr_stub_10(void); 51 | extern "C" void intr_stub_11(void); 52 | extern "C" void intr_stub_12(void); 53 | extern "C" void intr_stub_13(void); 54 | extern "C" void intr_stub_14(void); 55 | extern "C" void intr_stub_15(void); 56 | extern "C" void intr_stub_16(void); 57 | extern "C" void intr_stub_17(void); 58 | extern "C" void intr_stub_18(void); 59 | 60 | extern "C" void intr_stub_32(void); 61 | extern "C" void intr_stub_33(void); 62 | extern "C" void intr_stub_34(void); 63 | extern "C" void intr_stub_35(void); 64 | extern "C" void intr_stub_36(void); 65 | extern "C" void intr_stub_37(void); 66 | extern "C" void intr_stub_38(void); 67 | extern "C" void intr_stub_39(void); 68 | extern "C" void intr_stub_40(void); 69 | extern "C" void intr_stub_41(void); 70 | extern "C" void intr_stub_42(void); 71 | extern "C" void intr_stub_43(void); 72 | extern "C" void intr_stub_44(void); 73 | extern "C" void intr_stub_45(void); 74 | extern "C" void intr_stub_46(void); 75 | extern "C" void intr_stub_47(void); 76 | 77 | extern "C" void intr_stub_48(void); -------------------------------------------------------------------------------- /src/include/interrupts/panic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace interrupts { 10 | 11 | class Panic { 12 | private: 13 | int intr; 14 | char* get_panic_message(); 15 | char* panic; 16 | 17 | public: 18 | Panic(int intr); 19 | Panic(char* panic); 20 | void dump_regs(s_registers* regs); 21 | void do_it(s_registers* regs); 22 | }; 23 | } -------------------------------------------------------------------------------- /src/include/kernel_info.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | extern uint64_t kernel_start; 8 | extern uint64_t kernel_end; 9 | 10 | struct KernelInfo { 11 | PageTableManager* page_table_manager; 12 | }; -------------------------------------------------------------------------------- /src/include/kmod.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct module_t { 6 | const char* name; 7 | void (*init)(); 8 | void* base_address; 9 | uint64_t loaded_pages; 10 | }; 11 | 12 | #define define_module(name, init) module_t __module__ { name, init, 0, 0 } 13 | 14 | void load_module(char* path); 15 | void load_module(void* module, uint32_t size); -------------------------------------------------------------------------------- /src/include/memory/heap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | struct HeapSegHdr{ 7 | size_t length; 8 | HeapSegHdr* next; 9 | HeapSegHdr* last; 10 | bool free; 11 | void combine_forward(); 12 | void combine_backward(); 13 | HeapSegHdr* split(size_t split_length); 14 | }; 15 | 16 | void initialize_heap(void* heap_address, size_t page_count); 17 | 18 | void* malloc(size_t size); 19 | void* realloc(void* ptr, size_t oldSize, size_t size); 20 | void free(void* address); 21 | 22 | void expand_heap(size_t length); 23 | 24 | inline void* operator new(size_t size) {return malloc(size);} 25 | inline void* operator new[](size_t size) {return malloc(size);} 26 | 27 | inline void operator delete(void* p, unsigned long) {free(p);} 28 | inline void operator delete[](void* p) {free(p);} -------------------------------------------------------------------------------- /src/include/memory/memory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | uint64_t get_memory_size(stivale2_struct* bootinfo); 7 | void memset(void* start, uint8_t value, uint64_t num); 8 | 9 | extern "C" void init_fast_mem(); -------------------------------------------------------------------------------- /src/include/mmio.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class MMIO { 6 | public: 7 | static uint8_t read8 (uint64_t p_address); 8 | static uint16_t read16 (uint64_t p_address); 9 | static uint32_t read32 (uint64_t p_address); 10 | static uint64_t read64 (uint64_t p_address); 11 | static void write8 (uint64_t p_address,uint8_t p_value); 12 | static void write16 (uint64_t p_address,uint16_t p_value); 13 | static void write32 (uint64_t p_address,uint32_t p_value); 14 | static void write64 (uint64_t p_address,uint64_t p_value); 15 | }; -------------------------------------------------------------------------------- /src/include/net/arp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace net { 5 | struct arp_message_t { 6 | uint16_t hardware_type; 7 | uint16_t protocol; 8 | uint8_t hardware_address_size; 9 | uint8_t protocol_address_size; 10 | uint16_t command; 11 | 12 | uint64_t src_mac: 48; 13 | uint32_t src_ip; 14 | uint64_t dest_mac: 48; 15 | uint32_t dest_ip; 16 | } __attribute__((packed)); 17 | 18 | class AddressResolutionProtocol : public EtherFrameHandler { 19 | private: 20 | uint32_t ip_cache[128]; 21 | uint64_t mac_cache[128]; 22 | int num_cache_entry; 23 | 24 | public: 25 | AddressResolutionProtocol(EtherFrameProvider* ether); 26 | ~AddressResolutionProtocol(); 27 | 28 | virtual bool onEtherFrameReceived(uint8_t* payload, uint32_t size); 29 | void broadcast_mac(uint32_t ip_be); 30 | void request_mac_address(uint32_t ip_be); 31 | uint64_t get_mac_from_cache(uint32_t ip_be); 32 | uint64_t resolve(uint32_t ip_be); 33 | }; 34 | } -------------------------------------------------------------------------------- /src/include/net/dhcp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace net { 6 | 7 | struct dhcp_packet_t { 8 | uint8_t op; 9 | uint8_t hardware_type; 10 | uint8_t hardware_addr_len; 11 | uint8_t hops; 12 | uint32_t xid; 13 | uint16_t seconds; 14 | uint16_t flags; 15 | uint32_t client_ip; 16 | uint32_t your_ip; 17 | uint32_t server_ip; 18 | uint32_t gateway_ip; 19 | uint8_t client_hardware_addr[16]; 20 | uint8_t server_name[64]; 21 | uint8_t file[128]; 22 | uint8_t options[64]; 23 | } __attribute__ ((packed)); 24 | 25 | #define DHCP_REQUEST 1 26 | #define DHCP_REPLY 2 27 | 28 | #define DHCP_TRANSACTION_IDENTIFIER 0x55555555 29 | 30 | class DhcpProtocol : public net::UdpHandler{ 31 | public: 32 | DhcpProtocol(UdpSocket* socket); 33 | ~DhcpProtocol(); 34 | 35 | void request(); 36 | void request(uint32_t ip); 37 | 38 | uint32_t ip; 39 | uint32_t gateway; 40 | uint32_t subnet; 41 | uint32_t dns; 42 | 43 | bool complete = false; 44 | 45 | virtual void onUdpMessage(UdpSocket *socket, uint8_t* data, size_t size); 46 | 47 | private: 48 | UdpSocket* socket; 49 | 50 | void make_dhcp_packet(dhcp_packet_t* packet, uint8_t msg_type, uint32_t request_ip); 51 | void* get_dhcp_options(dhcp_packet_t* packet, uint8_t type); 52 | }; 53 | } -------------------------------------------------------------------------------- /src/include/net/dns.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace net { 6 | 7 | struct dnshdr_t { 8 | uint16_t id, opts, qdcount, ancount, nscount, arcount; 9 | }; 10 | 11 | struct dns_question_t { 12 | uint16_t qtype, qclass; 13 | }; 14 | 15 | struct dns_resource_t { 16 | uint16_t type, _class; 17 | uint32_t ttl; 18 | uint16_t data_len; 19 | } __attribute__((packed)); 20 | 21 | struct dns_result_t { 22 | uint32_t ip; 23 | char name[64]; 24 | }; 25 | 26 | class DomainNameServiceProvider: public UdpHandler { 27 | public: 28 | DomainNameServiceProvider(UdpSocket* socket); 29 | ~DomainNameServiceProvider(); 30 | 31 | void resolv_domain_to_hostname(char* dst_hostname, char* src_domain); 32 | 33 | uint32_t resolve(char* name); 34 | void dns_request(char* name); 35 | 36 | virtual void onUdpMessage(UdpSocket *socket, uint8_t* data, size_t size); 37 | 38 | UdpSocket* socket; 39 | listv2 results; 40 | 41 | bool wait_for_response; 42 | }; 43 | } -------------------------------------------------------------------------------- /src/include/net/etherframe.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #define MAX_ETHER_FRAME_HANDLERS 65535 7 | 8 | namespace net { 9 | struct ether_frame_header_t { 10 | uint64_t dest_mac_be : 48; 11 | uint64_t src_mac_be : 48; 12 | uint16_t ether_type_be; 13 | } __attribute__((packed)); 14 | 15 | typedef uint32_t ether_frame_footer_t; 16 | 17 | class EtherFrameProvider; 18 | 19 | class EtherFrameHandler { 20 | public: 21 | EtherFrameProvider* backend; 22 | uint16_t ether_type_be; 23 | 24 | EtherFrameHandler(EtherFrameProvider* backend, uint16_t ether_type); 25 | ~EtherFrameHandler(); 26 | 27 | virtual bool onEtherFrameReceived(uint8_t* payload, uint32_t size); 28 | void send(uint64_t dest_mac_be, uint8_t* payload, uint32_t size); 29 | }; 30 | 31 | class EtherFrameProvider : public driver::nic::NicDataManager { 32 | public: 33 | listv2 handlers; 34 | 35 | EtherFrameProvider(int nic_id); 36 | ~EtherFrameProvider(); 37 | 38 | virtual bool recv(uint8_t* data, int32_t size) override; 39 | void send_f(uint64_t dest_mac_be, uint16_t ether_type_be, uint8_t* payload, uint32_t size); 40 | 41 | }; 42 | } -------------------------------------------------------------------------------- /src/include/net/icmp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace net { 5 | struct icmp_message_t { 6 | uint8_t type; 7 | uint8_t code; 8 | 9 | uint16_t checksum; 10 | uint32_t data; 11 | } __attribute__((packed)); 12 | 13 | class IcmpProvider : public Ipv4Handler { 14 | public: 15 | IcmpProvider(Ipv4Provider* ipv4); 16 | ~IcmpProvider(); 17 | 18 | virtual bool onInternetProtocolReceived(uint32_t srcIP_BE, uint32_t dstIP_BE, uint8_t* payload, uint32_t size); 19 | void send_echo_request(uint32_t dstIP_BE); 20 | }; 21 | } -------------------------------------------------------------------------------- /src/include/net/ipv4.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace net { 7 | struct ipv4_message_t { 8 | uint8_t header_length : 4; 9 | uint8_t version : 4; 10 | uint8_t type_of_service; 11 | uint16_t total_length; 12 | 13 | uint16_t identification; 14 | uint16_t flags_and_fragment_offset; 15 | 16 | uint8_t time_to_live; 17 | uint8_t protocol; 18 | uint16_t header_checksum; 19 | 20 | uint32_t source_address; 21 | uint32_t destination_address; 22 | }; 23 | 24 | class Ipv4Provider; 25 | 26 | class Ipv4Handler { 27 | public: 28 | Ipv4Provider* backend; 29 | uint8_t protocol; 30 | 31 | Ipv4Handler(Ipv4Provider* backend, uint8_t protocol); 32 | ~Ipv4Handler(); 33 | 34 | void send(uint32_t dest_ip_be, uint8_t* payload, uint32_t size); 35 | 36 | virtual bool onInternetProtocolReceived(uint32_t srcIP_BE, uint32_t dstIP_BE, uint8_t* payload, uint32_t size); 37 | }; 38 | 39 | class Ipv4Provider : public net::EtherFrameHandler { 40 | public: 41 | listv2 handlers; 42 | AddressResolutionProtocol* arp; 43 | 44 | uint32_t gateway_ip_be; 45 | uint32_t subnet_mask_be; 46 | 47 | Ipv4Provider(EtherFrameProvider* backend, AddressResolutionProtocol* arp, uint32_t gateway_ip_be, uint32_t subnet_mask_be); 48 | ~Ipv4Provider(); 49 | 50 | virtual bool onEtherFrameReceived(uint8_t* payload, uint32_t size); 51 | void send(uint32_t dest_ip_be, uint8_t protocol, uint8_t* payload, uint32_t size); 52 | uint16_t checksum(uint16_t* data, uint32_t size); 53 | }; 54 | } -------------------------------------------------------------------------------- /src/include/net/listv2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | class listv2 { 9 | public: 10 | 11 | struct node { 12 | T data; 13 | bool taken = false; 14 | }; 15 | 16 | listv2(int initial_length) { 17 | length = initial_length; 18 | data = (node*) malloc(length * sizeof(node)); 19 | memset(data, 0, length * sizeof(T)); 20 | }; 21 | 22 | ~listv2() { 23 | free(data); 24 | } 25 | 26 | template 27 | node* find(bool (*f)(Y, node*), Y arg) { 28 | for (size_t i = 0; i < length; i++) { 29 | if (data[i].taken) { 30 | if (f(arg, &data[i])) { 31 | return &data[i]; 32 | } 33 | } 34 | } 35 | 36 | return nullptr; 37 | } 38 | 39 | void foreach(void (*f)(node*)) { 40 | for (size_t i = 0; i < length; i++) { 41 | if (data[i].taken) { 42 | f(&data[i]); 43 | } 44 | } 45 | } 46 | 47 | void remove(node* n) { 48 | for (size_t i = 0; i < length; i++) { 49 | if (&data[i] == n) { 50 | memset(&data[i], 0, sizeof(node)); 51 | } 52 | } 53 | } 54 | 55 | node* add(T d) { 56 | retry: 57 | for (size_t i = 0; i < length; i++) { 58 | if (!data[i].taken) { 59 | data[i].data = d; 60 | data[i].taken = true; 61 | return &data[i]; 62 | } 63 | } 64 | 65 | data = (node*) realloc(data, sizeof(node) * (length + 1), length * sizeof(node)); 66 | length++; 67 | goto retry; 68 | } 69 | 70 | private: 71 | int length; 72 | node* data; 73 | }; -------------------------------------------------------------------------------- /src/include/net/net_stack.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace net { 12 | struct net_stack_t { 13 | net::EtherFrameProvider* ether; 14 | net::AddressResolutionProtocol* arp; 15 | net::Ipv4Provider* ipv4; 16 | net::IcmpProvider* icmp; 17 | net::UdpProvider* udp; 18 | net::TcpProvider* tcp; 19 | net::DomainNameServiceProvider* dns; 20 | }; 21 | } -------------------------------------------------------------------------------- /src/include/net/tcp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace net { 8 | enum TcpSocketState { 9 | CLOSED = 0, 10 | LISTEN, 11 | SYN_SENT, 12 | SYN_RECEIVED, 13 | 14 | ESTABLISHED, 15 | 16 | FIN_WAIT_1, 17 | FIN_WAIT_2, 18 | CLOSING, 19 | TIME_WAIT, 20 | 21 | CLOSE_WAIT 22 | }; 23 | 24 | enum TcpFlag { 25 | FIN = 1, 26 | SYN = 2, 27 | RST = 4, 28 | PSH = 8, 29 | ACK = 16, 30 | URG = 32, 31 | ECE = 64, 32 | CWR = 128, 33 | NS = 256 34 | }; 35 | 36 | struct tcp_header_t { 37 | uint16_t src_port; 38 | uint16_t dst_port; 39 | uint32_t seq_num; 40 | uint32_t ack; 41 | 42 | uint8_t reserved : 4; 43 | uint8_t data_offset : 4; 44 | uint8_t flags; 45 | 46 | uint16_t window_size; 47 | uint16_t checksum; 48 | uint16_t urgent_ptr; //Only if the urgent flag is set 49 | 50 | uint32_t options; 51 | } __attribute__((packed)); 52 | 53 | struct tcp_pseudo_header_t { 54 | uint32_t src_ip; 55 | uint32_t dst_ip; 56 | uint16_t protocol; 57 | uint16_t total_len; 58 | } __attribute__((packed)); 59 | 60 | struct tcp_sent_packet_t { 61 | uint32_t seq_num; 62 | bool data_empty; 63 | bool was_acked; 64 | }; 65 | 66 | class TcpSocket; 67 | class TcpProvider; 68 | 69 | class TcpHandler { 70 | public: 71 | TcpHandler(); 72 | ~TcpHandler(); 73 | 74 | virtual bool onTcpMessage(TcpSocket* socket, uint8_t* data, size_t size); 75 | }; 76 | 77 | class TcpSocket { 78 | public: 79 | TcpSocket(TcpProvider *provider); 80 | ~TcpSocket(); 81 | 82 | virtual bool handleTcpMessage(uint8_t* data, size_t size); 83 | virtual void send(uint8_t* data, size_t size); 84 | virtual void disconnect(); 85 | 86 | TcpSocketState state; 87 | uint16_t remotePort; 88 | uint32_t remoteIp; 89 | uint16_t localPort; 90 | uint32_t localIp; 91 | uint32_t seq_num; 92 | uint32_t ack_num; 93 | 94 | TcpProvider* provider; 95 | TcpHandler* handler; 96 | 97 | listv2 acknowledged; 98 | }; 99 | 100 | class TcpProvider: public Ipv4Handler { 101 | public: 102 | struct tcp_bind_t { 103 | uint16_t port; 104 | TcpSocket* handler; 105 | }; 106 | 107 | listv2 binds; 108 | 109 | int free_port = 1024; 110 | 111 | TcpProvider(Ipv4Provider *ipv4Provider); 112 | ~TcpProvider(); 113 | 114 | virtual bool onInternetProtocolReceived(uint32_t srcIP_BE, uint32_t dstIP_BE, uint8_t* payload, uint32_t size); 115 | 116 | virtual TcpSocket* connect(uint32_t ip, uint16_t port); 117 | virtual TcpSocket* listen(uint16_t port); 118 | 119 | virtual void disconnect(TcpSocket* socket); 120 | 121 | virtual void send(TcpSocket* socket, uint8_t* data, size_t size, uint16_t flags = 0); 122 | virtual void retransmit(TcpSocket* socket, uint8_t* packet, size_t size, listv2::node* list_node); 123 | 124 | virtual void bind(TcpSocket* socket, TcpHandler* handler); 125 | }; 126 | } -------------------------------------------------------------------------------- /src/include/net/udp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace net { 7 | 8 | struct udp_header_t { 9 | uint16_t src_port; 10 | uint16_t dst_port; 11 | uint16_t length; 12 | uint16_t checksum; 13 | } __attribute__((packed)); 14 | 15 | class UdpSocket; 16 | class UdpProvider; 17 | 18 | 19 | class UdpHandler { 20 | public: 21 | UdpHandler(); 22 | ~UdpHandler(); 23 | 24 | virtual void onUdpMessage(UdpSocket *socket, uint8_t* data, size_t size); 25 | }; 26 | 27 | class UdpSocket { 28 | public: 29 | UdpSocket(UdpProvider *provider); 30 | ~UdpSocket(); 31 | 32 | virtual void handleUdpMessage(uint8_t* data, size_t size); 33 | virtual void send(uint8_t* data, size_t size); 34 | virtual void disconnect(); 35 | 36 | bool listening; 37 | uint16_t remotePort; 38 | uint32_t remoteIp; 39 | uint16_t localPort; 40 | uint32_t localIp; 41 | 42 | UdpProvider* provider; 43 | UdpHandler* handler; 44 | }; 45 | 46 | class UdpProvider: public Ipv4Handler { 47 | public: 48 | 49 | struct udp_bind_t { 50 | uint16_t port; 51 | UdpSocket* handler; 52 | }; 53 | 54 | listv2 binds; 55 | 56 | int free_port = 1024; 57 | 58 | 59 | UdpProvider(Ipv4Provider *ipv4Provider); 60 | ~UdpProvider(); 61 | 62 | virtual bool onInternetProtocolReceived(uint32_t srcIP_BE, uint32_t dstIP_BE, uint8_t* payload, uint32_t size); 63 | 64 | virtual UdpSocket* connect(uint32_t ip, uint16_t port); 65 | virtual UdpSocket* listen(uint16_t port); 66 | 67 | virtual void disconnect(UdpSocket* socket); 68 | 69 | virtual void send(UdpSocket* socket, uint8_t* data, size_t size); 70 | 71 | virtual void bind(UdpSocket* socket, UdpHandler* handler); 72 | }; 73 | } -------------------------------------------------------------------------------- /src/include/paging/page_frame_allocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "stddef.h" 6 | #include "bitmap.h" 7 | 8 | #include 9 | 10 | class PageFrameAllocator { 11 | public: 12 | void read_EFI_memory_map(stivale2_struct* bootinfo); 13 | Bitmap page_bitmap; 14 | void free_page(void* address); 15 | void free_pages(void* address, uint64_t page_count); 16 | void lock_page(void* address); 17 | void lock_pages(void* address, uint64_t page_count); 18 | void* request_page(); 19 | void* request_pages(int amount); 20 | uint64_t get_free_RAM(); 21 | uint64_t get_used_RAM(); 22 | uint64_t get_reserved_RAM(); 23 | 24 | private: 25 | void init_bitmap(size_t bitmapSize, void* buffer_address); 26 | void reserve_page(void* address); 27 | void reserve_pages(void* address, uint64_t page_count); 28 | void unreserve_page(void* address); 29 | void unreserve_pages(void* address, uint64_t page_count); 30 | }; 31 | 32 | extern PageFrameAllocator global_allocator; -------------------------------------------------------------------------------- /src/include/paging/page_map_indexer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class PageMapIndexer { 6 | public: 7 | PageMapIndexer(uint64_t virtual_address); 8 | uint64_t PDP_i; 9 | uint64_t PD_i; 10 | uint64_t PT_i; 11 | uint64_t P_i; 12 | }; -------------------------------------------------------------------------------- /src/include/paging/page_table_manager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "paging.h" 4 | #include 5 | 6 | class PageTableManager { 7 | public: 8 | PageTableManager(PageTable* PML4_address); 9 | PageTable* PML4; 10 | void map_memory(void* virtual_memory, void* physical_memory); 11 | void map_range(void* virtual_memory, void* physical_memory, size_t range); 12 | }; 13 | 14 | extern PageTableManager g_page_table_manager; -------------------------------------------------------------------------------- /src/include/paging/paging.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | enum PT_Flag { 6 | present = 0, 7 | read_write = 1, 8 | user_super = 2, 9 | write_through = 3, 10 | cache_disabled = 4, 11 | accessed = 5, 12 | larger_pages = 7, 13 | custom0 = 9, 14 | custom1 = 10, 15 | custom2 = 11, 16 | NX = 63 // only if supported 17 | }; 18 | 19 | struct PageDirectoryEntry { 20 | uint64_t value; 21 | void set_flag(PT_Flag flag, bool enabled); 22 | bool get_flag(PT_Flag flag); 23 | void set_address(uint64_t address); 24 | uint64_t get_address(); 25 | }; 26 | 27 | struct PageTable { 28 | PageDirectoryEntry entries [512]; 29 | }__attribute__((aligned(0x1000))); -------------------------------------------------------------------------------- /src/include/pci/acpi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace pci { 6 | namespace acpi { 7 | struct rsdp2_t { 8 | uint8_t signature[8]; 9 | uint8_t checksum; 10 | uint8_t oem_id[6]; 11 | uint8_t revision; 12 | uint32_t rsdt_address; 13 | uint32_t length; 14 | uint64_t xsdt_address; 15 | uint8_t extended_checksum; 16 | uint8_t reserved[3]; 17 | } __attribute__((packed)); 18 | 19 | struct sdt_header_t { 20 | uint8_t signature[4]; 21 | uint32_t length; 22 | uint8_t revision; 23 | uint8_t checksum; 24 | uint8_t oem_id[6]; 25 | uint8_t oem_table_id[8]; 26 | uint32_t oem_revision; 27 | uint32_t creator_id; 28 | uint32_t creator_revision; 29 | } __attribute__((packed)); 30 | 31 | struct mcfg_header_t { 32 | sdt_header_t header; 33 | uint64_t reserved; 34 | } __attribute__((packed)); 35 | 36 | struct hpet_table_t { 37 | sdt_header_t header; 38 | uint8_t hardware_rev_id; 39 | uint8_t info; 40 | uint16_t pci_id; 41 | uint8_t address_space_id; 42 | uint8_t register_width; 43 | uint8_t register_offset; 44 | uint8_t reserved; 45 | uint64_t address; 46 | uint8_t hpet_num; 47 | uint16_t minim_ticks; 48 | uint8_t page_protection; 49 | } __attribute__((packed)); 50 | 51 | struct device_config_t { 52 | uint64_t base_address; 53 | uint16_t pci_seg_group; 54 | uint8_t start_bus; 55 | uint8_t end_bus; 56 | uint32_t reserved; 57 | } __attribute__((packed)); 58 | 59 | void* find_table_xsdt(sdt_header_t* sdt_header, char* signature); 60 | void* find_table_rsdt(sdt_header_t* sdt_header, char* signature); 61 | } 62 | } -------------------------------------------------------------------------------- /src/include/pci/pci.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | namespace pci { 12 | struct pci_device_header_t { 13 | uint16_t vendor_id; 14 | uint16_t device_id; 15 | uint16_t command; 16 | uint16_t status; 17 | uint8_t revision_id; 18 | uint8_t prog_if; 19 | uint8_t subclass; 20 | uint8_t class_; 21 | uint8_t cache_line_size; 22 | uint8_t latency_timer; 23 | uint8_t header_type; 24 | uint8_t bist; 25 | }; 26 | 27 | struct pci_header_0_t { 28 | pci_device_header_t header; 29 | uint32_t BAR0; 30 | uint32_t BAR1; 31 | uint32_t BAR2; 32 | uint32_t BAR3; 33 | uint32_t BAR4; 34 | uint32_t BAR5; 35 | uint32_t cardbus_CIS_ptr; 36 | uint16_t subsystem_vendor_ID; 37 | uint16_t subsystem_ID; 38 | uint32_t expansion_ROM_base_addr; 39 | uint8_t capabilities_ptr; 40 | uint8_t rsv0; 41 | uint16_t rsv1; 42 | uint32_t rsv2; 43 | uint8_t interrupt_line; 44 | uint8_t interrupt_pin; 45 | uint8_t min_grant; 46 | uint8_t max_latency; 47 | }; 48 | 49 | struct pci_device { 50 | pci_header_0_t* header; 51 | uint16_t bus; 52 | uint16_t device; 53 | uint64_t function; 54 | }; 55 | 56 | void enumerate_pci(acpi::mcfg_header_t* mcfg); 57 | 58 | extern const char* device_classes[]; 59 | 60 | const char* get_vendor_name(uint16_t vendor_ID); 61 | const char* get_device_name(uint16_t vendor_ID, uint16_t device_ID); 62 | const char* get_subclass_name(uint8_t class_code, uint8_t subclass_code); 63 | const char* get_prog_IF_name(uint8_t class_code, uint8_t subclass_code, uint8_t prog_IF); 64 | 65 | uint32_t pci_readd(uint16_t bus, uint16_t device, uint16_t function, uint32_t registeroffset); 66 | void pci_writed(uint16_t bus, uint16_t device, uint16_t function, uint32_t registeroffset, uint32_t value); 67 | 68 | uint8_t pci_readb(uint16_t bus, uint16_t device, uint16_t function, uint32_t registeroffset); 69 | void pci_writeb(uint16_t bus, uint16_t device, uint16_t function, uint32_t registeroffset, uint8_t value); 70 | 71 | uint16_t pci_readw(uint16_t bus, uint16_t device, uint16_t function, uint32_t registeroffset); 72 | void pci_writew(uint16_t bus, uint16_t device, uint16_t function, uint32_t registeroffset, uint16_t value); 73 | 74 | int device_has_functions(uint16_t bus, uint16_t device); 75 | pci_header_0_t get_device_header(uint16_t bus, uint16_t device, uint16_t function); 76 | void enumerate_pci(); 77 | 78 | void enable_mmio(uint16_t bus, uint16_t device, uint16_t function); 79 | void become_bus_master(uint16_t bus, uint16_t device, uint16_t function); 80 | 81 | extern listv2* pci_devices; 82 | } 83 | -------------------------------------------------------------------------------- /src/include/pci/pci_bar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace pci { 7 | enum pci_bar_type_t { 8 | NONE = 0, 9 | MMIO64, 10 | MMIO32, 11 | IO 12 | }; 13 | 14 | struct pci_bar_t { 15 | uint64_t mem_address; 16 | uint16_t io_address; 17 | pci_bar_type_t type; 18 | uint16_t size; 19 | }; 20 | 21 | pci_bar_t get_bar(uint32_t* bar0, int bar_num, uint16_t bus, uint16_t device, uint16_t function); 22 | uint16_t get_io_port(pci::pci_header_0_t* header, uint16_t bus, uint16_t device, uint16_t function); 23 | } -------------------------------------------------------------------------------- /src/include/port.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class Port8Bit{ 6 | private: 7 | uint16_t portnumber; 8 | public: 9 | uint16_t offset; 10 | Port8Bit(uint16_t port); 11 | ~Port8Bit(); 12 | 13 | void Write(uint8_t data); 14 | uint8_t Read(); 15 | }; 16 | 17 | class Port16Bit{ 18 | private: 19 | uint16_t portnumber; 20 | public: 21 | uint16_t offset; 22 | Port16Bit(uint16_t port); 23 | ~Port16Bit(); 24 | 25 | void Write(uint16_t data); 26 | uint16_t Read(); 27 | }; 28 | 29 | class Port32Bit{ 30 | private: 31 | uint16_t portnumber; 32 | public: 33 | uint16_t offset; 34 | Port32Bit(uint16_t port); 35 | ~Port32Bit(); 36 | 37 | void Write(uint32_t data); 38 | uint32_t Read(); 39 | }; 40 | 41 | void io_wait(); 42 | 43 | unsigned char inb(unsigned short _port); 44 | void outb(unsigned short _port, unsigned char _data); 45 | uint16_t inw(uint16_t _port); 46 | void outw(uint16_t _port, uint16_t _data); 47 | uint32_t inl(uint16_t port); 48 | void outl(uint16_t port, uint32_t data); -------------------------------------------------------------------------------- /src/include/power.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void do_reboot(); -------------------------------------------------------------------------------- /src/include/renderer/font.h: -------------------------------------------------------------------------------- 1 | #ifndef FONT_H 2 | #define FONT_H 3 | 4 | #include 5 | 6 | #define PSF1_MAGIC0 0x36 7 | #define PSF1_MAGIC1 0x04 8 | 9 | struct psf1_header_t { 10 | uint8_t magic[2]; 11 | uint8_t mode; 12 | uint8_t charsize; 13 | }; 14 | 15 | struct psf1_font_t { 16 | psf1_header_t* psf1_Header; 17 | void* glyph_buffer; 18 | }; 19 | 20 | #endif -------------------------------------------------------------------------------- /src/include/renderer/font_renderer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | namespace renderer { 13 | class FontRenderer { 14 | public: 15 | FontRenderer(framebuffer_t* target_frame_buffer, psf1_font_t* font); 16 | renderer::point_t cursor_position; 17 | framebuffer_t* target_frame_buffer; 18 | psf1_font_t* font; 19 | uint32_t color; 20 | 21 | void printf(const char* str, ...); 22 | void putc(char c); 23 | void puts(const char* s); 24 | void putn(unsigned long x, int base); 25 | void clear(); 26 | void clear_line(); 27 | }; 28 | 29 | extern FontRenderer* global_font_renderer; 30 | } -------------------------------------------------------------------------------- /src/include/renderer/framebuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef FRAMEBUFFER_H 2 | #define FRAMEBUFFER_H 3 | 4 | #include 5 | #include 6 | 7 | struct framebuffer_t { 8 | void* base_address; 9 | size_t buffer_size; 10 | uint32_t width; 11 | uint32_t height; 12 | uint32_t pixels_per_scanline; 13 | }; 14 | 15 | #endif -------------------------------------------------------------------------------- /src/include/renderer/layer_renderer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace renderer { 6 | 7 | typedef framebuffer_t layer_t; 8 | 9 | layer_t* allocate_layer_matching(framebuffer_t* target_frame_buffer); 10 | void destroy_layer(layer_t* layer); 11 | 12 | class layer_renderer { 13 | public: 14 | layer_renderer(framebuffer_t* target_frame_buffer); 15 | ~layer_renderer(); 16 | 17 | void* buffer; 18 | 19 | void render(); 20 | void render_layer(layer_t* layer, bool base_layer); 21 | 22 | framebuffer_t* target_frame_buffer; 23 | }; 24 | 25 | } -------------------------------------------------------------------------------- /src/include/renderer/mouse_renderer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | namespace renderer { 14 | class MouseRenderer { 15 | private: 16 | uint8_t* mouse_pointer; 17 | 18 | public: 19 | MouseRenderer(); 20 | 21 | renderer::point_t mouse_position; 22 | renderer::point_t mouse_position_old; 23 | 24 | uint8_t* get_mouse_pointer(); 25 | void on_mouse_down(uint8_t button); 26 | void on_mouse_move(uint8_t mouse_packet[4]); 27 | }; 28 | 29 | extern MouseRenderer* global_mouse_renderer; 30 | } -------------------------------------------------------------------------------- /src/include/renderer/point.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace renderer { 4 | struct point_t{ 5 | long x; 6 | long y; 7 | }; 8 | } -------------------------------------------------------------------------------- /src/include/renderer/renderer2D.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | namespace renderer { 13 | class Renderer2D { 14 | public: 15 | Renderer2D(framebuffer_t* target_frame_buffer); 16 | framebuffer_t* target_frame_buffer; 17 | 18 | void put_pix(uint32_t x, uint32_t y, uint32_t colour); 19 | uint32_t get_pix(uint32_t x, uint32_t y); 20 | 21 | 22 | uint32_t mouse_cursor_buffer[16 * 16]; 23 | uint32_t mouse_cursor_buffer_after[16 * 16]; 24 | 25 | void clear_mouse_cursor(uint8_t* mouse_pointer, renderer::point_t pos); 26 | void draw_overlay_mouse_cursor(uint8_t* mouse_pointer, renderer::point_t pos, uint32_t colour); 27 | void load_bitmap(uint8_t data[], int y); 28 | void load_bitmap(uint8_t data[], int x, int y); 29 | renderer::point_t get_bitmap_info(uint8_t data[]); 30 | void scroll_down(); 31 | bool mouse_drawn; 32 | }; 33 | 34 | extern Renderer2D* global_renderer2D; 35 | } -------------------------------------------------------------------------------- /src/include/scheduling/hpet/hpet.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace hpet { 6 | struct hpet_t { 7 | uint64_t capabilities; 8 | uint64_t unused0; 9 | uint64_t general_config; 10 | uint64_t unused1; 11 | uint64_t int_status; 12 | uint64_t unused2; 13 | uint64_t unused3[24]; 14 | uint64_t counter_value; 15 | uint64_t unused4; 16 | } __attribute__((packed)); 17 | 18 | void sleep_d(uint64_t seconds); 19 | void sleep(uint64_t milliseconds); 20 | 21 | void init_hpet(pci::acpi::hpet_table_t* hpet_table); 22 | 23 | bool is_available(); 24 | } -------------------------------------------------------------------------------- /src/include/scheduling/pit/pit.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace PIT { 6 | extern uint64_t time_since_boot; 7 | const uint64_t base_frequency = 1193182; 8 | 9 | void sleep_d(uint64_t seconds); 10 | void sleep(uint64_t milliseconds); 11 | 12 | void set_divisor(uint16_t divisor); 13 | uint64_t get_frequency(); 14 | void set_frequency(uint64_t frequency); 15 | 16 | void init_pit(uint64_t divisor); 17 | void pit_interrupt_handler(uint8_t); 18 | } -------------------------------------------------------------------------------- /src/include/scheduling/scheduler/atomic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | extern "C" bool atomic_lock(uint64_t* mutex, uint64_t bit); 5 | extern "C" bool atomic_unlock(uint64_t* mutex, uint64_t bit); 6 | extern "C" void atomic_spinlock(uint64_t* mutex, uint64_t bit); 7 | 8 | #define define_spinlock(name) static uint64_t name = 0; 9 | 10 | #define atomic_acquire_spinlock(name) atomic_spinlock(&name, 0); atomic_lock(&name, 0); 11 | #define atomic_release_spinlock(name) atomic_unlock(&name, 0); -------------------------------------------------------------------------------- /src/include/scheduling/scheduler/errno.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void set_task_errno(int errno); -------------------------------------------------------------------------------- /src/include/scheduling/scheduler/queue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class uint64_t_queue { 6 | public: 7 | uint64_t len; 8 | uint64_t list[16]; 9 | 10 | uint64_t_queue(); 11 | ~uint64_t_queue(); 12 | 13 | void next(); 14 | void add(uint64_t num); 15 | void remove_first(); 16 | }; -------------------------------------------------------------------------------- /src/include/scheduling/scheduler/scheduler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | typedef void (*signal_handler)(uint8_t signum); 8 | struct task { 9 | s_registers regs; 10 | char fxsr_state[512] __attribute__((aligned(16))); 11 | void* xsave_state; 12 | uint64_t stack; 13 | bool first_sched; 14 | bool kill_me; 15 | bool lock; 16 | bool is_elf; 17 | void* offset; 18 | int page_count; 19 | char **argv; 20 | char **envp; 21 | int* errno; 22 | 23 | signal_handler signals[32]; 24 | }; 25 | 26 | void init_sched(); 27 | task* new_task(void* entry); 28 | task* load_elf(void* ptr, uint64_t file_size, const char **argv, const char **envp); 29 | void task_exit(); 30 | extern bool halt_cpu; 31 | extern bool scheduling; 32 | 33 | extern "C" void schedule(s_registers* regs); 34 | 35 | extern uint64_t_queue task_queue[256]; 36 | -------------------------------------------------------------------------------- /src/include/scheduling/scheduler/signal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | bool handle_signal(int signum); 6 | void register_signal_handler(int signum, uint64_t handler); -------------------------------------------------------------------------------- /src/include/shell/shell.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace shell { 4 | class Shell { 5 | private: 6 | char* command_buffer; 7 | int buffer_len; 8 | 9 | bool command_running; 10 | public: 11 | Shell(); 12 | 13 | void keypress(char c); 14 | }; 15 | 16 | extern Shell* global_shell; 17 | } -------------------------------------------------------------------------------- /src/include/stdarg.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDARG_H 2 | #define _STDARG_H 3 | 4 | typedef __builtin_va_list va_list; 5 | #define va_start(ap, X) __builtin_va_start(ap, X) 6 | #define va_arg(ap, type) __builtin_va_arg(ap, type) 7 | #define va_end(ap) __builtin_va_end(ap) 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/include/stdio.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | int sprintf(char *buf, const char *fmt, ...); 4 | -------------------------------------------------------------------------------- /src/include/stivale.h: -------------------------------------------------------------------------------- 1 | #ifndef __STIVALE__STIVALE_H__ 2 | #define __STIVALE__STIVALE_H__ 3 | 4 | #include 5 | 6 | // Anchor for non ELF kernels 7 | struct stivale_anchor { 8 | uint8_t anchor[15]; 9 | uint8_t bits; 10 | uint64_t phys_load_addr; 11 | uint64_t phys_bss_start; 12 | uint64_t phys_bss_end; 13 | uint64_t phys_stivalehdr; 14 | } __attribute__((__packed__)); 15 | 16 | /* --- Header --------------------------------------------------------------- */ 17 | /* Information passed from the kernel to the bootloader */ 18 | 19 | struct stivale_header { 20 | uint64_t stack; 21 | uint16_t flags; 22 | uint16_t framebuffer_width; 23 | uint16_t framebuffer_height; 24 | uint16_t framebuffer_bpp; 25 | uint64_t entry_point; 26 | } __attribute__((__packed__)); 27 | 28 | /* --- Struct --------------------------------------------------------------- */ 29 | /* Information passed from the bootloader to the kernel */ 30 | 31 | struct stivale_module { 32 | uint64_t begin; 33 | uint64_t end; 34 | char string[128]; 35 | uint64_t next; 36 | } __attribute__((__packed__)); 37 | 38 | #define STIVALE_MMAP_USABLE 1 39 | #define STIVALE_MMAP_RESERVED 2 40 | #define STIVALE_MMAP_ACPI_RECLAIMABLE 3 41 | #define STIVALE_MMAP_ACPI_NVS 4 42 | #define STIVALE_MMAP_BAD_MEMORY 5 43 | #define STIVALE_MMAP_KERNEL_AND_MODULES 10 44 | #define STIVALE_MMAP_BOOTLOADER_RECLAIMABLE 0x1000 45 | #define STIVALE_MMAP_FRAMEBUFFER 0x1002 46 | 47 | struct stivale_mmap_entry { 48 | uint64_t base; 49 | uint64_t length; 50 | uint32_t type; 51 | uint32_t unused; 52 | } __attribute__((__packed__)); 53 | 54 | #define STIVALE_FBUF_MMODEL_RGB 1 55 | 56 | struct stivale_struct { 57 | uint64_t cmdline; 58 | uint64_t memory_map_addr; 59 | uint64_t memory_map_entries; 60 | uint64_t framebuffer_addr; 61 | uint16_t framebuffer_pitch; 62 | uint16_t framebuffer_width; 63 | uint16_t framebuffer_height; 64 | uint16_t framebuffer_bpp; 65 | uint64_t rsdp; 66 | uint64_t module_count; 67 | uint64_t modules; 68 | uint64_t epoch; 69 | uint64_t flags; // bit 0: 1 if booted with BIOS, 0 if booted with UEFI 70 | // bit 1: 1 if extended colour information passed, 0 if not 71 | uint8_t fb_memory_model; 72 | uint8_t fb_red_mask_size; 73 | uint8_t fb_red_mask_shift; 74 | uint8_t fb_green_mask_size; 75 | uint8_t fb_green_mask_shift; 76 | uint8_t fb_blue_mask_size; 77 | uint8_t fb_blue_mask_shift; 78 | uint8_t reserved; 79 | uint64_t smbios_entry_32; 80 | uint64_t smbios_entry_64; 81 | } __attribute__((__packed__)); 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /src/include/string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | char* strcpy(char* dest, const char* src); 6 | int strlen(char* src); 7 | size_t strnlen(const char *s, size_t maxlen); 8 | char* strcat(char* dest, const char* src); 9 | int strcmp(char* str1, char* str2); 10 | const char* strstr(const char* X, const char* Y); 11 | char* strchr(const char* s, int c); 12 | char* strrchr (const char* s, int c); 13 | int strncmp(const char* s1, const char* s2, size_t n); 14 | void* memcpy(void* dest, const void* src, size_t n); 15 | int memcmp(const void * _s1, const void* _s2, size_t n); 16 | char* strncpy(char* _dst, const char* _src, size_t count); 17 | int sprintf(char *buf, const char *fmt, ...); -------------------------------------------------------------------------------- /src/include/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | void prepare_memory(stivale2_struct* boot_info); 11 | KernelInfo init_kernel(stivale2_struct* boot_info); 12 | 13 | extern interrupts::idt_t idtr; -------------------------------------------------------------------------------- /src/init/init_procces.cpp: -------------------------------------------------------------------------------- 1 | // This is the main init procces from the kernel the first thing witch runs after the kernel got the scheduler up and running! 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | bool autoexec = false; 16 | char* default_path_override = nullptr; 17 | 18 | extern "C" void syscall_table(); 19 | extern "C" void syscall_table_end(); 20 | 21 | //#set_autoexec-doc: Configures the init procces to run the predefined file on startup. 22 | void set_autoexec(char* path) { 23 | autoexec = true; 24 | default_path_override = path; 25 | 26 | if (default_path_override) { 27 | driver::global_serial_driver->printf("Setting autoexec to %s!\n", default_path_override); 28 | } else { 29 | driver::global_serial_driver->printf("Setting autoexec to %s!\n", AUTOEXEC_PATH); 30 | } 31 | } 32 | 33 | //#__init_procces_sighandler-doc: The standard init procces signal handler. Just shows the general panic screen. 34 | void __init_procces_sighandler(int signum) { 35 | char error[256]; 36 | 37 | sprintf(error, "Init procces failed because of exception %d!", signum); 38 | 39 | interrupts::Panic* panic = new interrupts::Panic(error); 40 | panic->do_it(nullptr); 41 | } 42 | 43 | //#init_procces-doc: The init procces is the first procces that runs after the kernel got the scheduler up and running! Depending on the configuration this procces will load a predefined or custom execurable file. 44 | extern "C" void init_procces() { 45 | int errno = 0; 46 | for (int i = 0; i < 32; i++) { 47 | __asm__ __volatile__ ("int $0x30" : : "a" (5), "b" (3), "c" (i), "d" (__init_procces_sighandler)); 48 | } 49 | 50 | __asm__ __volatile__ ("int $0x30" : : "a" (5), "b" (2), "c" (&errno)); 51 | 52 | driver::global_serial_driver->printf("Kernel knows following syscalls:\n"); 53 | for (int i = 0; i < ((uint64_t) syscall_table_end - (uint64_t) syscall_table) / sizeof(uint64_t); i++) { 54 | uint64_t addr = *((uint64_t*) ((uint64_t) syscall_table + i * sizeof(uint64_t))); 55 | driver::global_serial_driver->printf("%d: %s\n", i, resolve_symbol(addr)); 56 | } 57 | 58 | readloop: 59 | bool reading = true; 60 | char* buffer = (char*) malloc(sizeof(char) * 512); 61 | char* orig_buffer = buffer; 62 | 63 | renderer::global_font_renderer->clear_line(); 64 | renderer::global_font_renderer->printf("Executable to start > "); 65 | 66 | if (autoexec) { 67 | if (default_path_override) { 68 | renderer::global_font_renderer->printf("%s\n", default_path_override); 69 | strcpy(buffer, default_path_override); 70 | reading = false; 71 | } else { 72 | renderer::global_font_renderer->printf("%s\n", AUTOEXEC_PATH); 73 | strcpy(buffer, AUTOEXEC_PATH); 74 | reading = false; 75 | } 76 | } 77 | 78 | while (reading) { 79 | bool done = false; 80 | __asm__ __volatile__ ("mov %%rax, %%r8" : : "a" (&done)); 81 | __asm__ __volatile__ ("int $0x30" : : "a" (6), "b" (0), "c" (buffer), "d" (1)); 82 | 83 | while (!done) { 84 | __asm__ __volatile__ ("nop"); 85 | } 86 | 87 | switch (*buffer) { 88 | case '\n': 89 | reading = false; 90 | *buffer = 0; 91 | break; 92 | 93 | case '\b': 94 | if (buffer > orig_buffer) { 95 | *buffer = 0; 96 | buffer--; 97 | } 98 | break; 99 | 100 | default: 101 | buffer++; 102 | break; 103 | } 104 | } 105 | 106 | errno = 0; 107 | FILE* file = fopen(orig_buffer, "r"); 108 | 109 | if (errno != 0) { 110 | renderer::global_font_renderer->printf("Failed to open file: %s, errno: %d\n", orig_buffer, errno); 111 | free(orig_buffer); 112 | goto readloop; 113 | } 114 | 115 | int page_amount = file->size / 0x1000 + 1; 116 | void* elf_contents = global_allocator.request_pages(page_amount); 117 | 118 | fseek(file, 0, SEEK_SET); 119 | 120 | fread(elf_contents, file->size, 1, file); 121 | 122 | const char* argv[] = { orig_buffer, NULL }; 123 | const char* envp[] = { "PATH=/bin", NULL }; 124 | load_elf((void*) elf_contents, file->size, argv, envp); 125 | 126 | fclose(file); 127 | } 128 | -------------------------------------------------------------------------------- /src/interrupts/idt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace interrupts; 4 | 5 | //#idt_desc_entry_t::set_offset-doc: Sets the offset of a entry in the interrupt descriptor table. 6 | void idt_desc_entry_t::set_offset(uint64_t offset) { 7 | offset0 = (uint16_t) (offset & 0x000000000000ffff); 8 | offset1 = (uint16_t) ((offset & 0x00000000ffff0000) >> 16); 9 | offset2 = (uint32_t) ((offset & 0xffffffff00000000) >> 32); 10 | } 11 | 12 | //#idt_desc_entry_t::get_offset-doc: Gets the offset of a entry in the interrupt descriptor table. 13 | uint64_t idt_desc_entry_t::get_offset(){ 14 | uint64_t offset = 0; 15 | offset |= (uint64_t) offset0; 16 | offset |= (uint64_t) offset1 << 16; 17 | offset |= (uint64_t) offset2 << 32; 18 | return offset; 19 | } -------------------------------------------------------------------------------- /src/interrupts/interrupt_handler.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace interrupts; 5 | InterruptHandler* interrupts::handlers[256]; 6 | intr_handler_ptr interrupts::static_handlers[256]; 7 | 8 | //#InterruptHandler::InterruptHandler-doc: Registers the interrupt handler for the given interrupt number. This is called by is the constructor. 9 | InterruptHandler::InterruptHandler(uint8_t int_num) { 10 | this->int_num = int_num; 11 | handlers[this->int_num] = this; 12 | } 13 | 14 | //#InterruptHandler::~InterruptHandler-doc: Unregisters the interrupt handler for the given interrupt number. This is a destructor no need to call it manually. 15 | InterruptHandler::~InterruptHandler() { 16 | if(handlers[this->int_num] == this) { 17 | handlers[this->int_num] = NULL; 18 | } 19 | } 20 | 21 | //#InterruptHandler::handle-doc: Default handler for interrupts. Gets called if the default handler doesn't get overwritten. 22 | void InterruptHandler::handle() { 23 | 24 | } 25 | 26 | //#interrupts::register_interrupt_handler-doc: Register an interrupt handler for the given interrupt number. Uses the static_handlers array to store the handler. 27 | void interrupts::register_interrupt_handler(uint8_t intr, intr_handler_ptr handler) { 28 | static_handlers[intr] = handler; 29 | } -------------------------------------------------------------------------------- /src/interrupts/interrupts.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | using namespace interrupts; 16 | 17 | extern "C" void schedule(s_registers* regs); 18 | 19 | //#intr_common_handler_c-doc: The general purpose interrupt handler. This handler is called when an interrupt is received. The handler will check if there is a interrupt handler for the interrupt. If there is a interrupt handler, the handler will be called. If the interrupt is a exception, the handler will cause a panic if there is no signal handler. 20 | extern "C" void intr_common_handler_c(s_registers* regs) { 21 | if(regs->interrupt_number <= 0x1f) { 22 | #ifdef SEND_SIGNALS 23 | if (!handle_signal(regs->interrupt_number)) { 24 | Panic p = Panic(regs->interrupt_number); 25 | p.do_it(regs); 26 | while(1); 27 | } 28 | #else 29 | Panic p = Panic(regs->interrupt_number); 30 | p.do_it(regs); 31 | while(1); 32 | #endif 33 | } 34 | 35 | if(regs->interrupt_number >= 0x20 && regs->interrupt_number <= 0x2f) { 36 | if(regs->interrupt_number == 0x20) { 37 | 38 | if (!NO_SMP_SHED) { 39 | schedule(regs); 40 | } 41 | 42 | uint8_t id; 43 | __asm__ __volatile__ ("mov $1, %%eax; cpuid; shrl $24, %%ebx;": "=b"(id) : : ); 44 | 45 | if(id != bspid) { 46 | *((volatile uint32_t*)(lapic_ptr + 0xb0)) = 0; 47 | return; 48 | } 49 | else if (NO_SMP_SHED){ 50 | schedule(regs); 51 | } 52 | } 53 | 54 | if(handlers[regs->interrupt_number] != NULL) { 55 | handlers[regs->interrupt_number]->handle(); 56 | } 57 | 58 | if(static_handlers[regs->interrupt_number] != NULL) { 59 | (*(static_handlers[regs->interrupt_number]))(regs->interrupt_number); 60 | } 61 | 62 | if (regs->interrupt_number >= 0x28) { 63 | Port8Bit p(0xa0); 64 | p.Write(0x20); 65 | } 66 | 67 | Port8Bit p(0x20); 68 | p.Write(0x20); 69 | } 70 | } -------------------------------------------------------------------------------- /src/interrupts/interrupts_stub.asm: -------------------------------------------------------------------------------- 1 | [extern intr_common_handler_c] 2 | [extern schedule] 3 | [extern halt_cpu] 4 | 5 | %macro intr_stub 1 6 | GLOBAL intr_stub_%1 7 | intr_stub_%1: 8 | push 0 9 | push %1 10 | jmp intr_common_handler 11 | %endmacro 12 | 13 | %macro intr_stub_err 1 14 | GLOBAL intr_stub_%1 15 | intr_stub_%1: 16 | push %1 17 | jmp intr_common_handler 18 | %endmacro 19 | 20 | %macro pusha 0 21 | push rax 22 | push rcx 23 | push rdx 24 | push rbx 25 | push rbp 26 | push rsi 27 | push rdi 28 | push r8 29 | push r9 30 | push r10 31 | push r11 32 | push r12 33 | push r13 34 | push r14 35 | push r15 36 | %endmacro 37 | 38 | %macro popa 0 39 | pop r15 40 | pop r14 41 | pop r13 42 | pop r12 43 | pop r11 44 | pop r10 45 | pop r9 46 | pop r8 47 | pop rdi 48 | pop rsi 49 | pop rbp 50 | pop rbx 51 | pop rdx 52 | pop rcx 53 | pop rax 54 | %endmacro 55 | 56 | intr_stub 0 57 | intr_stub 1 58 | intr_stub 2 59 | intr_stub 3 60 | intr_stub 4 61 | intr_stub 5 62 | intr_stub 6 63 | intr_stub 7 64 | intr_stub_err 8 65 | intr_stub 9 66 | intr_stub_err 10 67 | intr_stub_err 11 68 | intr_stub_err 12 69 | intr_stub_err 13 70 | intr_stub_err 14 71 | intr_stub 15 72 | intr_stub 16 73 | intr_stub_err 17 74 | intr_stub 18 75 | 76 | intr_stub 32 77 | intr_stub 33 78 | 79 | intr_stub 34 80 | intr_stub 35 81 | intr_stub 36 82 | intr_stub 37 83 | intr_stub 38 84 | intr_stub 39 85 | intr_stub 40 86 | intr_stub 41 87 | intr_stub 42 88 | intr_stub 43 89 | intr_stub 44 90 | intr_stub 45 91 | intr_stub 46 92 | intr_stub 47 93 | 94 | ;# intr_common_handler-signature: void intr_common_handler() 95 | ;# intr_common_handler-doc: The common interrupt handler. Every interrupt except for the syscall lands here first. Calls the init_comon_handler_c function. 96 | 97 | intr_common_handler: 98 | cli 99 | pusha 100 | 101 | mov rax, cr0 102 | push rax 103 | mov rax, cr2 104 | push rax 105 | mov rax, cr3 106 | push rax 107 | mov rax, cr4 108 | push rax 109 | 110 | mov rdi, rsp 111 | 112 | mov rax, 0 113 | mov ah, [halt_cpu] 114 | cmp ah, 0 115 | jne .halt 116 | 117 | call intr_common_handler_c 118 | 119 | pop rax 120 | pop rax 121 | pop rax 122 | pop rax 123 | popa 124 | 125 | add rsp, 16 126 | 127 | sti 128 | iretq 129 | 130 | .halt: 131 | cli 132 | hlt 133 | jmp .halt -------------------------------------------------------------------------------- /src/interrupts/syscall.asm: -------------------------------------------------------------------------------- 1 | %macro intr_stub 1 2 | GLOBAL intr_stub_%1 3 | intr_stub_%1: 4 | push 0 5 | push %1 6 | jmp syscall_handler 7 | %endmacro 8 | 9 | %macro pusha 0 10 | push rax 11 | push rcx 12 | push rdx 13 | push rbx 14 | push rbp 15 | push rsi 16 | push rdi 17 | push r8 18 | push r9 19 | push r10 20 | push r11 21 | push r12 22 | push r13 23 | push r14 24 | push r15 25 | %endmacro 26 | 27 | %macro popa 0 28 | pop r15 29 | pop r14 30 | pop r13 31 | pop r12 32 | pop r11 33 | pop r10 34 | pop r9 35 | pop r8 36 | pop rdi 37 | pop rsi 38 | pop rbp 39 | pop rbx 40 | pop rdx 41 | pop rcx 42 | pop rax 43 | %endmacro 44 | 45 | intr_stub 48 46 | 47 | ;# syscall_handler-signature: void syscall_handler() 48 | ;# syscall_handler-doc: Main syscall handler. Looks up the syscall number in the syscall table, the syscall number is stored in rax. 49 | 50 | [GLOBAL syscall_handler] 51 | syscall_handler: 52 | cli 53 | pusha 54 | mov r15, cr0 55 | push r15 56 | mov r15, cr2 57 | push r15 58 | mov r15, cr3 59 | push r15 60 | mov r15, cr4 61 | push r15 62 | 63 | mov rdi, rsp 64 | 65 | cmp rax, max_syscall 66 | ja .skip 67 | 68 | lea r15, [syscall_table + rax * 8] 69 | call [r15] 70 | 71 | .skip: 72 | 73 | pop rax 74 | pop rax 75 | pop rax 76 | pop rax 77 | popa 78 | 79 | add rsp, 16 80 | 81 | sti 82 | 83 | iretq 84 | 85 | [extern syscall_test] 86 | [extern syscall_test2] 87 | [extern sys_write] 88 | [extern sys_resolve_symbol] 89 | [extern sys_memory] 90 | [extern sys_env] 91 | [extern sys_read] 92 | [extern schedule] 93 | [extern sys_spawn] 94 | [extern sys_open] 95 | [extern sys_close] 96 | [extern sys_seek_get] 97 | [extern sys_seek_set] 98 | 99 | [GLOBAL syscall_table] 100 | [GLOBAL syscall_table_end] 101 | 102 | ;# syscall_table-discard 103 | ;# syscall_table_end-discard 104 | 105 | syscall_table: 106 | dq syscall_test 107 | dq syscall_test2 108 | dq sys_write 109 | dq sys_resolve_symbol 110 | dq sys_memory 111 | dq sys_env 112 | dq sys_read 113 | dq schedule 114 | dq sys_spawn 115 | dq sys_open 116 | dq sys_close 117 | dq sys_seek_get 118 | dq sys_seek_set 119 | syscall_table_end: 120 | 121 | max_syscall equ ((syscall_table_end - syscall_table) / 8) -1 122 | -------------------------------------------------------------------------------- /src/interrupts/syscalls/close.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //#sys_close-doc: Takes a file descriptor and closes the file. The file descriptor needs to be supplied in rbx. 5 | extern "C" void sys_close(s_registers regs) { 6 | fd::FileDescriptor* fd = fd::fdm->get_fd(regs.rbx); 7 | delete fd; 8 | 9 | fd::fdm->free_fd(regs.rbx); 10 | } -------------------------------------------------------------------------------- /src/interrupts/syscalls/env.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | //#sys_env-doc: Syscall to control various system features. Can be used to change the keymap, get argv/envp/errno and to register a signal handler. 11 | extern "C" void sys_env(s_registers regs) { 12 | uint8_t id; 13 | __asm__ __volatile__ ("mov $1, %%eax; cpuid; shrl $24, %%ebx;": "=b"(id) : : ); 14 | 15 | task* t = (task*) task_queue[id].list[0]; 16 | 17 | switch(regs.rbx) { 18 | case 0: 19 | regs.rcx = (uint64_t) t->argv; 20 | break; 21 | case 1: 22 | regs.rcx = (uint64_t) t->envp; 23 | break; 24 | case 2: 25 | t->errno = (int*) regs.rcx; 26 | break; 27 | case 3: 28 | register_signal_handler(regs.rcx, regs.rdx); 29 | break; 30 | case 4: 31 | { 32 | driver::KeyboardDriver* kbdrv = (driver::KeyboardDriver*) driver::global_driver_manager->find_driver_by_name((char*) "keyboard"); 33 | if(kbdrv != nullptr) { 34 | kbdrv->keymap = (uint8_t) regs.rcx; 35 | } 36 | } 37 | break; 38 | case 5: 39 | { 40 | driver::KeyboardDriver* kbdrv = (driver::KeyboardDriver*) driver::global_driver_manager->find_driver_by_name((char*) "keyboard"); 41 | if(kbdrv != nullptr) { 42 | kbdrv->debug_mode = (bool) regs.rcx; 43 | } 44 | } 45 | break; 46 | case 6: 47 | do_reboot(); 48 | break; 49 | } 50 | } -------------------------------------------------------------------------------- /src/interrupts/syscalls/memory.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | define_spinlock(memory_lock); 7 | 8 | //#sys_memory-doc: The syscall handler to allocate memory. 9 | extern "C" void sys_memory(s_registers regs) { 10 | atomic_acquire_spinlock(memory_lock); 11 | 12 | switch(regs.rbx) { 13 | case 0: 14 | regs.rcx = (uint64_t) malloc(regs.rdx); 15 | break; 16 | case 1: 17 | free((void*) regs.rcx); 18 | break; 19 | } 20 | 21 | atomic_release_spinlock(memory_lock); 22 | } -------------------------------------------------------------------------------- /src/interrupts/syscalls/open.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //#sys_open-doc: The opens a file and returns a file descriptor. It takes the name of the file in rbx and the mode in rcx. The file descriptor is returned in rdx. 5 | extern "C" void sys_open(s_registers regs) { 6 | int fd = fd::fdm->alloc_fd(); 7 | fd::FileDescriptor* fd_ptr = new fd::FileDescriptor(fd); 8 | fd::fdm->register_fd(fd_ptr); 9 | 10 | fd_ptr->open((const char*) regs.rbx, (const char*) regs.rcx); 11 | 12 | regs.rdx = fd; 13 | } -------------------------------------------------------------------------------- /src/interrupts/syscalls/read.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define ASSERT_NO_PANIC 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | 13 | struct read_buffer { 14 | bool* is_done; 15 | char* buffer; 16 | bool is_reading = false; 17 | int count = 0; 18 | }; 19 | 20 | read_buffer stdin_read_buffer; 21 | 22 | //#add_char-doc: Adds a character to the stdin buffer if a process is reading from stdin. 23 | void add_char(char c) { 24 | if(stdin_read_buffer.is_reading) { 25 | *stdin_read_buffer.buffer = c; 26 | stdin_read_buffer.buffer++; 27 | stdin_read_buffer.count--; 28 | 29 | if(stdin_read_buffer.count == 0) { 30 | stdin_read_buffer.is_reading = false; 31 | *stdin_read_buffer.is_done = true; 32 | } 33 | } 34 | } 35 | 36 | //#is_reading-doc: Checks if a program is reading from stdin. 37 | bool is_reading() { 38 | return stdin_read_buffer.is_reading; 39 | } 40 | 41 | //#sys_read-doc: The syscall to read n bytes from a file descriptor. 42 | extern "C" void sys_read(s_registers regs) { 43 | switch(regs.rbx) { 44 | case 0: 45 | assert(stdin_read_buffer.is_reading != true); 46 | 47 | stdin_read_buffer.count = regs.rdx; 48 | stdin_read_buffer.buffer = (char*) regs.rcx; 49 | stdin_read_buffer.is_done = (bool*) regs.r8; 50 | 51 | stdin_read_buffer.is_reading = true; 52 | break; 53 | 54 | assert_fail: 55 | set_task_errno(0xded); 56 | break; 57 | 58 | case 1: 59 | break; 60 | case 2: 61 | break; 62 | 63 | default: 64 | { 65 | fd::FileDescriptor* fd = fd::fdm->get_fd(regs.rbx); 66 | driver::global_serial_driver->printf("sys_read: fd %d buffer %x count %d\n", regs.rbx, regs.rcx, regs.rdx); 67 | fd->read((void*) regs.rcx, regs.rdx, 1); 68 | } 69 | break; 70 | } 71 | } -------------------------------------------------------------------------------- /src/interrupts/syscalls/resolve_symbol.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //#sys_resolve_symbol-doc: Syscall to reslove a symbol from the kernel. Can be used to call kernel functions directly. 5 | extern "C" void sys_resolve_symbol(s_registers regs) { 6 | regs.rcx = resolve_symbol((char*) regs.rbx); 7 | } -------------------------------------------------------------------------------- /src/interrupts/syscalls/seek_get.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | //#sys_seek_get-doc: Get the current position of a file descriptor. The file descriptor must be provided in rbx. The result will be stored in rcx. 6 | extern "C" void sys_seek_get(s_registers regs) { 7 | fd::FileDescriptor* fd = fd::fdm->get_fd(regs.rbx); 8 | 9 | regs.rcx = ftell(fd->file); 10 | } -------------------------------------------------------------------------------- /src/interrupts/syscalls/seek_set.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | //#sys_seek_set-doc: Set the current position of a file descriptor. The file descriptor must be provided in rbx. The offset is in rcx and the whence is in rdx. If the whence is 0 SEEK_SET gets used. 6 | extern "C" void sys_seek_set(s_registers regs) { 7 | fd::FileDescriptor* fd = fd::fdm->get_fd(regs.rbx); 8 | 9 | if (regs.rdx == 0) { 10 | fseek(fd->file, regs.rcx, SEEK_SET); 11 | } else { 12 | fseek(fd->file, regs.rcx, regs.rdx); 13 | } 14 | } -------------------------------------------------------------------------------- /src/interrupts/syscalls/spawn.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | define_spinlock(spawn_lock); 10 | 11 | //#sys_spawn-doc: Spawns a new process. The new process will be created from a file witch the calling process needs to supply the path to. 12 | extern "C" void sys_spawn(s_registers regs) { 13 | atomic_acquire_spinlock(spawn_lock); 14 | 15 | const char* name = (const char*) regs.rbx; 16 | const char** argv = (const char**) regs.rcx; 17 | const char** envp = (const char**) regs.rdx; 18 | FILE* file = fopen(name, "r"); 19 | 20 | if (file->is_error) { 21 | driver::global_serial_driver->printf("Error: Could not open file %s\n", name); 22 | return; 23 | } 24 | 25 | int page_amount = file->size / 0x1000 + 1; 26 | void* elf_contents = global_allocator.request_pages(page_amount); 27 | 28 | driver::global_serial_driver->printf("Spawning process %s\n", name); 29 | 30 | fread(elf_contents, file->size, 1, file); 31 | 32 | regs.rax = (uint64_t) load_elf((void*) elf_contents, file->size, argv, envp); 33 | 34 | fclose(file); 35 | 36 | atomic_release_spinlock(spawn_lock); 37 | } -------------------------------------------------------------------------------- /src/interrupts/syscalls/write.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | define_spinlock(write_lock); 10 | 11 | //#sys_write-doc: Syscall to write to a file descriptor. 12 | extern "C" void sys_write(s_registers regs) { 13 | atomic_acquire_spinlock(write_lock); 14 | 15 | switch(regs.rbx) { 16 | case 0: 17 | break; 18 | case 1: 19 | for (int i = 0; i < regs.rdx; i++) { 20 | renderer::global_font_renderer->putc(*((char*)regs.rcx + i)); 21 | } 22 | break; 23 | case 2: 24 | for (int i = 0; i < regs.rdx; i++) { 25 | driver::global_serial_driver->putc(*((char*)regs.rcx + i)); 26 | } 27 | break; 28 | default: 29 | { 30 | fd::FileDescriptor* fd = fd::fdm->get_fd(regs.rbx); 31 | driver::global_serial_driver->printf("sys_write: fd %d buffer %x count %d\n", regs.rbx, regs.rcx, regs.rdx); 32 | fd->write((void*) regs.rcx, regs.rdx, 1); 33 | } 34 | } 35 | 36 | atomic_release_spinlock(write_lock); 37 | } -------------------------------------------------------------------------------- /src/link.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT(elf64-x86-64) 2 | ENTRY(_start) 3 | 4 | SECTIONS 5 | { 6 | . = 0x100000; 7 | kernel_start = .; 8 | .stivale2hdr : ALIGN(0x1000) 9 | { 10 | KEEP(*(.stivale2hdr)) 11 | } 12 | .text : ALIGN(0x1000) 13 | { 14 | *(.text) 15 | } 16 | .data : ALIGN(0x1000) 17 | { 18 | *(.data) 19 | } 20 | .rodata : ALIGN(0x1000) 21 | { 22 | *(.rodata) 23 | } 24 | .bss : ALIGN(0x1000) 25 | { 26 | *(COMMON) 27 | *(.bss) 28 | } 29 | kernel_end = .; 30 | } -------------------------------------------------------------------------------- /src/load_gdt.asm: -------------------------------------------------------------------------------- 1 | [bits 64] 2 | 3 | ;# load_gdt-signature: extern "C" void load_gdt(gdt_descriptor_t* gdt_descriptor); 4 | ;# load_gdt-doc: Load the GDT with the given descriptor. 5 | 6 | load_gdt: 7 | lgdt [rdi] 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 | 15 | pop rdi 16 | mov rax, 0x08 17 | push rax 18 | push rdi 19 | 20 | retfq 21 | 22 | GLOBAL load_gdt -------------------------------------------------------------------------------- /src/memory/fast_mem.asm: -------------------------------------------------------------------------------- 1 | [bits 64] 2 | [extern _Z5patchPcm] 3 | [global memset_fast1] 4 | [global memcpy_fast1] 5 | [global memset_fast2] 6 | [global memcpy_fast2] 7 | [global init_fast_mem] 8 | 9 | ;# memset_fast1-signature: void* memset_fast1(void* dest, int c, size_t n) 10 | ;# memset_fast1-doc: A faster version of memset. 11 | 12 | memset_fast1: 13 | mov r9, rdi 14 | mov al, sil 15 | mov rcx, rdx 16 | rep stosb 17 | mov rax, r9 18 | ret 19 | 20 | ;# memcpy_fast1-signature: void* memcpy_fast1(void* dest, const void* src, size_t n) 21 | ;# memcpy_fast1-doc: A faster version of memcpy. 22 | 23 | memcpy_fast1: 24 | mov rax, rdi 25 | mov rcx, rdx 26 | rep movsb 27 | ret 28 | 29 | ;# memcpy_fast2-signature: void* memcpy_fast2(void* dest, const void* src, size_t n) 30 | ;# memcpy_fast2-doc: A even faster version of memcpy. 31 | 32 | memcpy_fast2: 33 | mov rax, rdi 34 | mov rcx, rdx 35 | shr rcx, 3 36 | and edx, 7 37 | rep movsq 38 | mov ecx, edx 39 | rep movsb 40 | ret 41 | 42 | 43 | ;# memset_fast2-signature: void* memset_fast2(void* dest, int c, size_t n) 44 | ;# memset_fast2-doc: A even faster version of memset. 45 | 46 | memset_fast2: 47 | mov r9, rdi 48 | mov rcx, rdx 49 | shr rcx, 3 50 | and edx, 7 51 | movsx esi, sil 52 | mov rax, 0x0101010101010101 53 | imul rax, rsi 54 | rep stosq 55 | mov ecx, edx 56 | rep stosb 57 | mov rax, r9 58 | ret 59 | 60 | ;# init_fast_mem-signature: void init_fast_mem() 61 | ;# init_fast_mem-doc: Initialize the fast memory functions. This patches the original memset/memcpy functions to use the fast versions. 62 | 63 | init_fast_mem: 64 | mov rdi, .memcpy_str 65 | mov rsi, memcpy_fast2 66 | call _Z5patchPcm 67 | 68 | mov rdi, .memset_str 69 | mov rsi, memset_fast2 70 | call _Z5patchPcm 71 | 72 | ret 73 | 74 | .memset_str: db "_Z6memsetPvhm", 0 75 | .memcpy_str: db "_Z6memcpyPvPKvm", 0 -------------------------------------------------------------------------------- /src/memory/memory.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //#get_memory_size-doc: Get the amount of memory in bytes. 4 | uint64_t get_memory_size(stivale2_struct* bootinfo) { 5 | 6 | static uint64_t memorySizeBytes = 0; 7 | if (memorySizeBytes > 0) return memorySizeBytes; 8 | 9 | stivale2_struct_tag_memmap* memmap = stivale2_tag_find(bootinfo, STIVALE2_STRUCT_TAG_MEMMAP_ID); 10 | 11 | for (int i = 0; i < memmap->entries; i++){ 12 | memorySizeBytes += memmap->memmap[i].length; 13 | } 14 | 15 | return memorySizeBytes; 16 | } 17 | 18 | //#memset-doc: Set a section of memory to a value. 19 | void memset(void* start, uint8_t value, uint64_t num) { 20 | for (uint64_t i = 0; i < num; i++){ 21 | *(uint8_t*)((uint64_t)start + i) = value; 22 | } 23 | } -------------------------------------------------------------------------------- /src/mmio.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //#MMIO::read8-doc: Read a uint8 from an MMIO address. 4 | uint8_t MMIO::read8(uint64_t p_address) { 5 | return *((volatile uint8_t*) p_address); 6 | } 7 | 8 | //#MMIO::read16-doc: Read a uint16 from an MMIO address. 9 | uint16_t MMIO::read16(uint64_t p_address) { 10 | return *((volatile uint16_t*) p_address); 11 | } 12 | 13 | //#MMIO::read32-doc: Read a uint32 from an MMIO address. 14 | uint32_t MMIO::read32(uint64_t p_address) { 15 | return *((volatile uint32_t*) p_address); 16 | } 17 | 18 | //#MMIO::read64-doc: Read a uint64 from an MMIO address. 19 | uint64_t MMIO::read64(uint64_t p_address) { 20 | return *((volatile uint64_t*) p_address); 21 | } 22 | 23 | //#MMIO::write8-doc: Write a uint8 to an MMIO address. 24 | void MMIO::write8(uint64_t p_address,uint8_t p_value) { 25 | (*((volatile uint8_t*) p_address)) = p_value; 26 | } 27 | 28 | //#MMIO::write16-doc: Write a uint16 to an MMIO address. 29 | void MMIO::write16(uint64_t p_address,uint16_t p_value) { 30 | (*((volatile uint16_t*) p_address)) = p_value; 31 | } 32 | 33 | //#MMIO::write32-doc: Write a uint32 to an MMIO address. 34 | void MMIO::write32(uint64_t p_address,uint32_t p_value) { 35 | (*((volatile uint32_t*) p_address)) = p_value; 36 | } 37 | 38 | //#MMIO::write64-doc: Write a uint64 to an MMIO address. 39 | void MMIO::write64(uint64_t p_address,uint64_t p_value) { 40 | (*((volatile uint64_t*) p_address)) = p_value; 41 | } -------------------------------------------------------------------------------- /src/net/etherframe.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace net; 7 | 8 | //#EtherFrameHandler::EtherFrameHandler-doc: EtherFrameHandler constructor. 9 | EtherFrameHandler::EtherFrameHandler(EtherFrameProvider* backend, uint16_t ether_type) { 10 | this->ether_type_be = ((ether_type & 0x00FF) << 8) | ((ether_type & 0xFF00) >> 8); 11 | this->backend = backend; 12 | backend->handlers.add(this); 13 | } 14 | 15 | //#EtherFrameHandler::~EtherFrameHandler-doc: EtherFrameHandler destructor. 16 | EtherFrameHandler::~EtherFrameHandler() { 17 | this->backend->handlers.remove(this->backend->handlers.find([](EtherFrameHandler* h, listv2::node* n) { 18 | return h == n->data; 19 | }, this)); 20 | } 21 | 22 | //#EtherFrameHandler::onEtherFrameReceived-doc: Virtual function to be overridden. Called when the ether frame receives a message. 23 | bool EtherFrameHandler::onEtherFrameReceived(uint8_t* payload, uint32_t size) { 24 | driver::global_serial_driver->printf("Unhandlet etherframe package!\n"); 25 | return false; 26 | } 27 | 28 | //#EtherFrameHandler::send-doc: Send some data with the ether frame. 29 | void EtherFrameHandler::send(uint64_t dest_mac_be, uint8_t* payload, uint32_t size) { 30 | this->backend->send_f(dest_mac_be, this->ether_type_be, payload, size); 31 | } 32 | 33 | //#EtherFrameProvider::EtherFrameProvider-doc: Empty constructor. 34 | EtherFrameProvider::EtherFrameProvider(int nic_id) : driver::nic::NicDataManager(nic_id), handlers(100) { 35 | 36 | } 37 | 38 | //#EtherFrameProvider::~EtherFrameProvider-doc: Empty destructor. 39 | EtherFrameProvider::~EtherFrameProvider() { 40 | 41 | } 42 | 43 | //#EtherFrameProvider::recv-doc: Called when the network card gets a message. 44 | bool EtherFrameProvider::recv(uint8_t* data, int32_t size) { 45 | ether_frame_header_t* frame = (ether_frame_header_t*) data; 46 | 47 | bool send_back = false; 48 | 49 | if (frame->dest_mac_be == 0xFFFFFFFFFFFF || frame->dest_mac_be == nic->get_mac()) { 50 | listv2::node* n = this->handlers.find([](uint16_t t, listv2::node* n) { 51 | return t == n->data->ether_type_be; 52 | }, frame->ether_type_be); 53 | 54 | if (n != nullptr) { 55 | send_back = n->data->onEtherFrameReceived(data + sizeof(ether_frame_header_t), size - sizeof(ether_frame_header_t)); 56 | } else { 57 | driver::global_serial_driver->printf("Unhandled etherframe!\n"); 58 | } 59 | } 60 | 61 | if (send_back) { 62 | frame->dest_mac_be = frame->src_mac_be; 63 | frame->src_mac_be = this->nic->get_mac(); 64 | } 65 | 66 | return send_back; 67 | } 68 | 69 | //#EtherFrameProvider::send_f-doc: Send a etherframe message. 70 | void EtherFrameProvider::send_f(uint64_t dest_mac_be, uint16_t ether_type_be, uint8_t* payload, uint32_t size) { 71 | uint8_t* buffer = (uint8_t*) global_allocator.request_page(); 72 | 73 | ether_frame_header_t* frame = (ether_frame_header_t*) buffer; 74 | 75 | frame->dest_mac_be = dest_mac_be; 76 | frame->src_mac_be = this->nic->get_mac(); 77 | frame->ether_type_be = ether_type_be; 78 | 79 | memcpy(buffer + sizeof(ether_frame_header_t), payload, size); 80 | 81 | 82 | this->nic->send(buffer, size + sizeof(ether_frame_header_t)); 83 | 84 | global_allocator.free_page(buffer); 85 | 86 | } -------------------------------------------------------------------------------- /src/net/icmp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace net; 6 | 7 | //#IcmpProvider::IcmpProvider-doc: Empty constructor for the IcmpProvider class. 8 | IcmpProvider::IcmpProvider(Ipv4Provider* ipv4) : Ipv4Handler(ipv4, 0x01) { 9 | 10 | } 11 | 12 | //#IcmpProvider::~IcmpProvider-doc: Empty destructor for the IcmpProvider class. 13 | IcmpProvider::~IcmpProvider() { 14 | 15 | } 16 | 17 | //#IcmpProvider::onInternetProtocolReceived-doc: Handle an internet protocol packet. 18 | bool IcmpProvider::onInternetProtocolReceived(uint32_t srcIP_BE, uint32_t dstIP_BE, uint8_t* payload, uint32_t size) { 19 | if (size < sizeof(icmp_message_t)) { 20 | return false; 21 | } 22 | 23 | icmp_message_t* icmp = (icmp_message_t*) payload; 24 | 25 | switch (icmp->type) { 26 | case 0: 27 | { 28 | // Echo reply 29 | driver::nic::ip_u ip; 30 | ip.ip = srcIP_BE; 31 | 32 | driver::global_serial_driver->printf("ICMP: Echo reply from %d.%d.%d.%d\n", ip.ip_p[0], ip.ip_p[1], ip.ip_p[2], ip.ip_p[3]); 33 | return false; 34 | } 35 | break; 36 | case 8: 37 | { 38 | // Echo request 39 | icmp->type = 0; 40 | icmp->checksum = 0; 41 | icmp->checksum = this->backend->checksum((uint16_t*) icmp, sizeof(icmp_message_t)); 42 | this->send(srcIP_BE, (uint8_t*) icmp, sizeof(icmp_message_t)); 43 | return false; 44 | } 45 | break; 46 | } 47 | 48 | return false; 49 | } 50 | 51 | //#IcmpProvider::send_echo_request-doc: Send a echo request to the specified ip. 52 | void IcmpProvider::send_echo_request(uint32_t dstIP_BE) { 53 | icmp_message_t icmp = { 54 | .type = 8, 55 | .code = 0, 56 | .checksum = 0, 57 | .data = 0x3713 58 | }; 59 | 60 | icmp.checksum = backend->checksum((uint16_t*) &icmp, sizeof(icmp_message_t)); 61 | this->send(dstIP_BE, (uint8_t*) &icmp, sizeof(icmp_message_t)); 62 | } -------------------------------------------------------------------------------- /src/paging/page_map_indexer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //#PageMapIndexer::PageMapIndexer-doc: Used to get the indexes of a virtual address. 4 | PageMapIndexer::PageMapIndexer(uint64_t virtual_address) { 5 | virtual_address >>= 12; 6 | P_i = virtual_address & 0x1ff; 7 | virtual_address >>= 9; 8 | PT_i = virtual_address & 0x1ff; 9 | virtual_address >>= 9; 10 | PD_i = virtual_address & 0x1ff; 11 | virtual_address >>= 9; 12 | PDP_i = virtual_address & 0x1ff; 13 | } -------------------------------------------------------------------------------- /src/paging/page_table_manager.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | PageTableManager g_page_table_manager = NULL; 10 | 11 | //#PageTableManager::PageTableManager-doc: Constructor for the PageTableManager class. Needs a physical address of the page table to be used. 12 | PageTableManager::PageTableManager(PageTable* PML4_address){ 13 | this->PML4 = PML4_address; 14 | } 15 | 16 | //#PageTableManager::map_memory-doc: Map a page of memory to a virtual address. 17 | void PageTableManager::map_memory(void* virtual_memory, void* physical_memory){ 18 | PageMapIndexer indexer = PageMapIndexer((uint64_t)virtual_memory); 19 | PageDirectoryEntry PDE; 20 | 21 | PDE = PML4->entries[indexer.PDP_i]; 22 | PageTable* PDP; 23 | if (!PDE.get_flag(PT_Flag::present)){ 24 | PDP = (PageTable*)global_allocator.request_page(); 25 | memset(PDP, 0, 0x1000); 26 | PDE.set_address((uint64_t)PDP >> 12); 27 | PDE.set_flag(PT_Flag::present, true); 28 | PDE.set_flag(PT_Flag::read_write, true); 29 | PML4->entries[indexer.PDP_i] = PDE; 30 | } 31 | else 32 | { 33 | PDP = (PageTable*)((uint64_t)PDE.get_address() << 12); 34 | } 35 | 36 | 37 | PDE = PDP->entries[indexer.PD_i]; 38 | PageTable* PD; 39 | if (!PDE.get_flag(PT_Flag::present)){ 40 | PD = (PageTable*)global_allocator.request_page(); 41 | memset(PD, 0, 0x1000); 42 | PDE.set_address((uint64_t)PD >> 12); 43 | PDE.set_flag(PT_Flag::present, true); 44 | PDE.set_flag(PT_Flag::read_write, true); 45 | PDP->entries[indexer.PD_i] = PDE; 46 | } 47 | else 48 | { 49 | PD = (PageTable*)((uint64_t)PDE.get_address() << 12); 50 | } 51 | 52 | PDE = PD->entries[indexer.PT_i]; 53 | PageTable* PT; 54 | if (!PDE.get_flag(PT_Flag::present)){ 55 | PT = (PageTable*)global_allocator.request_page(); 56 | memset(PT, 0, 0x1000); 57 | PDE.set_address((uint64_t)PT >> 12); 58 | PDE.set_flag(PT_Flag::present, true); 59 | PDE.set_flag(PT_Flag::read_write, true); 60 | PD->entries[indexer.PT_i] = PDE; 61 | } 62 | else 63 | { 64 | PT = (PageTable*)((uint64_t)PDE.get_address() << 12); 65 | } 66 | 67 | PDE = PT->entries[indexer.P_i]; 68 | PDE.set_address((uint64_t)physical_memory >> 12); 69 | PDE.set_flag(PT_Flag::present, true); 70 | PDE.set_flag(PT_Flag::read_write, true); 71 | PT->entries[indexer.P_i] = PDE; 72 | } 73 | 74 | //#PageTableManager::map_range-doc: Map a range of physical memory to virtual memory. 75 | void PageTableManager::map_range(void* virtual_memory, void* physical_memory, size_t range) { 76 | for (int i = 0; i < range; i += 1000) { 77 | g_page_table_manager.map_memory((void*) ((uint64_t) virtual_memory + i), (void*) ((uint64_t) physical_memory + i)); 78 | } 79 | } -------------------------------------------------------------------------------- /src/paging/paging.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //#PageDirectoryEntry::set_flag-doc: Set a flag from a page directory entry. 4 | void PageDirectoryEntry::set_flag(PT_Flag flag, bool enabled){ 5 | uint64_t bit_selector = (uint64_t)1 << flag; 6 | value &= ~bit_selector; 7 | if (enabled){ 8 | value |= bit_selector; 9 | } 10 | } 11 | 12 | //#PageDirectoryEntry::get_flag-doc: Get a flag from a page directory entry. 13 | bool PageDirectoryEntry::get_flag(PT_Flag flag){ 14 | uint64_t bit_selector = (uint64_t)1 << flag; 15 | return value & bit_selector > 0 ? true : false; 16 | } 17 | 18 | //#PageDirectoryEntry::get_address-doc: Get the address of the page directory entry. 19 | uint64_t PageDirectoryEntry::get_address(){ 20 | return (value & 0x000ffffffffff000) >> 12; 21 | } 22 | 23 | //#PageDirectoryEntry::set_address-doc: Set the address of the page directory entry. 24 | void PageDirectoryEntry::set_address(uint64_t address){ 25 | address &= 0x000000ffffffffff; 26 | value &= 0xfff0000000000fff; 27 | value |= (address << 12); 28 | } -------------------------------------------------------------------------------- /src/pci/acpi.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace pci; 4 | using namespace pci::acpi; 5 | 6 | //#pci::acpi::find_table_xsdt-doc: Find a table in the ACPI namespace using the xsdt header. 7 | void* pci::acpi::find_table_xsdt(sdt_header_t* sdt_header, char* signature) { 8 | int entries = (sdt_header->length - sizeof(sdt_header_t)) / 8; 9 | 10 | for(int t = 0; t < entries; t++) { 11 | sdt_header_t* new_header = (sdt_header_t*) * (uint64_t*) ((uint64_t) sdt_header + sizeof(sdt_header_t) + (t * 8)); 12 | for(int i = 0; i < 4; i++) { 13 | if(new_header->signature[i] != signature[i]) { 14 | break; 15 | } 16 | if(i == 3) { 17 | return new_header; 18 | } 19 | } 20 | } 21 | return 0; 22 | } 23 | 24 | //#pci::acpi::find_table_rsdt-doc: Find a table in the ACPI namespace using the rsdt header. 25 | void* pci::acpi::find_table_rsdt(sdt_header_t* sdt_header, char* signature) { 26 | int entries = (sdt_header->length - sizeof(sdt_header_t)) / 4; 27 | 28 | for(int t = 0; t < entries; t++) { 29 | sdt_header_t* new_header = (sdt_header_t*) (uint64_t) * (uint32_t*) ((uint64_t) sdt_header + sizeof(sdt_header_t) + (t * 4)); 30 | for(int i = 0; i < 4; i++) { 31 | if(new_header->signature[i] != signature[i]) { 32 | break; 33 | } 34 | if(i == 3) { 35 | return new_header; 36 | } 37 | } 38 | } 39 | return 0; 40 | } -------------------------------------------------------------------------------- /src/pci/pci_bar.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace pci; 6 | 7 | //#read_bar-doc: Read the mask of the BAR. 8 | void read_bar(uint32_t* mask, uint16_t bus, uint16_t device, uint16_t function, uint32_t offset) { 9 | uint32_t data = pci::pci_readd(bus, device, function, offset); 10 | pci::pci_writed(bus, device, function, offset, 0xffffffff); 11 | *mask = pci::pci_readd(bus, device, function, offset); 12 | pci::pci_writed(bus, device, function, offset, data); 13 | } 14 | 15 | //#pci::get_bar-doc: Get a pci bar with some more information about it. The information is: bar type, size, and address. 16 | pci_bar_t pci::get_bar(uint32_t* bar0, int bar_num, uint16_t bus, uint16_t device, uint16_t function) { 17 | pci_bar_t bar; 18 | uint32_t* bar_ptr = (uint32_t*) (bar0 + bar_num * sizeof(uint32_t)); 19 | 20 | if (*bar_ptr) { 21 | uint32_t mask; 22 | read_bar(&mask, bus, device, function, bar_num * sizeof(uint32_t)); 23 | 24 | if (*bar_ptr & 0x04) { //64-bit mmio 25 | bar.type = pci_bar_type_t::MMIO64; 26 | 27 | uint32_t* bar_ptr_high = (uint32_t*) (bar0 + bar_num * sizeof(uint32_t)); 28 | uint32_t mask_high; 29 | read_bar(&mask_high, bus, device, function, (bar_num * sizeof(uint32_t)) + 0x4); 30 | 31 | bar.mem_address = ((uint64_t) (*bar_ptr_high & ~0xf) << 32) | (*bar_ptr & ~0xf); 32 | bar.size = (((uint64_t) mask_high << 32) | (mask & ~0xf)) + 1; 33 | } else if (*bar_ptr & 0x01) { //IO 34 | bar.type = pci_bar_type_t::IO; 35 | 36 | bar.io_address = (uint16_t)(*bar_ptr & ~0x3); 37 | bar.size = (uint16_t)(~(mask & ~0x3) + 1); 38 | } else { //32-bit mmio 39 | bar.type = pci_bar_type_t::MMIO32; 40 | 41 | bar.mem_address = (uint64_t) *bar_ptr & ~0xf; 42 | bar.size = ~(mask & ~0xf) + 1; 43 | } 44 | } else { 45 | bar.type = pci_bar_type_t::NONE; 46 | } 47 | 48 | return bar; 49 | } 50 | 51 | //#pci::get_io_port-doc: Get the IO port address of the device. If the device doesn't have an IO port, 0 is returned. 52 | uint16_t pci::get_io_port(pci::pci_header_0_t* header, uint16_t bus, uint16_t device, uint16_t function) { 53 | uint16_t port = 0; 54 | 55 | for (int i = 0; i < 6; i++) { 56 | uint32_t* bar_ptr = (uint32_t*) (&header->BAR0 + i * sizeof(uint32_t)); 57 | pci::pci_bar_t pci_bar = pci::get_bar(&header->BAR0, i, bus, device, function); 58 | 59 | if (pci_bar.type == pci::pci_bar_type_t::IO) { 60 | port = pci_bar.io_address; 61 | break; 62 | } 63 | } 64 | 65 | return port; 66 | } -------------------------------------------------------------------------------- /src/port.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //#Port8Bit::Port8Bit-doc: Costructor for the Port8Bit class. Takes the port number as an argument. 4 | Port8Bit::Port8Bit(uint16_t port){ 5 | portnumber = port; 6 | offset = 0; 7 | } 8 | 9 | //#Port8Bit::~Port8Bit-doc: Empty destructor. 10 | Port8Bit::~Port8Bit(){ 11 | 12 | } 13 | 14 | //#Port8Bit::Read-doc: Reads a byte from the port. 15 | uint8_t Port8Bit::Read(){ 16 | uint8_t result; 17 | __asm__ ("inb %1, %0" : "=a" (result) : "Nd" ((uint16_t) portnumber + offset)); 18 | return result; 19 | } 20 | 21 | //#Port8Bit::Write-doc: Writes a byte to the port. 22 | void Port8Bit::Write(uint8_t data){ 23 | __asm__ ("outb %0, %1" : : "a" (data), "Nd" ((uint16_t) portnumber + offset)); 24 | } 25 | 26 | //#Port16Bit::Port16Bit-doc: Costructor for the Port16Bit class. Takes the port number as an argument. 27 | Port16Bit::Port16Bit(uint16_t port){ 28 | portnumber = port; 29 | offset = 0; 30 | } 31 | 32 | //#Port16Bit::~Port16Bit-doc: Empty destructor. 33 | Port16Bit::~Port16Bit(){ 34 | 35 | } 36 | 37 | //#Port16Bit::Read-doc: Reads a word from the port. 38 | uint16_t Port16Bit::Read(){ 39 | uint16_t result; 40 | __asm__ volatile("inw %1, %0" : "=a" (result) : "Nd" ((uint16_t) portnumber + offset)); 41 | return result; 42 | } 43 | 44 | //#Port16Bit::Write-doc: Writes a word to the port. 45 | void Port16Bit::Write(uint16_t data){ 46 | asm volatile ("outw %0, %1" : : "a" (data), "Nd" ((uint16_t) portnumber + offset)); 47 | } 48 | 49 | //#Port32Bit::Port32Bit-doc: Costructor for the Port32Bit class. Takes the port number as an argument. 50 | Port32Bit::Port32Bit(uint16_t port){ 51 | portnumber = port; 52 | offset = 0; 53 | } 54 | 55 | //#Port32Bit::~Port32Bit-doc: Empty destructor. 56 | Port32Bit::~Port32Bit(){ 57 | 58 | } 59 | 60 | //#Port32Bit::Read-doc: Reads a dword from the port. 61 | uint32_t Port32Bit::Read(){ 62 | uint32_t result; 63 | asm volatile ("inl %1, %0" : "=a" (result) : "d" ((uint16_t) portnumber + offset)); 64 | return result; 65 | } 66 | 67 | //#Port32Bit::Write-doc: Writes a dword to the port. 68 | void Port32Bit::Write(uint32_t data){ 69 | asm volatile ("outl %0, %1" : : "a" (data), "Nd" ((uint16_t) portnumber + offset)); 70 | } 71 | 72 | //#io_wait-doc: Waits for the I/O port to be ready. 73 | void io_wait() { 74 | asm volatile ("outb %%al, $0x80" : : "a"(0)); 75 | } 76 | 77 | //#inb-doc: Reads a byte from the I/O port. 78 | unsigned char inb(unsigned short _port){ 79 | unsigned char result; 80 | __asm__ ("inb %1, %0" : "=a" (result) : "Nd" (_port)); 81 | return result; 82 | } 83 | 84 | //#outb-doc: Writes a byte to the I/O port. 85 | void outb(unsigned short _port, unsigned char _data){ 86 | __asm__ ("outb %0, %1" : : "a" (_data), "Nd" (_port)); 87 | } 88 | 89 | //#inw-doc: Reads a word from the I/O port. 90 | uint16_t inw(uint16_t _port) { 91 | uint16_t result; 92 | __asm__ volatile("inw %1, %0" : "=a" (result) : "Nd" (_port)); 93 | return result; 94 | } 95 | 96 | //#outw-doc: Writes a word to the I/O port. 97 | void outw(uint16_t _port, uint16_t data) { 98 | asm volatile ("outw %0, %1" : : "a" (data), "Nd" (_port)); 99 | } 100 | 101 | //#inl-doc: Reads a dword from the I/O port. 102 | uint32_t inl(uint16_t _port) { 103 | uint32_t result; 104 | __asm__ volatile("inl %1, %0" : "=a" (result) : "Nd" (_port)); 105 | return result; 106 | } 107 | 108 | //#outl-doc: Writes a dword to the I/O port. 109 | void outl(uint16_t _port, uint32_t data) { 110 | asm volatile ("outl %0, %1" : : "a" (data), "Nd" (_port)); 111 | } -------------------------------------------------------------------------------- /src/power.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | //#do_reboot-doc: Reboot FoxOS 7 | void do_reboot() { 8 | uint8_t good = 0x02; 9 | while (good & 0x02) { 10 | good = inb(0x64); 11 | } 12 | 13 | outb(0x64, 0xfe); 14 | asm("hlt"); 15 | 16 | interrupts::Panic p = interrupts::Panic((char*) "Reboot failed!"); 17 | p.do_it(NULL); 18 | } -------------------------------------------------------------------------------- /src/renderer/layer_copy.asm: -------------------------------------------------------------------------------- 1 | [bits 64] 2 | [global do_copy] 3 | 4 | ; void do_copy(void* target, void* source, size_t size); 5 | ; rdi = target; 6 | ; rsi = source; 7 | ; rdx = size (/sizeof(uint32_t)); 8 | 9 | ;# do_copy-signature: extern "C" void do_copy(void* target, void* source, size_t size); 10 | ;# do_copy-doc: This function copies data from one memory location to another. It does not overwrite the target memory location if the source memory location is 0. 11 | 12 | do_copy: 13 | push r8 14 | push rcx 15 | 16 | mov rcx, rdx 17 | 18 | .copy_loop: 19 | 20 | mov eax, [rsi + rcx * 4] 21 | 22 | cmp eax, dword 0 23 | je .skip_copy 24 | 25 | mov [rdi + rcx * 4], eax 26 | 27 | .skip_copy: 28 | loop .copy_loop 29 | 30 | pop rcx 31 | pop r8 32 | 33 | ret -------------------------------------------------------------------------------- /src/renderer/layer_renderer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace renderer; 8 | 9 | //#renderer::allocate_layer_matching-doc: Allocates a new layer matching the given framebuffer configuration. 10 | layer_t* renderer::allocate_layer_matching(framebuffer_t* target_frame_buffer) { 11 | layer_t* layer = (layer_t*) malloc(sizeof(layer_t)); 12 | 13 | memcpy(layer, target_frame_buffer, sizeof(layer_t)); 14 | 15 | // allocate new frame buffer for new layer 16 | layer->base_address = global_allocator.request_pages((layer->buffer_size / 0x1000) + 1); 17 | 18 | memset(layer->base_address, 0, layer->buffer_size); 19 | 20 | return layer; 21 | } 22 | 23 | 24 | //#renderer::destroy_layer-doc: Destroys a layer. 25 | void renderer::destroy_layer(layer_t* layer) { 26 | global_allocator.free_pages(layer->base_address, (layer->buffer_size / 0x1000) + 1); 27 | free(layer); 28 | } 29 | 30 | //#layer_renderer::layer_renderer-doc: Layer renderer constructor. Takes a target framebuffer. 31 | layer_renderer::layer_renderer(framebuffer_t* target_frame_buffer) { 32 | this->target_frame_buffer = target_frame_buffer; 33 | 34 | buffer = global_allocator.request_pages((target_frame_buffer->buffer_size / 0x1000) + 1); 35 | } 36 | 37 | //#layer_renderer::~layer_renderer-doc: Destructor for the layer renderer. 38 | layer_renderer::~layer_renderer() { 39 | global_allocator.free_pages(buffer,(target_frame_buffer->buffer_size / 0x1000) + 1); 40 | } 41 | 42 | extern "C" void do_copy(void* target, void* source, size_t size); 43 | 44 | //#layer_renderer::render_layer-doc: Renders a layer to the buffer. If the layer is the first layer please set the base_layer to true. 45 | void layer_renderer::render_layer(layer_t* layer, bool base_layer) { 46 | 47 | if (base_layer) { 48 | // copy base layer to frame buffer 49 | memcpy(buffer, layer->base_address, layer->buffer_size); 50 | } else { 51 | do_copy(buffer, layer->base_address, layer->buffer_size / sizeof(uint32_t)); 52 | } 53 | } 54 | 55 | //#layer_renderer::render-doc: Renders the buffer to the target framebuffer. 56 | void layer_renderer::render() { 57 | memcpy(target_frame_buffer->base_address, buffer, target_frame_buffer->buffer_size); 58 | } -------------------------------------------------------------------------------- /src/renderer/mouse_renderer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace renderer; 6 | 7 | MouseRenderer* renderer::global_mouse_renderer; 8 | 9 | uint8_t MousePointer[] = { 10 | 0b10000000, 0b00000000, 11 | 0b11000000, 0b00000000, 12 | 0b11100000, 0b00000000, 13 | 0b11110000, 0b00000000, 14 | 0b11111000, 0b00000000, 15 | 0b11111100, 0b00000000, 16 | 0b11111110, 0b00000000, 17 | 0b11111111, 0b00000000, 18 | 0b11111111, 0b10000000, 19 | 0b11111111, 0b11000000, 20 | 0b11111100, 0b00000000, 21 | 0b11101100, 0b00000000, 22 | 0b11000110, 0b00000000, 23 | 0b10000110, 0b00000000, 24 | 0b00000011, 0b00000000, 25 | 0b00000011, 0b00000000, 26 | }; 27 | 28 | //#MouseRenderer::MouseRenderer-doc: MouseRenderer constructor. 29 | MouseRenderer::MouseRenderer() { 30 | this->mouse_pointer = MousePointer; 31 | } 32 | 33 | //#MouseRenderer::get_mouse_pointer-doc: Get the mouse pointer data. 34 | uint8_t* MouseRenderer::get_mouse_pointer() { 35 | return this->mouse_pointer; 36 | } 37 | 38 | //#MouseRenderer::on_mouse_down-doc: Called when a mouse button is pressed. Currently draws dots on the screen. 39 | void MouseRenderer::on_mouse_down(uint8_t button) { 40 | if (button == 1) { //Left 41 | global_renderer2D->put_pix(mouse_position.x, mouse_position.y, 0xff00ff00); 42 | } else if (button == 2) { //Right 43 | global_renderer2D->put_pix(mouse_position.x, mouse_position.y, 0xff0000ff); 44 | } else if (button == 3) { //Middle 45 | global_renderer2D->put_pix(mouse_position.x, mouse_position.y, 0xffff0000); 46 | } 47 | } 48 | 49 | //#MouseRenderer::on_mouse_move-doc: Called when the mouse is moved. Re-draw the cursor to a new position. 50 | void MouseRenderer::on_mouse_move(uint8_t mouse_packet[4]) { 51 | bool xNegative, yNegative, xOverflow, yOverflow; 52 | 53 | if (mouse_packet[0] & PS2XSign) { 54 | xNegative = true; 55 | } else xNegative = false; 56 | 57 | if (mouse_packet[0] & PS2YSign) { 58 | yNegative = true; 59 | } else yNegative = false; 60 | 61 | if (mouse_packet[0] & PS2XOverflow) { 62 | xOverflow = true; 63 | } else xOverflow = false; 64 | 65 | if (mouse_packet[0] & PS2YOverflow) { 66 | yOverflow = true; 67 | } else yOverflow = false; 68 | 69 | if (!xNegative) { 70 | mouse_position.x += mouse_packet[1]; 71 | if (xOverflow){ 72 | mouse_position.x += 255; 73 | } 74 | } else { 75 | mouse_packet[1] = 256 - mouse_packet[1]; 76 | mouse_position.x -= mouse_packet[1]; 77 | if (xOverflow){ 78 | mouse_position.x -= 255; 79 | } 80 | } 81 | 82 | if (!yNegative) { 83 | mouse_position.y -= mouse_packet[2]; 84 | if (yOverflow){ 85 | mouse_position.y -= 255; 86 | } 87 | } else { 88 | mouse_packet[2] = 256 - mouse_packet[2]; 89 | mouse_position.y += mouse_packet[2]; 90 | if (yOverflow){ 91 | mouse_position.y += 255; 92 | } 93 | } 94 | 95 | if (mouse_position.x < 0) mouse_position.x = 0; 96 | if (mouse_position.x > global_renderer2D->target_frame_buffer->width-1) mouse_position.x = global_renderer2D->target_frame_buffer->width-1; 97 | 98 | if (mouse_position.y < 0) mouse_position.y = 0; 99 | if (mouse_position.y > global_renderer2D->target_frame_buffer->height-1) mouse_position.y = global_renderer2D->target_frame_buffer->height-1; 100 | 101 | global_renderer2D->clear_mouse_cursor(get_mouse_pointer(), mouse_position_old); 102 | global_renderer2D->draw_overlay_mouse_cursor(get_mouse_pointer(), mouse_position, 0xffffffff); 103 | 104 | mouse_position_old = mouse_position; 105 | } -------------------------------------------------------------------------------- /src/renderer/redirect_serial_to_screen.asm: -------------------------------------------------------------------------------- 1 | [bits 64] 2 | [extern _Z5patchPcm] 3 | 4 | [extern _ZN8renderer12FontRenderer6printfEPKcz] 5 | [extern _ZN8renderer12FontRenderer4putcEc] 6 | [extern _ZN8renderer12FontRenderer4putnEmi] 7 | [extern _ZN8renderer12FontRenderer4putsEPKc] 8 | 9 | [extern _ZN8renderer20global_font_rendererE] 10 | [global write_serial_to_screen_redirection] 11 | 12 | ; #serial_to_screen_printf-discard 13 | 14 | serial_to_screen_printf: 15 | mov rdi, [_ZN8renderer20global_font_rendererE] 16 | jmp _ZN8renderer12FontRenderer6printfEPKcz 17 | 18 | ; #serial_to_screen_putc-discard 19 | 20 | serial_to_screen_putc: 21 | mov rdi, [_ZN8renderer20global_font_rendererE] 22 | jmp _ZN8renderer12FontRenderer4putcEc 23 | 24 | ; #serial_to_screen_putn-discard 25 | 26 | serial_to_screen_putn: 27 | mov rdi, [_ZN8renderer20global_font_rendererE] 28 | jmp _ZN8renderer12FontRenderer4putnEmi 29 | 30 | ; #serial_to_screen_puts-discard 31 | 32 | serial_to_screen_puts: 33 | mov rdi, [_ZN8renderer20global_font_rendererE] 34 | jmp _ZN8renderer12FontRenderer4putsEPKc 35 | 36 | ; #write_serial_to_screen_redirection-signature: void write_serial_to_screen_redirection(); 37 | ; #write_serial_to_screen_redirection-doc: Redirects serial output to the screen. Used for testing on real hardware with no serial port. 38 | 39 | write_serial_to_screen_redirection: 40 | mov rdi, .serial_printf_str 41 | mov rsi, serial_to_screen_printf 42 | call _Z5patchPcm 43 | 44 | mov rdi, .serial_putc_str 45 | mov rsi, serial_to_screen_putc 46 | call _Z5patchPcm 47 | 48 | mov rdi, .serial_putn_str 49 | mov rsi, serial_to_screen_putn 50 | call _Z5patchPcm 51 | 52 | mov rdi, .serial_puts_str 53 | mov rsi, serial_to_screen_puts 54 | call _Z5patchPcm 55 | 56 | ret 57 | 58 | .serial_printf_str: db "_ZN6driver6Serial6printfEPKcz", 0 59 | .serial_putc_str: db "_ZN6driver6Serial4putcEc", 0 60 | .serial_putn_str: db "_ZN6driver6Serial4putnEmi", 0 61 | .serial_puts_str: db "_ZN6driver6Serial4putsEPKc", 0 -------------------------------------------------------------------------------- /src/scheduling/hpet/hpet.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace hpet; 6 | 7 | hpet_t* hpet_ = nullptr; 8 | 9 | //#hpet::init_hpet-doc: Initialise the HPET. 10 | void hpet::init_hpet(pci::acpi::hpet_table_t* hpet_table) { 11 | hpet_ = (hpet_t*) hpet_table->address; 12 | 13 | g_page_table_manager.map_memory(hpet_, hpet_); 14 | 15 | hpet_->general_config = 1; 16 | 17 | driver::global_serial_driver->printf("HPET at 0x%x\n", hpet_); 18 | } 19 | 20 | //#hpet::sleep-doc: Sleep for an amount of milliseconds. 21 | void hpet::sleep(uint64_t ms) { 22 | ms /= 8; 23 | uint64_t ticks = hpet_->counter_value + (ms * 1000000000000) / ((hpet_->capabilities >> 32) & 0xffffffff); 24 | 25 | while (hpet_->counter_value < ticks) { 26 | asm volatile("pause" ::: "memory"); 27 | } 28 | } 29 | 30 | //#hpet::sleep_d-doc: Sleep for an amount of seconds. 31 | void hpet::sleep_d(uint64_t seconds) { 32 | sleep((uint64_t) (seconds * 1000)); 33 | } 34 | 35 | //#hpet::is_available-doc: Get if the HPET is available. 36 | bool hpet::is_available() { 37 | return hpet_ != nullptr; 38 | } -------------------------------------------------------------------------------- /src/scheduling/pit/pit.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace PIT { 8 | uint64_t time_since_boot = 0; 9 | 10 | uint16_t divisor = 65535; 11 | 12 | //#sleep-doc: Sleep for an amount of milliseconds. 13 | void sleep(uint64_t milliseconds) { 14 | sleep_d(milliseconds / 1000); 15 | } 16 | 17 | //#set_divisor-doc: Set a divisor. 18 | void set_divisor(uint16_t this_divisor) { 19 | if (divisor < 100) { 20 | divisor = 100; 21 | } 22 | divisor = this_divisor; 23 | 24 | Port8Bit port = Port8Bit(0x40); 25 | port.Write((uint8_t)(divisor & 0x00ff)); 26 | io_wait(); 27 | port.Write((uint8_t)(divisor & 0xff00) >> 8); 28 | } 29 | 30 | //#get_frequency-doc: Get the PIT's interrupt handler calling frequency. 31 | uint64_t get_frequency() { 32 | return base_frequency / divisor; 33 | } 34 | 35 | //#set_frequency-doc: Set the PIT's interrupt handler calling frequency. 36 | void set_frequency(uint64_t frequency) { 37 | set_divisor(base_frequency / frequency); 38 | } 39 | 40 | //#init_pit-doc: Initialise the PIT. 41 | void init_pit(uint64_t divisor) { 42 | interrupts::register_interrupt_handler(32, &pit_interrupt_handler); 43 | PIT::set_divisor(divisor); 44 | } 45 | 46 | //#pit_interrupt_handler-doc: Initialise the PIT interrupt handler. 47 | void pit_interrupt_handler(uint8_t ptr) { 48 | time_since_boot += 1; 49 | } 50 | 51 | //#sleep_d-doc: Sleep for an amount of seconds. 52 | void sleep_d(uint64_t seconds) { 53 | seconds *= get_frequency(); 54 | uint64_t start = time_since_boot; 55 | while (time_since_boot - start < seconds) { 56 | asm volatile("nop"); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/scheduling/scheduler/atomic.asm: -------------------------------------------------------------------------------- 1 | [bits 64] 2 | %macro CF_RESULT 0 3 | mov rcx, 1 4 | mov rax, 0 5 | cmovnc rax, rcx 6 | %endmacro 7 | 8 | ;# atomic_lock-signature: extern "C" bool atomic_lock(uint64_t* mutex, uint64_t bit); 9 | ;# atomic_lock-doc: Atomic set of a specific bit in a 64-bit value. 10 | 11 | [global atomic_lock] 12 | atomic_lock: 13 | lock bts qword [rdi], rsi 14 | CF_RESULT 15 | ret 16 | 17 | ;# atomic_unlock-signature: extern "C" bool atomic_unlock(uint64_t* mutex, uint64_t bit); 18 | ;# atomic_unlock-doc: Atomic clear of a specific bit in a 64-bit value. 19 | 20 | [global atomic_unlock] 21 | atomic_unlock: 22 | lock btr qword [rdi], rsi 23 | CF_RESULT 24 | ret 25 | 26 | ;# atomic_spinlock-signature: extern "C" void atomic_spinlock(uint64_t* mutex, uint64_t bit); 27 | ;# atomic_spinlock-doc: Atomic wait until a specific bit in a 64-bit value is cleared. 28 | 29 | [global atomic_spinlock] 30 | atomic_spinlock: 31 | .aquire: 32 | lock bts qword [rdi], rsi 33 | jnc .exit 34 | .spin: 35 | pause 36 | bt qword [rdi], rsi 37 | jc .spin 38 | jmp .aquire 39 | .exit: 40 | ret -------------------------------------------------------------------------------- /src/scheduling/scheduler/elf.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | //#ElfSymbolResolver::ElfSymbolResolver-doc: The constructor for the ElfSymbolResolver class. NOTE: the pointer to the raw elf file needs to contain a non loaded elf file. 6 | ElfSymbolResolver::ElfSymbolResolver(void* raw_elf_file) { 7 | Elf64_Ehdr* ehdr = (Elf64_Ehdr*) raw_elf_file; 8 | 9 | if(__builtin_bswap32(ehdr->e_ident.i) != elf::MAGIC) { 10 | return; // no elf 11 | } 12 | if(ehdr->e_ident.c[elf::EI_CLASS] != elf::ELFCLASS64) { 13 | return; // not 64 bit 14 | } 15 | 16 | Elf64_Shdr* shdr = (Elf64_Shdr*) ((char*) raw_elf_file + ehdr->e_shoff); 17 | this->sym_info.shdr = shdr; 18 | this->sym_info.shdr_count = ehdr->e_shnum; 19 | 20 | int section_sting_index = ehdr->e_shstrndx; 21 | 22 | for (int i = 0; i < this->sym_info.shdr_count; i++) { 23 | Elf64_Shdr* shdr = &this->sym_info.shdr[i]; 24 | if (shdr->sh_type == 0x2) { // symtab 25 | this->sym_info.sym_entries = (Elf64_Sym*) ((char*) raw_elf_file + shdr->sh_offset); 26 | this->sym_info.sym_count = shdr->sh_size / sizeof(Elf64_Sym); 27 | } else if (shdr->sh_type == 0x3) { // strtab 28 | if (section_sting_index == i) { 29 | this->sym_info.sect_str_table = (char*) raw_elf_file + shdr->sh_offset; 30 | this->sym_info.sect_str_table_size = shdr->sh_size; 31 | } else { 32 | this->sym_info.sym_str_table = (char*) raw_elf_file + shdr->sh_offset; 33 | this->sym_info.sym_str_table_size = shdr->sh_size; 34 | } 35 | } 36 | } 37 | } 38 | 39 | //#ElfSymbolResolver::resolve-doc: Resolve a symbol either to a string or to a address. 40 | void* ElfSymbolResolver::resolve(char* symbol_name) { 41 | for (int i = 0; i < this->sym_info.sym_count; i++) { 42 | Elf64_Sym* sym = &this->sym_info.sym_entries[i]; 43 | if (sym->st_value == 0) { 44 | continue; 45 | } 46 | 47 | if(strcmp(&this->sym_info.sym_str_table[sym->st_name], symbol_name) == 0) { 48 | return (void*) sym->st_value; 49 | } 50 | } 51 | 52 | return nullptr; 53 | } 54 | 55 | char* ElfSymbolResolver::resolve(void* symbol_addr) { 56 | for (int i = 0; i < this->sym_info.sym_count; i++) { 57 | Elf64_Sym* sym = &this->sym_info.sym_entries[i]; 58 | if (sym->st_value == 0) { 59 | continue; 60 | } 61 | 62 | if((uint64_t) symbol_addr >= (uint64_t) sym->st_value && (uint64_t) symbol_addr < (uint64_t) sym->st_value + sym->st_size) { 63 | return &this->sym_info.sym_str_table[sym->st_name] ; 64 | } 65 | } 66 | 67 | return (char*) ""; 68 | } -------------------------------------------------------------------------------- /src/scheduling/scheduler/errno.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define ASSERT_NO_PANIC // dont panic 5 | #include 6 | 7 | //#set_task_errno-doc: Set the error number of the current task. 8 | 9 | void set_task_errno(int errno) { 10 | int id; 11 | __asm__ __volatile__ ("mov $1, %%eax; cpuid; shrl $24, %%ebx;": "=b"(id) : : ); 12 | 13 | task* t = (task*) task_queue[id].list[0]; 14 | 15 | assert(t->errno != NULL); 16 | 17 | *t->errno = errno; 18 | 19 | assert_fail: 20 | return; 21 | } -------------------------------------------------------------------------------- /src/scheduling/scheduler/fxsr.asm: -------------------------------------------------------------------------------- 1 | [bits 64] 2 | 3 | ;# _fxsave_if_supported-signature: extern "C" void _fxsave_if_supported(char* buffer) 4 | ;# _fxsave_if_supported-doc: C wrapper for the fxsave instruction. 5 | 6 | [global _fxsave_if_supported] 7 | _fxsave_if_supported: 8 | mov rax, 1 9 | cpuid 10 | and edx, 1 << 24 ; check for FXSR 11 | test edx, edx 12 | je .exit 13 | 14 | fxsave [rdi] 15 | 16 | .exit: 17 | ret 18 | 19 | ;# _fxrstor_if_supported-signature: extern "C" void _fxrstor_if_supported(char* buffer) 20 | ;# _fxrstor_if_supported-doc: C wrapper for the fxrstor instruction. 21 | 22 | [global _fxrstor_if_supported] 23 | _fxrstor_if_supported: 24 | mov rax, 1 25 | cpuid 26 | and edx, 1 << 24 ; check for FXSR 27 | test edx, edx 28 | je .exit 29 | 30 | fxrstor [rdi] 31 | 32 | .exit 33 | ret -------------------------------------------------------------------------------- /src/scheduling/scheduler/queue.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //#uint64_t_queue::uint64_t_queue-doc: Constructor for the uint64_t_queue class. 4 | 5 | uint64_t_queue::uint64_t_queue() { 6 | this->len = 0; 7 | this->list[0] = 0; 8 | } 9 | 10 | //#uint64_t_queue::~uint64_t_queue-doc: Empty destructor for the uint64_t_queue class. 11 | uint64_t_queue::~uint64_t_queue() { 12 | } 13 | 14 | //#uint64_t_queue::add-doc: Add an element to the queue. 15 | void uint64_t_queue::add(uint64_t num) { 16 | this->list[this->len] = num; 17 | this->len++; 18 | } 19 | 20 | //#uint64_t_queue::next-doc: Rotate the queue to the next element. 21 | void uint64_t_queue::next() { 22 | this->list[this->len] = this->list[0]; 23 | for (int i = 0; i < this->len; i++) { 24 | this->list[i] = this->list[i + 1]; 25 | } 26 | } 27 | 28 | //#uint64_t_queue::remove_first-doc: Remove the first element from the queue. 29 | void uint64_t_queue::remove_first() { 30 | this->list[this->len] = this->list[0]; 31 | 32 | for (int i = 0; i < this->len; i++) { 33 | this->list[i] = this->list[i + 1]; 34 | } 35 | len--; 36 | } -------------------------------------------------------------------------------- /src/scheduling/scheduler/signal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define ASSERT_NO_PANIC // dont panic 5 | #include 6 | 7 | //#handle_signal-doc: Handels a signal. Calls the signal handler witch the current task has registered. Returns false if there is no handler registered. 8 | bool handle_signal(int signum) { 9 | int id; 10 | task* t; 11 | __asm__ __volatile__ ("mov $1, %%eax; cpuid; shrl $24, %%ebx;": "=b"(id) : : ); 12 | 13 | assert(scheduling == true); 14 | 15 | t = (task*) task_queue[id].list[0]; 16 | assert(t->signals[signum] != NULL); 17 | t->signals[signum](signum); 18 | return true; 19 | 20 | assert_fail: 21 | return false; 22 | } 23 | 24 | //#register_signal_handler-doc: Registers a signal handler for a signal for the current task. 25 | void register_signal_handler(int signum, uint64_t handler) { 26 | int id; 27 | task* t; 28 | __asm__ __volatile__ ("mov $1, %%eax; cpuid; shrl $24, %%ebx;": "=b"(id) : : ); 29 | 30 | t = (task*) task_queue[id].list[0]; 31 | t->signals[signum] = (signal_handler) handler; 32 | } -------------------------------------------------------------------------------- /src/scheduling/scheduler/task_entry.asm: -------------------------------------------------------------------------------- 1 | [bits 64] 2 | [extern _Z9task_exitv] 3 | [global task_entry] 4 | 5 | ; NOTE: the addres to the target task needs to be in rax 6 | ; we do this to prevent jumping to random code if the task returns 7 | 8 | ;# task_entry-signature: void task_entry() 9 | ;# task_entry-doc: The main entry point for a task. Marks the bottom of the new stack and jumps to the adress in rax. 10 | 11 | task_entry: 12 | sti 13 | mov rbp, 0 ; mark bottom of stack trace 14 | call rax 15 | 16 | .exit: 17 | call _Z9task_exitv ; if the task ever returns just exit 18 | 19 | jmp $ -------------------------------------------------------------------------------- /src/scheduling/scheduler/xsave.asm: -------------------------------------------------------------------------------- 1 | [bits 64] 2 | 3 | ;# _test_xsave_support-signature: extern "C" bool _test_xsave_support(); 4 | ;# _test_xsave_support-doc: Test if the processor supports the XSAVE instruction. 5 | 6 | [global _test_xsave_support] 7 | _test_xsave_support: 8 | mov rax, 1 9 | cpuid 10 | and ecx, 1 << 26 ; check for XSAVE support 11 | test ecx, ecx 12 | je .exit_fail 13 | jne .exit_ok 14 | 15 | .exit_fail: 16 | mov rax, 0 17 | ret 18 | 19 | .exit_ok: 20 | mov rax, 1 21 | ret 22 | 23 | ;# _enable_xsave-signature: extern "C" void _enable_xsave(); 24 | ;# _enable_xsave-doc: Enable the XSAVE instruction. 25 | 26 | [global _enable_xsave] 27 | _enable_xsave: 28 | mov rax, cr0 29 | xor rax, 1 << 3 30 | mov cr0, rax 31 | 32 | mov rax, cr4 33 | or eax, 1 << 18 34 | mov cr4, rax 35 | 36 | ret 37 | 38 | ;# _get_xsave_area_size-signature: extern "C" uint64_t _get_xsave_area_size(); 39 | ;# _get_xsave_area_size-doc: Get the size of the XSAVE area. 40 | 41 | [global _get_xsave_area_size] 42 | _get_xsave_area_size: 43 | mov rax, 0xd 44 | mov rcx, 0 45 | cpuid 46 | mov rax, rcx 47 | ret 48 | 49 | ;# _xsave_if_supported-signature: extern "C" void _xsave_if_supported(void* buffer); 50 | ;# _xsave_if_supported-doc: Save the extendet cpu state to the XSAVE area if the processor supports it. 51 | 52 | [global _xsave_if_supported] 53 | _xsave_if_supported: 54 | call _test_xsave_support 55 | test rax, rax 56 | je .exit 57 | 58 | mov rax, 0xFFFFFFFFFFFFFFFF 59 | mov rdx, 0xFFFFFFFFFFFFFFFF 60 | 61 | xsave [rdi] 62 | .exit: 63 | ret 64 | 65 | ;# _xrstor_if_supported-signature: extern "C" void _xrstor_if_supported(void* buffer); 66 | ;# _xrstor_if_supported-doc: Restore the extended cpu state from the XSAVE area if the processor supports it. 67 | 68 | [global _xrstor_if_supported] 69 | _xrstor_if_supported: 70 | call _test_xsave_support 71 | test rax, rax 72 | je .exit 73 | 74 | mov rax, 0xFFFFFFFFFFFFFFFF 75 | mov rdx, 0xFFFFFFFFFFFFFFFF 76 | 77 | xrstor [rdi] 78 | .exit: 79 | ret -------------------------------------------------------------------------------- /src/shell/shell.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | using namespace shell; 8 | 9 | Shell* shell::global_shell; 10 | 11 | //#Shell::Shell-doc: Empty constructor. 12 | Shell::Shell() { 13 | 14 | } 15 | 16 | void add_char(char c); 17 | bool is_reading(); 18 | 19 | //#Shell::keypress-doc: Used to handle keypresses. The function adds the key to a buffer. 20 | void Shell::keypress(char key) { 21 | if (key == 0) { 22 | return; 23 | } 24 | 25 | if (is_reading()) { 26 | renderer::global_font_renderer->printf("%c", key); 27 | add_char(key); 28 | return; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/stivale2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static unsigned char stack[0x4000]; 5 | 6 | #ifdef USE_STIVALE2_SMP 7 | static stivale2_header_tag_smp smp_tag = { 8 | .tag = { 9 | .identifier = STIVALE2_HEADER_TAG_SMP_ID, 10 | .next = 0, 11 | }, 12 | .flags = 1 // use x2APIC if aviable 13 | }; 14 | #endif 15 | 16 | static stivale2_header_tag_framebuffer framebuffer_tag = { 17 | .tag = { 18 | .identifier = STIVALE2_HEADER_TAG_FRAMEBUFFER_ID, 19 | #ifdef USE_STIVALE2_SMP 20 | .next = (uint64_t) &smp_tag, 21 | #else 22 | .next = 0, 23 | #endif 24 | }, 25 | .framebuffer_width = 0, 26 | .framebuffer_height = 0, 27 | .framebuffer_bpp = 32 28 | }; 29 | 30 | __attribute__((section(".stivale2hdr"), used)) 31 | static stivale2_header __stivale2_header = { 32 | .entry_point = 0, 33 | .stack = (uintptr_t) stack + sizeof(stack), 34 | .flags = 0, 35 | .tags = (uint64_t) &framebuffer_tag 36 | }; 37 | 38 | stivale2_struct* global_bootinfo; 39 | --------------------------------------------------------------------------------