├── .gitignore ├── README.md ├── src ├── kernel │ ├── h │ │ ├── int.h │ │ ├── string.h │ │ ├── lock.h │ │ ├── io.h │ │ ├── branch.h │ │ ├── multiboot.h │ │ ├── print.h │ │ └── types.h │ ├── main.c │ ├── string.c │ ├── io.c │ ├── print.c │ ├── int.c │ └── inthdl.asm └── boot │ ├── multiboot.asm │ ├── long.asm │ └── entry.asm ├── run.cmd ├── debug.cmd ├── env ├── spinup.cmd └── Dockerfile ├── linker.ld ├── workspace.code-workspace ├── .vscode ├── launch.json └── c_cpp_properties.json └── Makefile /.gitignore: -------------------------------------------------------------------------------- 1 | /build/obj 2 | /bin 3 | /snowman-v0.1.3-win-x86 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 64 bit hobby os. 2 | 3 | that's basically it 4 | -------------------------------------------------------------------------------- /src/kernel/h/int.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.h" 3 | 4 | Bool InitInterrupts(); 5 | -------------------------------------------------------------------------------- /run.cmd: -------------------------------------------------------------------------------- 1 | qemu-system-x86_64 -s -serial stdio -cdrom bin/kernel.iso -L "C:\Program Files\qemu" 2 | pause -------------------------------------------------------------------------------- /src/kernel/h/string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.h" 3 | 4 | Char *IntToString(Int value, Char *str, Byte base); -------------------------------------------------------------------------------- /debug.cmd: -------------------------------------------------------------------------------- 1 | qemu-system-x86_64 -device bochs-display -s -S -serial stdio -cdrom bin/kernel.iso -L "C:\Program Files\qemu" 2 | pause -------------------------------------------------------------------------------- /src/kernel/h/lock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.h" 3 | 4 | #define WAIT_UNTIL(expr) while(!(expr)); _Static_assert(True, "semicolon after WAIT_UNTIL") // force a semicolon -------------------------------------------------------------------------------- /env/spinup.cmd: -------------------------------------------------------------------------------- 1 | docker build env -t os 2 | 3 | docker run --rm -it -v %cd%:/root/env os 4 | 5 | D:\w64\bin\gdb.exe 6 | target remote localhost:1234 7 | file "C:/various_shit/os/bin/kernel.bin" -------------------------------------------------------------------------------- /src/kernel/h/io.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.h" 3 | 4 | UByte InByte(UShort port); 5 | void OutByte(UShort port, UByte data); 6 | void SerialPrint(Char *str); 7 | void SerialPrintln(Char *str); 8 | void SerialChar(Char ch); 9 | 10 | Bool InitSerial(); -------------------------------------------------------------------------------- /linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(start) 2 | 3 | SECTIONS 4 | { 5 | . = 1M; 6 | 7 | .boot : 8 | { 9 | KEEP(*(.multiboot)) 10 | } 11 | 12 | .text : 13 | { 14 | KEEP(*(.entry)) /* Put the loading code before everything else. Won't boot otherwise */ 15 | *(.text) 16 | } 17 | } -------------------------------------------------------------------------------- /env/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM randomdude/gcc-cross-x86_64-elf 2 | 3 | RUN apt-get update 4 | RUN apt-get upgrade -y 5 | RUN apt-get install -y fasm 6 | RUN apt-get install -y xorriso 7 | RUN apt-get install -y grub-pc-bin 8 | RUN apt-get install -y grub-common 9 | 10 | VOLUME /root/env 11 | WORKDIR /root/env -------------------------------------------------------------------------------- /src/boot/multiboot.asm: -------------------------------------------------------------------------------- 1 | format elf64 2 | 3 | section ".multiboot" 4 | 5 | MB_FLAGS = 0 and (1 shl 2) 6 | 7 | header_start: 8 | dd 0xe85250d6 9 | dd MB_FLAGS 10 | dd header_end - header_start 11 | dd 0x100000000 - (0xe85250d6 + MB_FLAGS + (header_end - header_start)) 12 | dd 0 13 | dd 0 ; 8? 14 | dd 0 15 | dd 0 16 | dd 0 17 | 18 | dd 0 ; video mode 19 | dd 80 20 | dd 50 21 | dd 0 22 | header_end: 23 | -------------------------------------------------------------------------------- /src/kernel/h/branch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define BRANCH(expr, tru, fls) \ 4 | if (expr) \ 5 | { \ 6 | tru \ 7 | } \ 8 | else \ 9 | { \ 10 | fls \ 11 | } \ 12 | _Static_assert(true, "semicolon after WAIT_UNTIL") // force a semicolon 13 | -------------------------------------------------------------------------------- /workspace.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": { 8 | "workbench.colorTheme": "Palenight (Mild Contrast)", 9 | "files.associations": { 10 | "print.h": "c", 11 | "multiboot.h": "c", 12 | "types.h": "c", 13 | "inttypes.h": "c", 14 | "stdint.h": "c", 15 | "string.h": "c", 16 | "io.h": "c", 17 | "stddef.h": "c", 18 | "branch.h": "c", 19 | "stdbool.h": "c" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/kernel/h/multiboot.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* The section header table for ELF. */ 4 | typedef struct elf_section_header_table 5 | { 6 | ULong num; 7 | ULong size; 8 | ULong addr; 9 | ULong shndx; 10 | } elf_section_header_table_t; 11 | 12 | typedef struct multiboot_info 13 | { 14 | ULong flags; 15 | ULong mem_lower; 16 | ULong mem_upper; 17 | ULong boot_device; 18 | ULong cmdline; 19 | ULong mods_count; 20 | ULong mods_addr; 21 | elf_section_header_table_t elf_sec; 22 | ULong mmap_length; 23 | ULong mmap_addr; 24 | } multiboot_info_t; -------------------------------------------------------------------------------- /src/boot/long.asm: -------------------------------------------------------------------------------- 1 | format elf64 2 | use64 3 | section ".entry" 4 | 5 | extrn kmain 6 | extrn Println 7 | public long_mode_start 8 | 9 | bruhmoment_message: db "You're back in long.asm bruh" 10 | 11 | long_mode_start: 12 | 13 | mov rax, rsp 14 | 15 | push 0x10 16 | push rax 17 | pushf 18 | push 0x08 19 | push .reload_segments 20 | iretq 21 | 22 | .reload_segments: 23 | mov ax, 0x10 24 | mov ss, ax 25 | mov ds, ax 26 | mov es, ax 27 | mov fs, ax 28 | mov gs, ax 29 | 30 | call kmain 31 | 32 | mov rdi, [bruhmoment_message] 33 | call Println 34 | 35 | hlt -------------------------------------------------------------------------------- /src/kernel/main.c: -------------------------------------------------------------------------------- 1 | #include "print.h" 2 | #include "multiboot.h" 3 | #include "string.h" 4 | #include "multiboot.h" 5 | #include "io.h" 6 | #include "int.h" 7 | #include "types.h" 8 | #include "branch.h" 9 | 10 | static inline void cpuid(int code, uint32_t *a, uint32_t *d) 11 | { 12 | asm volatile("cpuid" 13 | : "=a"(*a), "=d"(*d) 14 | : "a"(code) 15 | : "ecx", "ebx"); 16 | } 17 | 18 | void kmain() // multiboot_info_t info 19 | { 20 | ClearScreen(); 21 | 22 | BRANCH(InitSerial(), Println("SERIAL INIT OK");, Println("SERIAL INIT FAIL");); 23 | BRANCH(InitInterrupts(), Println("INTERRUPT INIT OK");, Println("INTERRUPT INIT FAIL");); 24 | 25 | SetPrintColor(PRINT_COLOR_LIGHT_GREEN, PRINT_COLOR_BLACK); 26 | Println("IDLE"); 27 | } 28 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | // "name": "Debug", 9 | // "type": "gdb", 10 | // "request": "launch", 11 | // "target": "./bin/executable", 12 | // "cwd": "${workspaceRoot}", 13 | // "valuesFormatting": "parseText" 14 | "type": "gdb", 15 | "request": "attach", 16 | "name": "Attach to gdbserver", 17 | // "executable": "D:\\mingw\\bin\\gdb.exe", 18 | "target": "localhost:1234", 19 | "remote": true, 20 | "cwd": "${workspaceRoot}", 21 | "gdbpath": "D:\\w64\\bin\\gdb.exe", 22 | "autorun": [""] 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /src/kernel/h/print.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | enum 6 | { 7 | PRINT_COLOR_BLACK = 0, 8 | PRINT_COLOR_BLUE = 1, 9 | PRINT_COLOR_GREEN = 2, 10 | PRINT_COLOR_CYAN = 3, 11 | PRINT_COLOR_RED = 4, 12 | PRINT_COLOR_MAGENTA = 5, 13 | PRINT_COLOR_BROWN = 6, 14 | PRINT_COLOR_LIGHT_GRAY = 7, 15 | PRINT_COLOR_DARK_GRAY = 8, 16 | PRINT_COLOR_LIGHT_BLUE = 9, 17 | PRINT_COLOR_LIGHT_GREEN = 10, 18 | PRINT_COLOR_LIGHT_CYAN = 11, 19 | PRINT_COLOR_LIGHT_RED = 12, 20 | PRINT_COLOR_PINK = 13, 21 | PRINT_COLOR_YELLOW = 14, 22 | PRINT_COLOR_WHITE = 15, 23 | }; 24 | 25 | void ClearScreen(); 26 | void PutChar(Char Character); 27 | void Print(Char *string); 28 | void Println(Char *string); 29 | void SetPrintColor(UByte foreground, UByte background); -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "OS", 5 | "includePath": [ 6 | "${workspaceFolder}/src/kernel/h/" 7 | ], 8 | "defines": [ 9 | "_DEBUG", 10 | "UNICODE", 11 | "_UNICODE" 12 | ], 13 | "compilerPath": "D:\\cygwin64\\bin\\gcc.exe", 14 | "cStandard": "gnu11", 15 | "cppStandard": "gnu++14", 16 | "intelliSenseMode": "windows-gcc-x64", 17 | "forcedInclude": [], 18 | "browse": { 19 | "path": [ 20 | "${workspaceFolder}/src/**" 21 | ], 22 | "limitSymbolsToIncludedHeaders": true, 23 | "databaseFilename": "" 24 | } 25 | } 26 | ], 27 | "version": 4 28 | } -------------------------------------------------------------------------------- /src/kernel/string.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | 3 | Char *IntToString(Int value, Char *str, Byte base) 4 | { 5 | char *rc; 6 | char *ptr; 7 | char *low; 8 | // Check for supported base. 9 | if (base < 2 || base > 36) 10 | { 11 | *str = '\0'; 12 | return str; 13 | } 14 | rc = ptr = str; 15 | // Set '-' for negative decimals. 16 | if (value < 0 && base == 10) 17 | { 18 | *ptr++ = '-'; 19 | } 20 | // Remember where the numbers start. 21 | low = ptr; 22 | // The actual conversion. 23 | do 24 | { 25 | // Modulo is negative for negative value. This trick makes abs() unnecessary. 26 | *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + value % base]; 27 | value /= base; 28 | } while (value); 29 | // Terminating the string. 30 | *ptr-- = '\0'; 31 | // Invert the numbers. 32 | while (low < ptr) 33 | { 34 | char tmp = *low; 35 | *low++ = *ptr; 36 | *ptr-- = tmp; 37 | } 38 | return rc; 39 | } -------------------------------------------------------------------------------- /src/kernel/h/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define BYTE_MAX 0x7F 8 | #define BYTE_MIN -0x80 9 | #define UBYTE_MAX 0xFF 10 | 11 | typedef int8_t Byte; 12 | typedef uint8_t UByte; 13 | 14 | #define SHORT_MAX 0x7FFF 15 | #define SHORT_MIN -0x8000 16 | #define USHORT_MAX 0xFFFF 17 | 18 | typedef int16_t Short; 19 | typedef uint16_t UShort; 20 | 21 | #define INT_MAX 0x7FFFFFFF 22 | #define INT_MIN -0x80000000 23 | #define UINT_MAX 0xFFFFFFFF 24 | 25 | typedef int32_t Int; 26 | typedef uint32_t UInt; 27 | 28 | #define LONG_MAX 0x7FFFFFFFFFFFFFFF 29 | #define LONG_MIN -0x8000000000000000 30 | #define ULONG_MAX 0xFFFFFFFFFFFFFFFF 31 | 32 | typedef int64_t Long; 33 | typedef uint64_t ULong; 34 | 35 | #ifdef SIZE_MAX 36 | #undef SIZE_MAX 37 | #endif 38 | #define SIZE_MAX 0xffffffff 39 | 40 | typedef UInt Size; 41 | 42 | #define TRUE 1 43 | #define FALSE 0 44 | #define True 1 45 | #define False 0 46 | typedef bool Bool; 47 | 48 | #define CHAR_MAX 0x7F 49 | #define CHAR_MIN -0x80 50 | typedef char Char; -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | x86_asm_src := $(shell find src -name *.asm) 2 | x86_asm_obj := $(patsubst src/%.asm, build/obj/%.o, $(x86_asm_src)) 3 | 4 | x86_64_c_src := $(shell find src -name *.c) 5 | x86_64_c_obj := $(patsubst src/%.c, build/obj/%.o, $(x86_64_c_src)) 6 | 7 | #TODO: Update whenever 8 | x86_64_obj := $(x86_64_c_obj) $(x86_asm_obj) 9 | 10 | $(x86_64_c_obj): build/obj/%.o : src/%.c 11 | @mkdir -p $(dir $@) && \ 12 | x86_64-elf-gcc -mno-red-zone -std=gnu99 -Werror=implicit-function-declaration -Wall -Wextra -c -I src/kernel/h -ffreestanding $(patsubst build/obj/%.o, src/%.c, $@) -o $@ 13 | 14 | $(x86_asm_obj): build/obj/%.o : src/%.asm 15 | @mkdir -p $(dir $@) && \ 16 | fasm $(patsubst build/obj/%.o, src/%.asm, $@) $@ 1> /dev/null 17 | 18 | .PHONY: build 19 | build: $(x86_64_obj) $(x86_asm_obj) 20 | @x86_64-elf-ld -nostdlib -n -o bin/kernel.bin -T linker.ld $(x86_64_obj) && \ 21 | cp bin/kernel.bin build/grub/boot/kernel.bin && \ 22 | grub-mkrescue /usr/lib/grub/i386-pc -o bin/kernel.iso build/grub > /dev/null 2>&1 && \ 23 | rm -r build/obj/* && \ 24 | rm build/grub/boot/kernel.bin 25 | -------------------------------------------------------------------------------- /src/kernel/io.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "lock.h" 3 | #include "string.h" 4 | #include "io.h" 5 | #include "print.h" 6 | 7 | UByte InByte(UShort port) 8 | { 9 | UByte result; 10 | asm volatile("inb %1, %0" 11 | : "=a"(result) 12 | : "Nd"(port)); 13 | return result; 14 | } 15 | 16 | void OutByte(UShort port, UByte data) 17 | { 18 | asm volatile("outb %0, %1" ::"a"(data), "Nd"(port)); 19 | } 20 | 21 | // ---------------- SERIAL ---------------- // 22 | 23 | #define COM1 0x3f8 24 | 25 | Bool InitSerial() 26 | { 27 | OutByte(COM1 + 1, 0x00); // Disable all interrupts 28 | OutByte(COM1 + 3, 0x80); // Enable DLAB (set baud rate divisor) 29 | OutByte(COM1 + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud 30 | OutByte(COM1 + 1, 0x00); // (hi byte) 31 | OutByte(COM1 + 3, 0x03); // 8 bits, no parity, one stop bit 32 | OutByte(COM1 + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold 33 | OutByte(COM1 + 4, 0x0B); // IRQs enabled, RTS/DSR set 34 | OutByte(COM1 + 4, 0x1E); // Set in loopback mode, test the serial chip 35 | OutByte(COM1 + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) 36 | 37 | // Check if serial is faulty (i.e: not same byte as sent) 38 | UByte recv = InByte(COM1 + 0); 39 | if (recv != 0xAE) 40 | { 41 | Char buf[4]; 42 | Println(IntToString((Int)recv, buf, 16)); 43 | return False; 44 | } 45 | 46 | // If serial is not faulty set it in normal operation mode 47 | // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) 48 | OutByte(COM1 + 4, 0x0F); 49 | return True; 50 | } 51 | 52 | static Byte _IsTransmitEmpty() 53 | { 54 | return InByte(COM1 + 5) & 0x20; 55 | } 56 | 57 | void SerialChar(char ch) 58 | { 59 | WAIT_UNTIL(_IsTransmitEmpty() != 0); 60 | OutByte(COM1, ch); 61 | } 62 | 63 | void SerialPrint(Char *str) 64 | { 65 | WAIT_UNTIL(_IsTransmitEmpty() != 0); 66 | for (Size i = 0; 1; i++) 67 | { 68 | char character = (Char)str[i]; 69 | 70 | if (character == '\0') 71 | { 72 | return; 73 | } 74 | 75 | SerialChar(character); 76 | } 77 | } 78 | void SerialPrintln(Char *str) 79 | { 80 | WAIT_UNTIL(_IsTransmitEmpty() != 0); 81 | for (Size i = 0; 1; i++) 82 | { 83 | Char character = (Char)str[i]; 84 | 85 | if (character == '\0') 86 | { 87 | SerialChar('\n'); 88 | return; 89 | } 90 | 91 | SerialChar(character); 92 | } 93 | } -------------------------------------------------------------------------------- /src/kernel/print.c: -------------------------------------------------------------------------------- 1 | #include "print.h" 2 | #include "io.h" 3 | 4 | static const size_t NUM_COLS = 80; 5 | static const size_t NUM_ROWS = 25; 6 | 7 | struct TermChar 8 | { 9 | UByte character; 10 | UByte color; 11 | }; 12 | 13 | struct TermChar *buffer = (struct TermChar *)0xb8000; 14 | size_t col = 0; 15 | size_t row = 0; 16 | UByte color = PRINT_COLOR_WHITE | PRINT_COLOR_BLACK << 4; 17 | 18 | void ClearRow(size_t row) 19 | { 20 | struct TermChar empty = (struct TermChar){ 21 | character : ' ', 22 | color : color, 23 | }; 24 | 25 | for (size_t col = 0; col < NUM_COLS; col++) 26 | { 27 | buffer[col + NUM_COLS * row] = empty; 28 | } 29 | } 30 | 31 | void ClearScreen() 32 | { 33 | for (size_t i = 0; i < NUM_ROWS; i++) 34 | { 35 | ClearRow(i); 36 | } 37 | } 38 | 39 | void PutNewline() 40 | { 41 | SerialChar('\n'); 42 | 43 | col = 0; 44 | 45 | if (row < NUM_ROWS - 1) 46 | { 47 | row++; 48 | return; 49 | } 50 | 51 | for (size_t row = 1; row < NUM_ROWS; row++) 52 | { 53 | for (size_t col = 0; col < NUM_COLS; col++) 54 | { 55 | struct TermChar character = buffer[col + NUM_COLS * row]; 56 | buffer[col + NUM_COLS * (row - 1)] = character; 57 | } 58 | } 59 | 60 | ClearRow(NUM_COLS - 1); 61 | } 62 | 63 | void PutChar(Char character) 64 | { 65 | if (character == '\n') 66 | { 67 | PutNewline(); 68 | return; 69 | } 70 | 71 | if (col > NUM_COLS) 72 | { 73 | PutNewline(); 74 | } 75 | 76 | buffer[col + NUM_COLS * row] = (struct TermChar){ 77 | character : (UByte)character, 78 | color : color, 79 | }; 80 | SerialChar(character); 81 | 82 | col++; 83 | } 84 | 85 | void Print(Char *str) 86 | { 87 | for (size_t i = 0; 1; i++) 88 | { 89 | Char character = (UByte)str[i]; 90 | 91 | if (character == '\0') 92 | { 93 | return; 94 | } 95 | 96 | PutChar(character); 97 | } 98 | } 99 | void Println(Char *str) 100 | { 101 | for (size_t i = 0; 1; i++) 102 | { 103 | Char character = (UByte)str[i]; 104 | 105 | if (character == '\0') 106 | { 107 | PutChar('\n'); 108 | return; 109 | } 110 | 111 | PutChar(character); 112 | } 113 | } 114 | 115 | void SetPrintColor(UByte foreground, UByte background) 116 | { 117 | color = foreground + (background << 4); 118 | } -------------------------------------------------------------------------------- /src/boot/entry.asm: -------------------------------------------------------------------------------- 1 | format elf64 2 | use32 3 | 4 | section ".entry" 5 | extrn long_mode_start 6 | 7 | public start 8 | start: 9 | mov esp, stack_top 10 | 11 | call check_multiboot 12 | call check_cpuid 13 | call check_long_mode 14 | 15 | call setup_page_tables 16 | call enable_paging 17 | 18 | lgdt [gdt64.desc] ;[gdt64.pointer] 19 | 20 | push ebx 21 | jmp gdt64.code:long_mode_start 22 | hlt 23 | 24 | check_multiboot: 25 | cmp eax, 0x36d76289 26 | jne .no_multiboot 27 | ret 28 | .no_multiboot: 29 | mov al, "M" 30 | jmp error 31 | 32 | check_cpuid: 33 | pushfd 34 | pop eax 35 | mov ecx, eax 36 | xor eax, 1 shl 21 37 | push eax 38 | popfd 39 | pushfd 40 | pop eax 41 | push ecx 42 | popfd 43 | cmp eax, ecx 44 | je .no_cpuid 45 | ret 46 | .no_cpuid: 47 | mov al, "C" 48 | jmp error 49 | 50 | check_long_mode: 51 | mov eax, 0x80000000 52 | cpuid 53 | cmp eax, 0x80000001 54 | jb .no_long_mode 55 | 56 | mov eax, 0x80000001 57 | cpuid 58 | test edx, 1 shl 29 59 | jz .no_long_mode 60 | 61 | ret 62 | .no_long_mode: 63 | mov al, "L" 64 | jmp error 65 | 66 | setup_page_tables: 67 | mov eax, page_table_l3 68 | or eax, 11b ; present, writable 69 | mov [page_table_l4], eax 70 | 71 | mov eax, page_table_l2 72 | or eax, 11b ; present, writable 73 | mov [page_table_l3], eax 74 | 75 | mov ecx, 0 ; counter 76 | .loop: 77 | mov eax, 0x200000 ; 2MiB 78 | mul ecx 79 | or eax, 10000011b ; present, writable, huge page 80 | mov [page_table_l2 + ecx * 8], eax 81 | 82 | inc ecx ; increment counter 83 | cmp ecx, 512 ; checks if the whole table is mapped 84 | jne .loop ; if not, continue 85 | 86 | ret 87 | 88 | enable_paging: 89 | ; pass page table location to cpu 90 | mov eax, page_table_l4 91 | mov cr3, eax 92 | 93 | ; enable PAE 94 | mov eax, cr4 95 | or eax, 1 shl 5 96 | mov cr4, eax 97 | 98 | ; enable long mode 99 | mov ecx, 0xC0000080 100 | rdmsr 101 | or eax, 1 shl 8 102 | wrmsr 103 | 104 | ; enable paging 105 | mov eax, cr0 106 | or eax, 1 shl 31 107 | mov cr0, eax 108 | 109 | ret 110 | 111 | error: 112 | ; print "ERR: X" where X is the error code 113 | mov dword [0xb8000], 0x4f524f45 114 | mov dword [0xb8004], 0x4f3a4f52 115 | mov dword [0xb8008], 0x4f204f20 116 | mov byte [0xb800a], al 117 | hlt 118 | 119 | section ".bss" align 4096 120 | align 4096 121 | page_table_l4: 122 | rb 4096 123 | page_table_l3: 124 | rb 4096 125 | page_table_l2: 126 | rb 4096 127 | align 16 128 | stack_bottom: 129 | rb 4096 * 4 130 | stack_top: 131 | 132 | ; section ".rodata" 133 | ; gdt64: 134 | ; dq 0 ; zero entry 135 | ; CODE_SEGMENT = $ - gdt64 136 | ; dq (1 shl 43) or (1 shl 44) or (1 shl 47) or (1 shl 53) ; code segment 137 | ; .pointer: 138 | ; dw $ - gdt64 - 1 ; length 139 | ; dq gdt64 ; address 140 | 141 | gdt64: 142 | dq 0x0000000000000000 ; Null Descriptor 143 | .code = $ - gdt64 ; Code segment 144 | dq 0x0020980000000000 145 | .data = $ - gdt64 ; Data segment 146 | dq 0x0000920000000000 147 | .desc: 148 | dw $ - gdt64 - 1 ; 16-bit Size (Limit) 149 | dq gdt64 ; 64-bit Base Address -------------------------------------------------------------------------------- /src/kernel/int.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "io.h" 3 | #include "print.h" 4 | #include "string.h" 5 | 6 | typedef struct __attribute__((packed)) 7 | { 8 | UShort offset_1; 9 | UShort selector; 10 | UShort type; 11 | UShort offset_2; 12 | UInt offset_3; 13 | UInt zero; // bruh it's an int 14 | } IDT_ENTRY; 15 | 16 | typedef struct __attribute__((packed)) 17 | { 18 | UShort limit; 19 | ULong base; 20 | } IDTPointer; 21 | 22 | extern void isr0(); 23 | extern void isr1(); 24 | extern void isr2(); 25 | extern void isr3(); 26 | extern void isr4(); 27 | extern void isr5(); 28 | extern void isr6(); 29 | extern void isr7(); 30 | extern void isr8(); 31 | extern void isr9(); 32 | extern void isr10(); 33 | extern void isr11(); 34 | extern void isr12(); 35 | extern void isr13(); 36 | extern void isr14(); 37 | extern void isr15(); // 'Unknown interrupt' 38 | extern void isr16(); 39 | extern void isr17(); 40 | extern void isr18(); 41 | extern void isr19(); 42 | extern void isr20(); 43 | extern void isr21(); 44 | extern void isr22(); 45 | extern void isr23(); 46 | extern void isr24(); 47 | extern void isr25(); 48 | extern void isr26(); 49 | extern void isr27(); 50 | extern void isr28(); 51 | extern void isr29(); 52 | extern void isr30(); 53 | extern void isr31(); 54 | 55 | extern void irq0(); 56 | extern void irq1(); 57 | extern void irq2(); 58 | extern void irq3(); 59 | extern void irq4(); 60 | extern void irq5(); 61 | extern void irq6(); 62 | extern void irq7(); 63 | extern void irq8(); 64 | extern void irq9(); 65 | extern void irq10(); 66 | extern void irq11(); 67 | extern void irq12(); 68 | extern void irq13(); 69 | extern void irq14(); 70 | extern void irq15(); 71 | 72 | extern void irq60(); 73 | extern void irq69(); 74 | 75 | extern void LoadIDT(); 76 | 77 | typedef struct 78 | { 79 | ULong gs, fs, es, ds; 80 | ULong rax, rbx, rcx, rdx, rbp, rsi, rdi, /*rsp*/ r8, r9, r10, r11, r12, r13, r14, r15; 81 | ULong intNum, errCode; 82 | ULong rip, cs, eflags, rsp, ss; 83 | } Registers; 84 | 85 | Char *interruptMessages[] = { 86 | "Division By Zero", //0 87 | "Debug", //1 88 | "Non Maskable Interrupt", //2 89 | "Breakpoint", //3 90 | "Into Detected Overflow", //4 91 | "Out of Bounds", //5 92 | "Invalid Opcode", //6 93 | "No Coprocessor", //7 94 | 95 | "Double Fault", //8 96 | "Coprocessor Segment Overrun", //9 97 | "Bad TSS", //10 98 | "Segment Not Present", //11 99 | "Stack Fault", //12 100 | "General Protection Fault", //13 101 | "Page Fault", 102 | "Unknown Interrupt", 103 | 104 | "Coprocessor Fault", 105 | "Alignment Check", 106 | "Machine Check", 107 | "Reserved", 108 | "Reserved", 109 | "Reserved", 110 | "Reserved", 111 | "Reserved", 112 | 113 | "Reserved", 114 | "Reserved", 115 | "Reserved", 116 | "Reserved", 117 | "Reserved", 118 | "Reserved", 119 | "Reserved", 120 | "Reserved", 121 | }; 122 | 123 | #define STRNUMBAS(str, num, buf) \ 124 | Print(str); \ 125 | Print(" - "); \ 126 | Print(IntToString(num, buf, 10)); \ 127 | Print(" 0x"); \ 128 | Print(IntToString(num, buf, 16)); \ 129 | Print(" b"); \ 130 | Println(IntToString(num, buf, 2)); 131 | 132 | #define STRNUMBASNO2(str, num, buf) \ 133 | Print(str); \ 134 | Print(" - "); \ 135 | Print(IntToString(num, buf, 10)); \ 136 | Print(" 0x"); \ 137 | Println(IntToString(num, buf, 16)); 138 | 139 | void FaultHandler(Registers *regs) // 0-31 CPU isr 140 | { 141 | SetPrintColor(COLOR_WHITE, COLOR_LIGHT_RED); 142 | ClearScreen(); 143 | ResetCursor(); 144 | Char buf[256]; 145 | Print(" ------ FATAL EXCEPTION: '"); 146 | Print(interruptMessages[regs->intNum]); 147 | Println("' ------"); 148 | STRNUMBAS("Int: ", regs->intNum, buf); 149 | STRNUMBAS("Err: ", regs->errCode, buf); 150 | STRNUMBAS("RIP: ", regs->rip, buf); 151 | STRNUMBAS("CS: ", regs->cs, buf); 152 | STRNUMBAS("Eflg: ", regs->eflags, buf); 153 | STRNUMBAS("RSP: ", regs->rsp, buf); 154 | STRNUMBAS("SS: ", regs->ss, buf); 155 | 156 | STRNUMBASNO2("R15: ", regs->r15, buf); 157 | STRNUMBASNO2("R14: ", regs->r14, buf); 158 | STRNUMBASNO2("R13: ", regs->r13, buf); 159 | STRNUMBASNO2("R12: ", regs->r12, buf); 160 | STRNUMBASNO2("R11: ", regs->r11, buf); 161 | STRNUMBASNO2("R10: ", regs->r10, buf); 162 | STRNUMBASNO2("R09: ", regs->r9, buf); 163 | STRNUMBASNO2("R08: ", regs->r8, buf); 164 | STRNUMBASNO2("RSI: ", regs->rsi, buf); 165 | STRNUMBASNO2("RDI: ", regs->rdi, buf); 166 | STRNUMBASNO2("RBP: ", regs->rbp, buf); 167 | STRNUMBASNO2("RDX: ", regs->rdx, buf); 168 | STRNUMBASNO2("RCX: ", regs->rcx, buf); 169 | STRNUMBASNO2("RBP: ", regs->rbp, buf); 170 | STRNUMBASNO2("RAX: ", regs->rax, buf); 171 | 172 | PutChar('\n'); 173 | 174 | while (1) 175 | asm volatile("hlt"); 176 | } 177 | 178 | void IrqHandler(Registers *regs) // 0-31 CPU isr // Registers numbah 179 | { 180 | OutByte(0x20, 0x20); 181 | if (regs->errCode >= 8) 182 | { 183 | OutByte(0xA0, 0x20); 184 | } 185 | } 186 | 187 | IDTPointer IDTPtr; 188 | IDT_ENTRY IDT[256]; 189 | void *IrqHandlers[256] = {0}; 190 | 191 | #define INTERRUPT_GATE 0x8e00 192 | #define TRAP_GATE 0x8f00 193 | 194 | #define Interrupt(n, h) _EnableInterrupt(n, (ULong)h, INTERRUPT_GATE) 195 | #define Interrupt_sf(n, h, t) _EnableInterrupt(n, (ULong)h, t) 196 | void _EnableInterrupt(UByte number, ULong handler, UShort type) 197 | { 198 | IDT[number].offset_1 = (UShort)handler; 199 | IDT[number].selector = 0x08; 200 | IDT[number].type = type; 201 | IDT[number].offset_2 = (UShort)(handler >> 16); 202 | IDT[number].offset_3 = (UInt)(handler >> 32); 203 | IDT[number].zero = 0; 204 | 205 | // UShort offset_1; 206 | // UShort selector; 207 | // UShort type; 208 | // UShort offset_2; 209 | // UInt offset_3; 210 | // UInt zero; 211 | } 212 | 213 | Bool InitInterrupts() 214 | { 215 | IDTPtr.limit = sizeof(IDT_ENTRY) * 256 - 1; 216 | IDTPtr.base = (ULong)&IDT; 217 | 218 | LoadIDT(); 219 | 220 | for (UInt i = 0; i < 255; i++) 221 | { 222 | Interrupt(i, isr15); 223 | } 224 | 225 | Interrupt(0, isr0); 226 | Interrupt(1, isr1); 227 | Interrupt(2, isr2); 228 | Interrupt(3, isr3); 229 | Interrupt(4, isr4); 230 | Interrupt(5, isr5); 231 | Interrupt(6, isr6); 232 | Interrupt(7, isr7); 233 | Interrupt(8, isr8); 234 | Interrupt(9, isr9); 235 | Interrupt(10, isr10); 236 | Interrupt(11, isr11); 237 | Interrupt(12, isr12); 238 | Interrupt(13, isr13); 239 | Interrupt(14, isr14); 240 | Interrupt(15, isr15); 241 | Interrupt(16, isr16); 242 | Interrupt(17, isr17); 243 | Interrupt(18, isr18); 244 | Interrupt(19, isr19); 245 | Interrupt(20, isr20); 246 | Interrupt(21, isr21); 247 | Interrupt(22, isr22); 248 | Interrupt(23, isr23); 249 | Interrupt(24, isr24); 250 | Interrupt(25, isr25); 251 | Interrupt(26, isr26); 252 | Interrupt(27, isr27); 253 | Interrupt(28, isr28); 254 | Interrupt(29, isr29); 255 | Interrupt(30, isr30); 256 | Interrupt(31, isr31); 257 | 258 | // Remap PIC 259 | OutByte(0x20, 0x11); 260 | OutByte(0xA0, 0x11); 261 | OutByte(0x21, 0x20); 262 | OutByte(0xA1, 40); 263 | OutByte(0x21, 0x04); 264 | OutByte(0xA1, 0x02); 265 | OutByte(0x21, 0x01); 266 | OutByte(0xA1, 0x01); 267 | OutByte(0x21, 0x0); 268 | OutByte(0xA1, 0x0); 269 | 270 | Interrupt(32, irq0); 271 | Interrupt(33, irq1); 272 | Interrupt(34, irq2); 273 | Interrupt(35, irq3); 274 | Interrupt(36, irq4); 275 | Interrupt(37, irq5); 276 | Interrupt(38, irq6); 277 | Interrupt(39, irq7); 278 | Interrupt(40, irq8); 279 | Interrupt(41, irq9); 280 | Interrupt(42, irq10); 281 | Interrupt(43, irq11); 282 | Interrupt(44, irq12); 283 | Interrupt(45, irq13); 284 | Interrupt(46, irq14); 285 | Interrupt(47, irq15); 286 | 287 | Interrupt(60, irq60); 288 | Interrupt(69, irq69); 289 | 290 | asm volatile("sti"); 291 | 292 | return True; 293 | } -------------------------------------------------------------------------------- /src/kernel/inthdl.asm: -------------------------------------------------------------------------------- 1 | format elf64 2 | use64 3 | section ".text" 4 | 5 | public LoadIDT 6 | 7 | extrn IDTPtr 8 | 9 | extrn Print 10 | 11 | public isr_handler_stub 12 | public irq_common_stub 13 | 14 | extrn FaultHandler 15 | extrn IrqHandler 16 | 17 | macro PUSHAQ { 18 | push rax 19 | push rbx 20 | push rcx 21 | push rdx 22 | push rbp 23 | push rsi 24 | push rdi 25 | ; push rsp 26 | push r8 27 | push r9 28 | push r10 29 | push r11 30 | push r12 31 | push r13 32 | push r14 33 | push r15 34 | } 35 | 36 | macro POPAQ { 37 | pop r15 38 | pop r14 39 | pop r13 40 | pop r12 41 | pop r11 42 | pop r10 43 | pop r9 44 | pop r8 45 | ; pop rsp 46 | pop rdi 47 | pop rsi 48 | pop rbp 49 | pop rdx 50 | pop rcx 51 | pop rbx 52 | pop rax 53 | } 54 | 55 | isr_handler_stub: 56 | PUSHAQ 57 | mov rdi, rsp ; pass the argument to C funciton 58 | call FaultHandler 59 | POPAQ 60 | add rsp, 16 ; i'm not sure about the size 61 | iretq 62 | ret 63 | 64 | irq_common_stub: 65 | PUSHAQ 66 | mov rdi, rsp ; pass the argument to C funciton 67 | call IrqHandler 68 | POPAQ 69 | add rsp, 16 ;; ^ 70 | iretq 71 | ret 72 | 73 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 74 | 75 | LoadIDT: 76 | lidt [IDTPtr] 77 | ret 78 | 79 | public isr0 80 | public isr1 81 | public isr2 82 | public isr3 83 | public isr4 84 | public isr5 85 | public isr6 86 | public isr7 87 | public isr8 88 | public isr9 89 | public isr10 90 | public isr11 91 | public isr12 92 | public isr13 93 | public isr14 94 | public isr15 95 | public isr16 96 | public isr17 97 | public isr18 98 | public isr19 99 | public isr20 100 | public isr21 101 | public isr22 102 | public isr23 103 | public isr24 104 | public isr25 105 | public isr26 106 | public isr27 107 | public isr28 108 | public isr29 109 | public isr30 110 | public isr31 111 | 112 | public irq0 113 | public irq1 114 | public irq2 115 | public irq3 116 | public irq4 117 | public irq5 118 | public irq6 119 | public irq7 120 | public irq8 121 | public irq9 122 | public irq10 123 | public irq11 124 | public irq12 125 | public irq13 126 | public irq14 127 | public irq15 128 | 129 | public irq69 130 | public irq60 131 | 132 | isr0: 133 | cli 134 | push 0 135 | push 0 136 | jmp isr_handler_stub 137 | 138 | ; 1: Debug Exception 139 | isr1: 140 | cli 141 | push 0 142 | push 1 143 | jmp isr_handler_stub 144 | 145 | ; 2: Non Maskable Interrupt Exception 146 | isr2: 147 | cli 148 | push 0 149 | push 2 150 | jmp isr_handler_stub 151 | 152 | ; 3: Int 3 Exception 153 | isr3: 154 | cli 155 | push 0 156 | push 3 157 | jmp isr_handler_stub 158 | 159 | ; 4: INTO Exception 160 | isr4: 161 | cli 162 | push 2 163 | push 4 164 | jmp isr_handler_stub 165 | 166 | ; 5: Out of Bounds Exception 167 | isr5: 168 | cli 169 | push 0 170 | push 5 171 | jmp isr_handler_stub 172 | 173 | ; 6: Invalid Opcode Exception 174 | isr6: 175 | cli 176 | push 0 177 | push 6 178 | jmp isr_handler_stub 179 | 180 | ; 7: Coprocessor Not Available Exception 181 | isr7: 182 | cli 183 | push 0 184 | push 7 185 | jmp isr_handler_stub 186 | 187 | ; 8: Double Fault Exception (With Error Code!) 188 | isr8: 189 | cli 190 | push 8 191 | jmp isr_handler_stub 192 | 193 | ; 9: Coprocessor Segment Overrun Exception 194 | isr9: 195 | cli 196 | push 0 197 | push 9 198 | jmp isr_handler_stub 199 | 200 | ; 10: Bad TSS Exception (With Error Code!) 201 | isr10: 202 | cli 203 | push 10 204 | jmp isr_handler_stub 205 | 206 | ; 11: Segment Not Present Exception (With Error Code!) 207 | isr11: 208 | cli 209 | push 11 210 | jmp isr_handler_stub 211 | 212 | ; 12: Stack Fault Exception (With Error Code!) 213 | isr12: 214 | cli 215 | push 12 216 | jmp isr_handler_stub 217 | 218 | ; 13: General Protection Fault Exception (With Error Code!) 219 | isr13: 220 | cli 221 | push 13 222 | jmp isr_handler_stub 223 | 224 | ; 14: Page Fault Exception (With Error Code!) 225 | isr14: 226 | cli 227 | push 14 228 | jmp isr_handler_stub 229 | 230 | ; 15: Unknown Interrupt 231 | ; Do nothing 232 | isr15: 233 | cli 234 | iretq 235 | 236 | ; 16: Floating Point Exception 237 | isr16: 238 | cli 239 | push 0 240 | push 16 241 | jmp isr_handler_stub 242 | 243 | ; 17: Alignment Check Exception 244 | isr17: 245 | cli 246 | push 0 247 | push 17 248 | jmp isr_handler_stub 249 | 250 | ; 18: Machine Check Exception 251 | isr18: 252 | cli 253 | push 0 254 | push 18 255 | jmp isr_handler_stub 256 | 257 | ; 19: Reserved 258 | isr19: 259 | cli 260 | push 0 261 | push 19 262 | jmp isr_handler_stub 263 | 264 | ; 20: Reserved 265 | isr20: 266 | cli 267 | push 0 268 | push 20 269 | jmp isr_handler_stub 270 | 271 | ; 21: Reserved 272 | isr21: 273 | cli 274 | push 0 275 | push 21 276 | jmp isr_handler_stub 277 | 278 | ; 22: Reserved 279 | isr22: 280 | cli 281 | push 0 282 | push 22 283 | jmp isr_handler_stub 284 | 285 | ; 23: Reserved 286 | isr23: 287 | cli 288 | push 0 289 | push 23 290 | jmp isr_handler_stub 291 | 292 | ; 24: Reserved 293 | isr24: 294 | cli 295 | push 0 296 | push 24 297 | jmp isr_handler_stub 298 | 299 | ; 25: Reserved 300 | isr25: 301 | cli 302 | push 0 303 | push 25 304 | jmp isr_handler_stub 305 | 306 | ; 26: Reserved 307 | isr26: 308 | cli 309 | push 0 310 | push 26 311 | jmp isr_handler_stub 312 | 313 | ; 27: Reserved 314 | isr27: 315 | cli 316 | push 0 317 | push 27 318 | jmp isr_handler_stub 319 | 320 | ; 28: Reserved 321 | isr28: 322 | cli 323 | push 0 324 | push 28 325 | jmp isr_handler_stub 326 | 327 | ; 29: Reserved 328 | isr29: 329 | cli 330 | push 0 331 | push 29 332 | jmp isr_handler_stub 333 | 334 | ; 30: Reserved 335 | isr30: 336 | cli 337 | push 0 338 | push 30 339 | jmp isr_handler_stub 340 | 341 | ; 31: Reserved 342 | isr31: 343 | cli 344 | push 0 345 | push 31 346 | jmp isr_handler_stub 347 | 348 | 349 | ; IRQ handlers 350 | irq0: 351 | cli 352 | push 0 353 | push 32 354 | jmp irq_common_stub 355 | 356 | irq1: 357 | cli 358 | push 1 359 | push 33 360 | jmp irq_common_stub 361 | 362 | irq2: 363 | cli 364 | push 2 365 | push 34 366 | jmp irq_common_stub 367 | 368 | irq3: 369 | cli 370 | push 3 371 | push 35 372 | jmp irq_common_stub 373 | 374 | irq4: 375 | cli 376 | push 4 377 | push 36 378 | jmp irq_common_stub 379 | 380 | irq5: 381 | cli 382 | push 5 383 | push 37 384 | jmp irq_common_stub 385 | 386 | irq6: 387 | cli 388 | push 6 389 | push 38 390 | jmp irq_common_stub 391 | 392 | irq7: 393 | cli 394 | push 7 395 | push 39 396 | jmp irq_common_stub 397 | 398 | irq8: 399 | cli 400 | push 8 401 | push 40 402 | jmp irq_common_stub 403 | 404 | irq9: 405 | cli 406 | push 9 407 | push 41 408 | jmp irq_common_stub 409 | 410 | irq10: 411 | cli 412 | push 10 413 | push 42 414 | jmp irq_common_stub 415 | 416 | irq11: 417 | cli 418 | push 11 419 | push 43 420 | jmp irq_common_stub 421 | 422 | irq12: 423 | cli 424 | push 12 425 | push 44 426 | jmp irq_common_stub 427 | 428 | irq13: 429 | cli 430 | push 13 431 | push 45 432 | jmp irq_common_stub 433 | 434 | irq14: 435 | cli 436 | push 14 437 | push 46 438 | jmp irq_common_stub 439 | 440 | irq15: 441 | cli 442 | push 15 443 | push 47 444 | jmp irq_common_stub 445 | 446 | 447 | 448 | irq60: 449 | cli 450 | push 60 451 | push 60 452 | jmp irq_common_stub 453 | 454 | irq69: 455 | cli 456 | push 69 457 | push 69 458 | jmp irq_common_stub 459 | --------------------------------------------------------------------------------