├── .gitignore ├── .ycm_extra_conf.py ├── CMakeLists.txt ├── LICENSE ├── README.md ├── dummy_disk.bin ├── gdbinit ├── linker.conf ├── screenshot.png ├── src ├── c_entry.c ├── console.c ├── cpu │ ├── cache.S │ ├── gdt.S │ └── init.S ├── drivers │ ├── ata │ │ ├── ata.c │ │ └── ata_util.c │ ├── device.c │ ├── kbdctl │ │ └── 8042.c │ ├── pci │ │ ├── pci.c │ │ └── pci_util.c │ ├── pic_8259 │ │ └── pic.c │ ├── pit │ │ ├── pit.c │ │ └── pit_handler.S │ └── serial │ │ └── serial.c ├── include │ ├── asm │ │ ├── cpu │ │ │ └── longjmp.h │ │ └── interrupts │ │ │ └── ivt_entry.h │ ├── console │ │ └── console.h │ ├── cpu │ │ └── common.h │ ├── drivers │ │ ├── ata │ │ │ └── ata.h │ │ ├── device.h │ │ ├── kbdctl │ │ │ └── 8042.h │ │ ├── pci │ │ │ ├── pci.h │ │ │ └── pci_util.h │ │ ├── pic_8259 │ │ │ └── pic.h │ │ ├── pit │ │ │ └── pit.h │ │ └── serial │ │ │ └── serial.h │ ├── interrupts │ │ ├── asm_helpers.h │ │ ├── common.h │ │ ├── interrupts.h │ │ └── ivt.h │ ├── itoa.h │ ├── mm │ │ ├── bitmap.h │ │ └── slab.h │ ├── panic.h │ ├── post.h │ ├── stdlib.h │ ├── string.h │ ├── superio │ │ └── superio.h │ └── sys │ │ └── io.h ├── interrupts │ ├── interrupts.S │ ├── interrupts.c │ └── ivt.c ├── mainboards │ └── qemu │ │ ├── CMakeLists.txt │ │ ├── memory_init.S │ │ └── superio │ │ └── superio.c ├── mm │ ├── malloc.c │ └── slab.c ├── panic.c ├── post.c ├── reset.S └── stdlib │ ├── CMakeLists.txt │ ├── itoa.c │ └── string.c ├── test_bootloader.asm └── test_disk /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /.ycm_extra_conf.py: -------------------------------------------------------------------------------- 1 | def Settings( **kwargs ): 2 | return { 3 | 'flags':['-x', 'c', '-Wall', '-Wextra', '-I./src/include', '-Wno-unused-function', 4 | '-std=gnu2x'], 5 | } 6 | 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(tinybios LANGUAGES C ASM VERSION 0.5) 3 | 4 | find_program(dd NAMES dd HINTS /usr/bin /usr/local/bin /bin) 5 | find_program(clang NAMES clang clang16 HINTS /usr/bin /usr/local/bin /bin) 6 | 7 | set(target_mainboard "qemu" CACHE STRING "Currently we only support qemu for now") 8 | set(target_cpu "x86-64" CACHE STRING "We only support x86-64 cpus for now") 9 | set(CC clang) 10 | 11 | # These source files are used by _all_ versions of x86 bios of ours 12 | # 13 | add_executable(tinybios 14 | src/cpu/gdt.S 15 | src/cpu/init.S 16 | 17 | src/interrupts/interrupts.S 18 | src/interrupts/interrupts.c 19 | src/interrupts/ivt.c 20 | 21 | src/drivers/device.c 22 | src/drivers/serial/serial.c 23 | src/drivers/kbdctl/8042.c 24 | src/drivers/pic_8259/pic.c 25 | src/drivers/pit/pit.c 26 | src/drivers/pit/pit_handler.S 27 | src/drivers/pci/pci.c 28 | src/drivers/pci/pci_util.c 29 | 30 | src/drivers/ata/ata.c 31 | src/drivers/ata/ata_util.c 32 | 33 | src/mm/slab.c 34 | src/mm/malloc.c 35 | 36 | src/c_entry.c 37 | src/panic.c 38 | src/post.c 39 | src/console.c 40 | src/reset.S 41 | ) 42 | 43 | # Helper stuff 44 | add_subdirectory(src/stdlib) 45 | 46 | # These sources are mainboard dependant 47 | # 48 | add_subdirectory(src/mainboards/${target_mainboard}) 49 | 50 | add_custom_command( 51 | TARGET tinybios 52 | POST_BUILD 53 | COMMENT "Building BIOS Image from ELF file" 54 | COMMAND objcopy -j .rom_text -j .data -j .text -j .reset -O binary tinybios.elf tinybios.bin 55 | ) 56 | 57 | add_custom_target(run 58 | COMMAND qemu-system-x86_64 -bios tinybios.bin -device piix3-ide,id=ide -drive id=disk,file=${CMAKE_CURRENT_SOURCE_DIR}/test_disk,format=raw,if=none -device ide-hd,drive=disk,bus=ide.0 59 | DEPENDS tinybios.bin 60 | USES_TERMINAL 61 | ) 62 | 63 | add_custom_target(log-int 64 | COMMAND qemu-system-x86_64 -bios tinybios.bin -d int 65 | DEPENDS tinybios.bin 66 | USES_TERMINAL 67 | ) 68 | 69 | add_custom_target(log-asm 70 | COMMAND qemu-system-x86_64 -bios tinybios.bin -d in_asm 71 | DEPENDS tinybios.bin 72 | USES_TERMINAL 73 | ) 74 | 75 | 76 | add_custom_target(debug 77 | COMMAND qemu-system-x86_64 -S --daemonize -s -bios tinybios.bin 78 | COMMAND gdb -ix ${CMAKE_CURRENT_SOURCE_DIR}/gdbinit 79 | DEPENDS tinybios.bin 80 | USES_TERMINAL 81 | ) 82 | 83 | target_include_directories(tinybios SYSTEM PUBLIC 84 | "src/include" 85 | ) 86 | 87 | target_compile_options(tinybios PUBLIC 88 | -Wall -Wextra 89 | -nostdlib 90 | -ibuiltininc 91 | -ffreestanding 92 | -masm=intel 93 | -fno-pic 94 | -std=gnu2x 95 | -D TARGET_MAINBOARD=${target_mainboard} 96 | -march=${target_cpu} 97 | ) 98 | 99 | target_link_options(tinybios PUBLIC 100 | -nostdlib -no-pie -Wl,--script=${CMAKE_CURRENT_SOURCE_DIR}/linker.conf 101 | ) 102 | 103 | set_target_properties(tinybios PROPERTIES OUTPUT_NAME tinybios.elf) 104 | 105 | 106 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, k4m1 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TinyBIOS 2 | A minimalist open source BIOS project for fun 3 | 4 | ![Alt text](/screenshot.png?raw=true) 5 | 6 | # NOTE 7 | The above screenshot is form BEFORE current rewrite idea occured, if you 8 | want to try out that version, use legacy branch. 9 | 10 | Testing: 11 | 12 | $: git clone 13 | 14 | $: mkdir build 15 | 16 | $: cd build 17 | 18 | $: cmake .. 19 | 20 | $: make 21 | 22 | $ make run 23 | 24 | -------------------------------------------------------------------------------- /dummy_disk.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwk4m1/TinyBIOS/8bfd09f646db0313c2b00c8ee4e19215162d000a/dummy_disk.bin -------------------------------------------------------------------------------- /gdbinit: -------------------------------------------------------------------------------- 1 | target remote :1234 2 | set architecture i386 3 | add-symbol-file tinybios.elf 4 | tui enable 5 | tui new-layout main regs 1 asm 1 status 0 cmd 1 6 | tui layout main 7 | set disassembly-flavor intel 8 | 9 | -------------------------------------------------------------------------------- /linker.conf: -------------------------------------------------------------------------------- 1 | # Output file is bios-tmp.elf, that is then changed by objcopy into the 2 | # format we want 3 | # 4 | # 5 | ENTRY(reset) 6 | 7 | # Code section definitions, see memory map for reference with different 8 | # regions and stuff 9 | # 10 | # 00000000 - 000003FF -- IVT 11 | # 00000400 - 000004FF -- BDA 12 | # 00000500 - 00007BFF -- FREE 13 | # 00007C00 - 00007DFF -- Boot sector 14 | # 00007E00 - 0007FFFF -- FREE 15 | # 00080000 - 0009FFFF -- EBDA 16 | # 000A0000 -> -- MMIO 17 | # 18 | MEMORY { 19 | mem_ram (rw) : org = 0, len = 0x90000 20 | mem_rom_low (rx) : org = 0xE0000, len = 0x00E00 21 | mem_rom_high (rx) : org = 0xF0000, len = 0x10000 22 | } 23 | 24 | mem_pagetable_entry = 0; 25 | bda_int_handler_cpu_state = 0x04AC; 26 | bda_int_handler_cpu_state_end = bda_int_handler_cpu_state + 16; 27 | bda_int_handler_gdtr = bda_int_handler_cpu_state_end + 1; 28 | 29 | SECTIONS { 30 | 31 | .text 0x70000 : AT (0xE0000) { 32 | *(.bss) 33 | *(.data) 34 | *(.interp) 35 | *(.dynsym) 36 | *(.gnu.hash) 37 | *(.rodata) 38 | *(.plt) 39 | *(.dynstr) 40 | *(.rodata*) 41 | *(.dyn*) 42 | *(.rel*) 43 | *(.text) 44 | } 45 | 46 | . = 0xF0000; 47 | .rom_text 0xF0000 : AT (0xF0000) { 48 | *(.rom_text) 49 | *(.rom_int_handler) 50 | . = 0x0FFF0; 51 | *(.reset) 52 | . = ALIGN(16); 53 | } > mem_rom_high =0xFF 54 | } 55 | 56 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwk4m1/TinyBIOS/8bfd09f646db0313c2b00c8ee4e19215162d000a/screenshot.png -------------------------------------------------------------------------------- /src/c_entry.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | 39 | #include 40 | 41 | #include 42 | #include 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | #include 52 | 53 | #include 54 | #include 55 | 56 | extern void interrupt_handler_init_runtime(void); 57 | 58 | heap_start *heap = (heap_start *)0x8000; 59 | 60 | device *uart_dev = 0; 61 | console_device default_console_device = {0}; 62 | device *keyboard_controller_device = 0; 63 | device *programmable_interrupt_controller = 0; 64 | device *programmable_interrupt_timer = 0; 65 | device **pci_device_array = 0; 66 | ata_ide **ata_ide_array = 0; 67 | 68 | /* The C entrypoint for early initialisation for {hard,soft}ware 69 | * 70 | * This function should never return. 71 | */ 72 | __attribute__ ((noreturn)) void c_main(void) { 73 | superio_init(); 74 | 75 | heap_start *start = (heap_start *)heap; 76 | if (start->start == (memory_header *)((uint64_t)start + sizeof(heap_start))) { 77 | hang(); 78 | } 79 | 80 | heap_init((uint64_t)heap, (0x70000 - 0x8000)); 81 | 82 | post_and_init(); 83 | 84 | blogf("Early chipset initialisation done, halt\n"); 85 | for (;;) { 86 | hang(); 87 | } 88 | } 89 | 90 | -------------------------------------------------------------------------------- /src/console.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | 39 | #include 40 | #include 41 | 42 | #include 43 | 44 | #include 45 | #include 46 | 47 | extern console_device default_console_device; 48 | 49 | /* Write log message over default output device 50 | * 51 | * @param console_device *dev -- device to use for output 52 | * @param char *msg -- message to print 53 | * 54 | */ 55 | void blog(char *msg) { 56 | if (default_console_device.enabled == false) { 57 | return; 58 | } 59 | serial_uart_device *udev = default_console_device.dev->device_data; 60 | default_console_device.tx_func(udev->base_port, msg, strlen(msg)); 61 | } 62 | 63 | /* Print a sinlge byte over default output device 64 | * 65 | * @param char c -- character to write 66 | */ 67 | static inline void bputchar(char c) { 68 | if (default_console_device.enabled == false) { 69 | return; 70 | } 71 | 72 | serial_uart_device *udev = default_console_device.dev->device_data; 73 | default_console_device.tx_func(udev->base_port, &c, 1); 74 | } 75 | 76 | /* Print single integer over default output device 77 | * 78 | * @param int leading_zeros -- Amount of leading 0's to print 79 | * @param int d -- integer to print 80 | * @param int base -- base number 81 | */ 82 | static inline void bputint(int leading_zeros, int d, int base) { 83 | char tmp[33]; 84 | memset(tmp, 0, 33); 85 | 86 | if (base == 16) { 87 | itoah(d, tmp); 88 | } else { 89 | itoa(d, tmp); 90 | } 91 | 92 | char *start = tmp; 93 | for (int i = 0; i < 32; i++) { 94 | if (*start != 0x30) 95 | break; 96 | start++; 97 | } 98 | if (strlen(start) == 0) { 99 | start--; 100 | } 101 | if (leading_zeros) { 102 | if (strlen(start) < (unsigned long)leading_zeros) { 103 | int count = leading_zeros - strlen(start); 104 | start = (char *)((uint64_t)start - count); 105 | } 106 | } 107 | blog(start); 108 | } 109 | 110 | /* log messages, now with format string from panic() and co! 111 | * 112 | * @param const char *restrict format 113 | * @param va_list ap :3 114 | * @return int bytes written 115 | */ 116 | int vfblogf(const char *restrict format, va_list ap) { 117 | if (default_console_device.enabled == false) { 118 | return 0; 119 | } 120 | 121 | int written = 0; 122 | int d; 123 | char c; 124 | char *s; 125 | bool escaped = false; 126 | 127 | do { 128 | if (escaped) { 129 | bputchar(*format); 130 | escaped = false; 131 | } else { 132 | if (*format == '\\') { 133 | escaped = true; 134 | } else if (*format == '%') { 135 | format++; 136 | int lc = 0; 137 | if (*format == '0') { 138 | format++; 139 | while (*format <= 0x39) { 140 | if (*(format + 1) <= 0x39) { 141 | lc += 10 * ((int)(*format & 0x0F)); 142 | } else { 143 | lc += (int)(*format & 0x0F); 144 | } 145 | format++; 146 | } 147 | } 148 | switch (*format) { 149 | case 's': 150 | s = va_arg(ap, char *); 151 | blog(s); 152 | written += strlen(s); 153 | break; 154 | case 'x': 155 | d = va_arg(ap, int); 156 | bputint(lc, d, 16); 157 | written += sizeof(int); 158 | written += lc; 159 | break; 160 | case 'd': 161 | d = va_arg(ap, int); 162 | bputint(lc, d, 10); 163 | written += sizeof(int); 164 | written += lc; 165 | break; 166 | case 'c': 167 | c = (char) va_arg(ap, int); 168 | bputchar(c); 169 | written++; 170 | break; 171 | default: 172 | format--; 173 | bputchar(*format); 174 | written++; 175 | } 176 | } else { 177 | bputchar(*format); 178 | written++; 179 | } 180 | } 181 | } while (*format++); 182 | return written; 183 | } 184 | 185 | /* log messages, now with format string! 186 | * 187 | * @param const char *restrict format 188 | * @param ... :3 189 | * @return int bytes written 190 | */ 191 | int blogf(const char *restrict format, ...) { 192 | va_list ap; 193 | int written = 0; 194 | 195 | va_start(ap, format); 196 | written = vfblogf(format, ap); 197 | va_end(ap); 198 | return written; 199 | } 200 | 201 | -------------------------------------------------------------------------------- /src/cpu/cache.S: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2019, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | */ 33 | 34 | #ifndef __CPU_CACHE_AS_RAM__ 35 | #define __CPU_CACHE_AS_RAM__ 36 | 37 | #define CACHE_AS_RAM_BASE 0x08000000 38 | #define CACHE_AS_RAM_SIZE 0x2000 39 | #define MEMORY_TYPE_WRITEBACK 0x06 40 | #define MTRR_PAIR_VALID 0x800 41 | 42 | // base 43 | #define MTRR_PHYB_LO (CACHE_AS_RAM_BASE | \ 44 | MEMORY_TYPE_WRITEBACK) 45 | #define MTRR_PHYB_REG0 0x200 46 | #define MTRR_PHYB_HI 0x00 47 | 48 | // mask 49 | #define MTRR_PHYM_LO ((~((CACHE_AS_RAM_SIZE) - 1)) | \ 50 | MTRR_PAIR_VALID) 51 | 52 | #define MTRR_PHYM_HI 0xF 53 | #define MTRR_PHYM_REG0 0x201 54 | 55 | #define MTRR_DEFTYPE_REG0 0x2FF 56 | #define MTRR_ENABLE 0x800 57 | 58 | // Setup MTRR Base 59 | mov eax, MTRR_PHYB_LO 60 | mov ecx, MTRR_PHYB_REG0 61 | xor edx, edx 62 | wrmsr 63 | 64 | // Setup MTRR Mask 65 | mov eax, MTRR_PHYM_LO 66 | mov ecx, MTRR_PHYM_REG0 67 | mov edx, MTRR_PHYM_HI 68 | wrmsr 69 | 70 | // Enable MTRR subsystem 71 | mov ecx, MTRR_DEFTYPE_REG0 72 | rdmsr 73 | or eax, MTRR_ENABLE 74 | wrmsr 75 | 76 | // Enter normal cache mode 77 | mov eax, cr0 78 | and eax, 0x9fffffff 79 | invd 80 | mov cr0, eax 81 | 82 | // establish tags for cache as ram region 83 | mov esi, CACHE_AS_RAM_BASE 84 | mov ecx, (CACHE_AS_RAM_SIZE / 2) 85 | rep lodsw 86 | 87 | // Enter no-fill cache mode 88 | mov eax, cr0 89 | or eax, 0x40000000 90 | mov cr0, eax 91 | 92 | // Clear cache region 93 | mov edi, CACHE_AS_RAM_BASE 94 | mov ecx, (CACHE_AS_RAM_SIZE / 2) 95 | rep stosw 96 | 97 | // Set stack pointer to point to cache :3 98 | xor ax, ax 99 | mov ss, ax 100 | mov esp, (CACHE_AS_RAM_BASE + CACHE_AS_RAM_SIZE) 101 | 102 | #else 103 | #error "Cpu cache as ram init included twice!" 104 | #endif // __CPU_CACHE_AS_RAM__ 105 | -------------------------------------------------------------------------------- /src/cpu/gdt.S: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | .section .rom_text 34 | .global gdt 35 | .code32 36 | gdt: 37 | .short .gdt_end - .gdt_start 38 | .int .gdt_start 39 | .gdt_start: 40 | .int 0 41 | .int 0 42 | ._gdt_code32: 43 | .short 0xFFFF 44 | .short 0x0000 45 | .byte 0x00 46 | .byte 0x9A 47 | .byte 0xCF 48 | .byte 0x00 49 | ._gdt_code64: 50 | .short 0xFFFF 51 | .short 0x0000 52 | .byte 0x00 53 | .byte 0x9A 54 | .byte 0xAF 55 | .byte 0x00 56 | ._gdt_data64: 57 | .short 0xFFFF 58 | .short 0x0000 59 | .byte 0x00 60 | .byte 0x92 61 | .byte 0xAF 62 | .byte 0x00 63 | .gdt_end: 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/cpu/init.S: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | .section .rom_text 34 | .global init_cpu 35 | .global switch_to_unreal 36 | .global switch_to_protected 37 | 38 | #include 39 | 40 | /* Helper function for switching to protected mode, this is used during early boot 41 | * as well as by interrupt handlers. 42 | * 43 | * Clobbers cs, eax, gdtr 44 | */ 45 | switch_to_protected: 46 | .code16 47 | mov eax, offset gdt 48 | lgdt [eax] 49 | xor eax, eax 50 | lidt [eax] 51 | mov eax, cr0 52 | or al, 1 53 | mov cr0, eax 54 | LONGJMP(0x0008, next) 55 | next: 56 | .code32 57 | pop eax 58 | or eax, 0xf0000 59 | jmp eax 60 | .code16 61 | 62 | /* Helper function for switching to unreal mode, this is used during early boot 63 | * as well as by interrupt handlers. 64 | * 65 | * Clobbers ds, gdtr 66 | */ 67 | switch_to_unreal: 68 | .code32 69 | push eax 70 | push bx 71 | mov eax, offset gdt 72 | lgdt [eax] 73 | mov eax, cr0 74 | mov bx, 0x08 75 | mov ds, bx 76 | and al, 0xFE 77 | mov cr0, eax 78 | xor ax, ax 79 | mov ds, ax 80 | pop bx 81 | pop eax 82 | ret 83 | .code16 84 | 85 | setup_paging: 86 | .code32 87 | pusha 88 | mov ecx, ((2048 + 512) * 2) 89 | xor eax, eax 90 | xor edi, edi 91 | rep stosd 92 | 93 | mov eax, 3 94 | xor edi, edi 95 | xor ebx, ebx 96 | mov ecx, 1024 97 | .loop_pt: 98 | stosd 99 | xchg ebx, eax 100 | stosd 101 | xchg ebx, eax 102 | add eax, 0x1000 103 | loop .loop_pt 104 | 105 | // pd 106 | mov ecx, 1024 107 | mov eax, 3 108 | push edi 109 | .loop_pd: 110 | stosd 111 | xchg ebx, eax 112 | stosd 113 | xchg ebx, eax 114 | loop .loop_pd 115 | 116 | // pml4 117 | pop eax 118 | and eax, 0xFFFFF000 119 | or eax, 3 120 | stosd 121 | xchg ebx, eax 122 | stosd 123 | 124 | mov eax, edi 125 | sub eax, 8 126 | mov cr3, eax 127 | 128 | mov ecx, 0xC0000080 129 | rdmsr 130 | or eax, (1 << 8) 131 | wrmsr 132 | 133 | mov eax, cr4 134 | or eax, (1 << 5) 135 | mov cr4, eax 136 | 137 | mov eax, cr0 138 | or eax, ((1 << 31) | (1 << 0)) 139 | mov cr0, eax 140 | 141 | mov ax, 0x18 142 | mov ds, ax 143 | mov es, ax 144 | mov gs, ax 145 | mov fs, ax 146 | mov ss, ax 147 | LONGJMP32(0x0010, .next_64) 148 | 149 | .next_64: 150 | .code64 151 | jmp continue_entry_prep 152 | .code16 153 | 154 | // We'll land here from reset.S, things we'll want to do next are 155 | // to move to some more appropriate runmode which doesn't do segments and 156 | // 20-bit addressing, etc. 157 | // 158 | init_cpu: 159 | .code16 160 | 161 | // Start by moving to 32 bit protected mode 162 | push eax 163 | call switch_to_protected 164 | .code32 165 | pop eax 166 | mov esp, 0x00007c00 167 | // call switch_to_unreal 168 | call setup_paging 169 | 170 | .code64 171 | continue_entry_prep: 172 | // Relocate our C code into ram 173 | // 174 | mov rsi, 0xE0000 175 | mov rdi, 0x70000 176 | mov rcx, 0x0FFFF 177 | rep movsb 178 | mov rsp, 0x00007c00 179 | mov rbp, rsp 180 | 181 | xor rdi, rdi 182 | xor rsi, rsi 183 | call c_main 184 | 185 | // Never reached but better be overly careful 186 | .hang: 187 | mov rax, 0xdeadc0de 188 | cli 189 | hlt 190 | jmp .hang 191 | 192 | -------------------------------------------------------------------------------- /src/drivers/ata/ata.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2025, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include 41 | 42 | #include 43 | #include 44 | #include 45 | 46 | #include 47 | 48 | /* Try and read ID of sata/atapi device 49 | * 50 | * @param ata_bus *bus -- Bus we're currently working with 51 | * @return uint16_t id 52 | */ 53 | static uint16_t ata_try_read_id(ata_bus *bus) { 54 | uint16_t ret; 55 | ata_register reg = ata_read_lba_mi(bus); 56 | ret = (reg.raw) << 8; 57 | reg = ata_read_lba_hi(bus); 58 | ret |= reg.raw; 59 | return ret; 60 | } 61 | 62 | /* Clear out ata sector count and lba 63 | * values 64 | * 65 | * @param ata_bus *bus -- Bus we're currently working with 66 | */ 67 | static void ata_clear_sc_lba(ata_bus *bus) { 68 | ata_register reg = {0}; 69 | ata_write_sector_count(bus, reg); 70 | ata_write_lba_lo(bus, reg); 71 | ata_write_lba_mi(bus, reg); 72 | ata_write_lba_hi(bus, reg); 73 | } 74 | 75 | /* Try and identify ATA drive we're working with 76 | * 77 | * @param ata_bus *bus -- Bus we're currently working with 78 | * @return enum ata_drive_id id on success or -1 on timeout 79 | */ 80 | static enum ata_drive_id ata_identify_drive(ata_bus *bus) { 81 | ata_clear_sc_lba(bus); 82 | ata_register reg = {0}; 83 | reg.raw = ata_cmd_identify; 84 | ata_write_command(bus, reg); 85 | uint16_t id = ata_try_read_id(bus); 86 | 87 | if ((id == ata_drive_id_sata) || (id == ata_drive_id_atapi)) { 88 | return id; 89 | } 90 | reg.raw = 0; 91 | reg.status.drive_busy = false; 92 | if (ata_waitfor_status(bus, reg.raw, false, 50) == false) { 93 | return ata_drive_id_not_ata; 94 | } 95 | id = ata_try_read_id(bus); 96 | if (id) { 97 | return ata_drive_id_not_ata; 98 | } 99 | reg.raw = 0; 100 | reg.status.drive_ready = true; 101 | if (ata_waitfor_status(bus, reg.raw, true, 50) == false) { 102 | return ata_drive_id_not_ata; 103 | } 104 | return ata_drive_id_ata; 105 | } 106 | 107 | static char *ata_drive_model_to_string(uint8_t *model) { 108 | char *ret = calloc(41, sizeof(char)); 109 | if (ret) { 110 | for (int i = 0; i < 40; i += 2) { 111 | ret[i] = model[i + 1]; 112 | ret[i + 1] = model[i]; 113 | } 114 | } 115 | return ret; 116 | } 117 | 118 | /* Initialize currently selected active drive 119 | * 120 | * @param ata_bus *bus -- Bus we're currently working with 121 | * @return pointer to allocated ata_drive structure on success 122 | * or NULL on error. 123 | */ 124 | static ata_drive *init_ata_drive(ata_bus *bus) { 125 | ata_drive *ret = calloc(1, sizeof(ata_drive)); 126 | if (!ret) { 127 | return NULL; 128 | } 129 | ret->drive_id = ata_identify_drive(bus); 130 | if ((ret->drive_id == ata_drive_id_not_ata) || (ret->drive_id == 0)) { 131 | free(ret); 132 | return NULL; 133 | } 134 | 135 | ret->hdr_addr = calloc(1, sizeof(ata_drive_header)); 136 | if (!ret->hdr_addr) { 137 | blogf("No enough space for reading ata drive info!\n"); 138 | } else { 139 | uint16_t *dst = (uint16_t *)ret->hdr_addr; 140 | for (int i = 0; i < 256; i++) { 141 | dst[i] = ata_read_data(bus); 142 | } 143 | blogf("Found drive: %s\n", ata_drive_model_to_string(ret->hdr_addr->model)); 144 | } 145 | return ret; 146 | } 147 | 148 | static ata_bus *init_ata_bus(uint16_t base, uint16_t dcr) { 149 | if (ata_no_drives_in_bus(base)) { 150 | return NULL; 151 | } 152 | ata_bus *ret = calloc(1, sizeof(ata_bus)); 153 | if (!ret) { 154 | return ret; 155 | } 156 | ret->base_addr = base; 157 | ret->dcr_addr = dcr; 158 | 159 | if (ata_select_drive(ret, drive1)) { 160 | ret->drive_array[1] = init_ata_drive(ret); 161 | } 162 | if (ata_select_drive(ret, drive0)) { 163 | ret->drive_array[0] = init_ata_drive(ret); 164 | } 165 | return ret; 166 | } 167 | 168 | static void ata_init_all_buses(ata_ide *ide) { 169 | if (ide->iface.pci_primary_native_enabled) { 170 | /* TODO */ 171 | } else { 172 | for (int i = 0; i < 4; i++) { 173 | uint16_t base = ata_ide_compability_base_addrs[i]; 174 | uint16_t dcr = ata_comp_base_to_dcr(base); 175 | ata_bus *bus = init_ata_bus(base, dcr); 176 | if (bus) { 177 | ide->bus_array[ide->bus_count] = bus; 178 | ide->bus_count++; 179 | } 180 | } 181 | } 182 | } 183 | 184 | ata_ide *ata_init_ide(device *ide) { 185 | ata_ide *ret = calloc(1, sizeof(ata_ide)); 186 | if (!ret) { 187 | return ret; 188 | } 189 | pci_device_data *dev = ide->device_data; 190 | ret->ide_device_data = ide; 191 | ret->iface.raw = dev->generic_header_fields.programming_interface_byte; 192 | ata_init_all_buses(ret); 193 | return ret; 194 | } 195 | 196 | /* Go through our array of identified PCI devices, 197 | * and try to bring up every IDE controller we've found. 198 | * 199 | * @param device **pci_device_array -- Pointer to device array 200 | * @param ata_ide **ata_ide_array -- Where to store our ATA IDE structures 201 | * @param uint8_t pci_dev_cnt -- Amount of devices we've found 202 | * @return uint8_t amount of IDE controllers we've intialized 203 | */ 204 | uint8_t init_ata_controllers(device **pci_device_array, ata_ide **ata_ide_array, uint8_t pci_dev_cnt) { 205 | uint8_t ide_count = 0; 206 | for (uint8_t offset = 0; offset < pci_dev_cnt; offset++) { 207 | device *dev = pci_device_array[offset]; 208 | if (pcidev_is_ata_ide(dev) == false) { 209 | continue; 210 | } 211 | ata_ide *ide = ata_init_ide(dev); 212 | if (ide) { 213 | ata_ide_array[ide_count] = ide; 214 | ide_count++; 215 | ata_ide_array = realloc(ata_ide_array, ((ide_count + 1) * sizeof(ata_ide **))); 216 | if (!ata_ide_array) { 217 | panic("Out of memory, too many IDEs found!"); 218 | } 219 | } 220 | } 221 | return ide_count; 222 | } 223 | 224 | -------------------------------------------------------------------------------- /src/drivers/ata/ata_util.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2025, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include 41 | 42 | #include 43 | #include 44 | #include 45 | 46 | #include 47 | 48 | /* Check if given PCI device is ata-ide for us 49 | * 50 | * @param device *dev -- Device we're working with 51 | * @return bool true if this is ata-ide 52 | */ 53 | bool pcidev_is_ata_ide(device *dev) { 54 | pci_device_data *pci = (pci_device_data *)dev->device_data; 55 | if (pci->generic_header_fields.class_code == pci_class_mass_storage_controller) { 56 | switch (pci->generic_header_fields.subclass) { 57 | case (pci_mass_storage_controller_ide_controller): 58 | case (pci_mass_storage_controller_ata_controller): 59 | case (pci_mass_storage_controller_sata_controller): 60 | dev->type = device_access_pio; 61 | return true; 62 | } 63 | } 64 | return false; 65 | } 66 | 67 | /* Reset both drives on this bus 68 | * 69 | * @param ata_bus *bus -- Bus we're working with 70 | */ 71 | void ata_bus_reset(ata_bus *bus) { 72 | ata_register reg = {0}; 73 | reg.ctrl.disable_interrupts = true; 74 | reg.ctrl.sw_reset = true; 75 | ata_write_register(bus->dcr_addr, reg); 76 | reg.ctrl.sw_reset = false; 77 | ata_write_register(bus->dcr_addr, reg); 78 | } 79 | 80 | /* Wait for given ata settings to change at status register 81 | * 82 | * @param ata_bus *bus -- Ata bus we're working with 83 | * @param uint8_t mask -- Flags to wait for 84 | * @param bool set -- Are we waiting for these flags to be set or clear 85 | * @param uint8_t wait -- Timeout 86 | * @return bool true if changes happen, false if timeout or error is encountered 87 | */ 88 | bool ata_waitfor_status(ata_bus *bus, uint8_t mask, bool set, uint8_t wait) { 89 | ata_register reg = {0}; 90 | for ( ; wait > 0; wait--) { 91 | reg = ata_read_status(bus); 92 | if (reg.status.error) { 93 | break; 94 | } 95 | reg.raw &= mask; 96 | if (set && (reg.raw == mask)) { 97 | return true; 98 | } 99 | if (!set && (reg.raw == 0)) { 100 | return true; 101 | } 102 | } 103 | return false; 104 | } 105 | 106 | /* Select given disk from ata bus 107 | * 108 | * @param ata_bus *bus -- Ata bus we're working with 109 | * @param ata_drive_selection drive -- Drive to select 110 | * @return bool true if drive got selected, false on error 111 | */ 112 | bool ata_select_drive(ata_bus *bus, ata_drive_selection drive) { 113 | if (bus->active_drive != drive) { 114 | /* Set always_set bits on */ 115 | ata_register reg = {0xA0}; 116 | reg.drive_head.drive_selection = drive; 117 | ata_write_drive_head(bus, reg); 118 | reg = ata_read_drive_address(bus); 119 | bool select_err = (drive == drive0) ? reg.drive_addr.drive_0_selected : reg.drive_addr.drive_1_selected; 120 | if (!select_err) { 121 | bus->active_drive = drive; 122 | } 123 | } 124 | return (bus->active_drive == drive); 125 | } 126 | 127 | 128 | -------------------------------------------------------------------------------- /src/drivers/device.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | 40 | /* Helper for allocating new device structures 41 | * 42 | * @param size_t size of device_data structure to allocate 43 | * @return pointer to our calloc'ed dev struct 44 | */ 45 | device *new_device(size_t dev_size) { 46 | device *ret = calloc(1, sizeof(device)); 47 | if (!ret) { 48 | panic_oom("creating new device"); 49 | } 50 | ret->device_data = calloc(1, dev_size); 51 | if (!ret->device_data) { 52 | panic_oom("Allocating space for device data"); 53 | } 54 | return ret; 55 | } 56 | 57 | /* Print why initilaisation failed, if possible. 58 | * 59 | */ 60 | static inline char *status_to_str(enum DEVICE_STATUS status) { 61 | switch (status) { 62 | case (status_present): 63 | return "device is present"; 64 | case (status_not_present): 65 | return "device is not present"; 66 | case (status_unknown): 67 | return "unable to determine device state"; 68 | case (status_faulty): 69 | return "device is misbehaving"; 70 | case (status_initialised): 71 | return "device initialisation completed"; 72 | default: 73 | return "unknown device status"; 74 | } 75 | } 76 | 77 | /* Wrapper for calling various device initialisation routines 78 | * 79 | * @param pio_device_init init -- pio device initialisation function to use 80 | * @param pio_device *dev -- pio device structure for this device 81 | * @param bool critical -- Do we fail to boot if we lack this device 82 | * @param char *name -- device name 83 | */ 84 | void initialize_device(device_init_function init, device *dev, char *name, bool critical) { 85 | blogf("Initializing %s... ", name); 86 | 87 | dev->status = init(dev); 88 | dev->device_name = name; 89 | if (dev->status != status_initialised) { 90 | blogf("Failed, reason: %s\n", status_to_str(dev->status)); 91 | if (critical) { 92 | panic("Unable to initialize a critical component"); 93 | } 94 | } else { 95 | blog("ok\n"); 96 | } 97 | } 98 | 99 | -------------------------------------------------------------------------------- /src/drivers/kbdctl/8042.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | 40 | #include 41 | 42 | #define WAITFOR_READ KBDCTL_STAT_OUT_BUF 43 | #define WAITFOR_WRITE 0 44 | 45 | ps2_8042_status keyboard_controller_status; 46 | 47 | // Wait until keyboard controller input buffer status is empty 48 | // 49 | // @return int waitfor -- are we waiting for empty or non-empty status (read or write) 50 | // @return bool true once controller is ready to recv or false on timeout 51 | // 52 | static bool kbdctl_ctrl_rdy(int waitfor) { 53 | unsigned char mask; 54 | if (waitfor != 0) { 55 | mask = waitfor; 56 | } else { 57 | mask = KBDCTL_STAT_IN_BUF; 58 | } 59 | for (int i = 0; i < 5000; i++) { 60 | if ((inb(KBDCTL_STAT) & mask) == waitfor) { 61 | return true; 62 | } 63 | } 64 | return false; 65 | } 66 | 67 | // Send command to kbd controller, read response 68 | // 69 | // @param unsigned char v -- Command byte to send 70 | // @return bool true on success or false on error 71 | // 72 | bool kbdctl_send_cmd(unsigned char v) { 73 | if (kbdctl_ctrl_rdy(WAITFOR_WRITE) == false) { 74 | return false; 75 | } 76 | outb(v, KBDCTL_CMD); 77 | return true; 78 | } 79 | 80 | // Read a byte from data port once data becomes readable 81 | // 82 | // @return unsigned char data we received or -1 on error 83 | // 84 | unsigned char kbdctl_recv_data_poll(void) { 85 | if (kbdctl_ctrl_rdy(WAITFOR_READ) == false) { 86 | blog("kbdctl_recv_data_poll timeout\n"); 87 | return 0xff; 88 | } 89 | return inb(KBDCTL_DATA); 90 | } 91 | 92 | // Write 1 byte of data to kbdctl port once it becomes writable 93 | // 94 | // @param unsigned char v -- byte to write 95 | // @return true on success or false on timeout 96 | // 97 | bool kbdctl_send_data_poll(unsigned char v) { 98 | if (kbdctl_ctrl_rdy(WAITFOR_WRITE) == false) { 99 | return false; 100 | } 101 | outb(v, KBDCTL_DATA); 102 | return true; 103 | } 104 | 105 | // Disable both ps/2 ports 106 | // 107 | // @return int 0 on success or which port failed to disable on error (1, 2, or both) 108 | // 109 | int kbdctl_disable_ports(void) { 110 | int ret = 0; 111 | if (kbdctl_send_cmd(KBDCTL_CMD_DISABLE_P1) == false) { 112 | ret |= 1; 113 | } 114 | if (kbdctl_send_cmd(KBDCTL_CMD_DISABLE_P2) == false) { 115 | ret |= 2; 116 | } 117 | return ret; 118 | } 119 | 120 | // Try and read configuration byte from device 121 | // 122 | // @return unsigned char configuration on success or FF on error 123 | // 124 | static unsigned char kbdctl_read_config(void) { 125 | if (kbdctl_send_cmd(KBDCTL_CMD_READ_CONFIG) == false) { 126 | return 0xff; 127 | } 128 | return kbdctl_recv_data_poll(); 129 | } 130 | 131 | // Try and write configuration to device 132 | // 133 | // @param unsigned char configuration 134 | // @return bool true on success or false on error 135 | // 136 | static bool kbdctl_write_config(unsigned char config_byte) { 137 | if (kbdctl_send_cmd(KBDCTL_CMD_WRITE_CONFIG) == false) { 138 | return false; 139 | } 140 | if (kbdctl_send_data_poll(config_byte) == false) { 141 | return false; 142 | } 143 | unsigned char t = kbdctl_read_config(); 144 | if (t != config_byte) { 145 | return false; 146 | } 147 | return true; 148 | } 149 | 150 | // Reset a specific device 151 | // 152 | // @param int device_number -- 0 or 1 for 1st or 2nd device 153 | // @return bool true on success or false on error 154 | // 155 | bool kbdctl_reset_device(int which) { 156 | // If we're reseting secondary device, tell that to controller first 157 | if (which == 1) { 158 | if (kbdctl_send_cmd(KBDCTL_CMD_WRITENEXT_P2INBUF) == false) { 159 | return false; 160 | } 161 | } 162 | if (kbdctl_send_cmd(KBDCTL_CMD_RST_DEVICE) == false) { 163 | return false; 164 | } 165 | if (kbdctl_recv_data_poll() != KBDCTL_STAT_ACK) { 166 | return false; 167 | } 168 | return true; 169 | } 170 | 171 | /* Helper to enable a20 line with keyboard controller 172 | * 173 | * @return true on success or false on error 174 | */ 175 | bool enable_a20line(void) { 176 | if (kbdctl_send_cmd(KBDCTL_CMD_WRITENEXT_CTL_OUT) == false) { 177 | return false; 178 | } 179 | if (kbdctl_send_data_poll(KBDCTL_CMD_ENABLE_A20) == false) { 180 | return false; 181 | } 182 | return true; 183 | } 184 | 185 | 186 | // Set keyboard controller byte with default config mask with 187 | // interrupts and translation layer disabled 188 | // 189 | // @param device *dev -- a pointer to device structure to populate 190 | // @param char *name -- name of this device 191 | // @return bool true on success or false on error 192 | // 193 | enum DEVICE_STATUS kbdctl_set_default_init(device *dev __attribute__((unused))) { 194 | ps2_8042_status *status = &keyboard_controller_status; 195 | 196 | // Start by reading inital configuration 197 | // 198 | unsigned char initial_config = kbdctl_read_config(); 199 | if (initial_config == 0xff) { 200 | blog("Failed to get initial config\n"); 201 | return status_unknown; 202 | } 203 | unsigned char new_config = initial_config & KBDCTL_DEFAULT_CONFIG_MASK; 204 | if (kbdctl_write_config(new_config) == false) { 205 | // Writing new configuration failed 206 | return status_faulty; 207 | } 208 | if (kbdctl_do_self_test() == false) { 209 | // Device failed self-test after our new configuration, fallback to old 210 | if (kbdctl_write_config(initial_config) == false) { 211 | // Can't write old configuration back anymore... 212 | blog("8042 keyboard controller became unresponsive, hard reboot required.\n"); 213 | do {} while (1); 214 | } 215 | return status_faulty; 216 | } 217 | return status_initialised; 218 | if (initial_config & KBDCTL_CTL_PS2_CLKE) { 219 | status->dual_channel = true; 220 | } 221 | status->a20line_enabled = enable_a20line(); 222 | status->current_configuration = new_config; 223 | return status_initialised; 224 | } 225 | 226 | // Perform keyboard controller self test. 227 | // 228 | // @return true on success or false on error 229 | // 230 | bool kbdctl_do_self_test(void) { 231 | if (kbdctl_send_cmd(KBDCTL_CMD_TEST_CTL) == false) { 232 | return false; 233 | } 234 | unsigned char stat = kbdctl_recv_data_poll(); 235 | if (stat != KBDCTL_SELFTEST_SUCCESS) { 236 | return false; 237 | } 238 | return true; 239 | } 240 | 241 | // Test a single device 242 | // 243 | // @param unsigned char dev_cmd -- device specific test cmd (KBDCTL_CMD_TEST_P{1,2} 244 | // @return unsigned char status of device test on success or 0xff on error 245 | // 246 | unsigned char kbdctl_test_device(unsigned char dev_cmd) { 247 | if (kbdctl_send_cmd(dev_cmd) == false) { 248 | return 0xff; 249 | } 250 | return kbdctl_recv_data_poll(); 251 | } 252 | 253 | // Enable all ps/2 devices 254 | // 255 | // @return unsigned char devices initialised 256 | // 257 | unsigned char kbdctl_enable_devices(device *dev) { 258 | ps2_8042_status *stat = dev->device_data; 259 | if (kbdctl_send_cmd(KBDCTL_CMD_ENABLE_P1) == false) { 260 | return 0; 261 | } 262 | stat->devices_initialised++; 263 | if (stat->dual_channel) { 264 | if (kbdctl_send_cmd(KBDCTL_CMD_ENABLE_P2)) { 265 | return 2; 266 | } 267 | } 268 | return 1; 269 | } 270 | 271 | -------------------------------------------------------------------------------- /src/drivers/pci/pci.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2025, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | 40 | #include 41 | #include 42 | #include 43 | 44 | #include 45 | 46 | static void add_device_class(pci_device_data *dev, pci_config_address *addr) { 47 | uint32_t reg = pci_read_config(addr, 8); 48 | dev->generic_header_fields.class_code = pci_class(reg); 49 | dev->generic_header_fields.subclass = pci_subclass(reg); 50 | } 51 | 52 | /* Fetch device data for next device in our list 53 | * 54 | * @param pci_device_data *dev -- Pointer to pci_device_data structure 55 | * @param pci_config_address *addr -- Pointer to current pci_config_address to use 56 | * @return bool true if device data was added, false if no device is plugged in 57 | */ 58 | static inline void pci_add_device_data(pci_device_data *dev, pci_config_address *addr) { 59 | add_device_class(dev, addr); 60 | dev->bist_executed = pci_start_selftest(dev); 61 | } 62 | 63 | static void pci_read_header(pci_device_data *dev) { 64 | uint32_t *hdr = (uint32_t *)&dev->generic_header_fields; 65 | for (int reg = 0; reg < 0x03; reg++) { 66 | hdr[reg] = pci_read_config(&dev->address, (reg * 4)); 67 | } 68 | enum pci_header_type type = dev->generic_header_fields.header_type; 69 | int limit = (type == pci2cb_bridge_hdr) ? 0x11 : 0x0F; 70 | for (int reg = 0x4; reg < limit; reg++) { 71 | hdr[reg] = pci_read_config(&dev->address, (reg * 4)); 72 | } 73 | } 74 | 75 | /* populate device structures for all devices in a given PCI bus 76 | * 77 | * @param device *pci_device_array -- Pointer to our pci device list 78 | * @param uint8_t offset -- Offset to next device in the list 79 | * @param pci_config_address *addr -- Pointer to current pci_config_address to use 80 | * @return uint8_t amount of devices added 81 | */ 82 | static uint8_t pci_add_devices_from_bus(device **pci_device_array, uint8_t offset, pci_config_address *addr) { 83 | uint8_t count = 0; 84 | 85 | for (unsigned i = 0; i < 31; i++) { 86 | addr->device = i; 87 | uint32_t reg = pci_read_config(addr, 0); 88 | if (reg == 0xFFFFFFFF) { 89 | continue; 90 | } 91 | pci_device_array[offset] = calloc(1, sizeof(device)); 92 | pci_device_data *dev = calloc(1, sizeof(pci_device_data)); 93 | if (!dev || !pci_device_array[offset]) { 94 | panic("%s: pci_add_devices_from_bus: out of memory\n", __FILE__); 95 | } 96 | dev->address = *addr; 97 | pci_device_array[offset]->device_data = (void *)dev; 98 | pci_read_header(dev); 99 | 100 | dev->bist_executed = pci_start_selftest(dev); 101 | pci_device_array[offset]->status = status_present; 102 | if (pci_dev_is_bridge(addr)) { 103 | pci_device_array[offset]->type = device_bridge; 104 | } else { 105 | pci_device_array[offset]->type = device_access_mmio; 106 | } 107 | count++; 108 | offset++; 109 | } 110 | return count; 111 | } 112 | 113 | static enum pci_header_type get_hdr_type(pci_config_address *addr) { 114 | return pci_header_type(pci_read_config(addr, 0x0C)); 115 | } 116 | 117 | /* Fetch headers for all pci devices we have plugged in 118 | * 119 | * @param device *pci_device_array -- Pointer to pci device array 120 | * @return uint8_t amount of devices found or -1 on error 121 | */ 122 | uint8_t enumerate_pci_buses(device **pci_device_array) { 123 | bool multibus_system = false; 124 | uint8_t dev_cnt = 0; 125 | pci_config_address addr = {0}; 126 | addr.enable = 1; 127 | 128 | uint32_t reg = pci_read_config(&addr, 0); 129 | if (pci_vid(reg) == 0xFFFF) { 130 | return 0; 131 | } 132 | if (get_hdr_type(&addr) & pci_mf_hdr) { 133 | multibus_system = true; 134 | } 135 | dev_cnt += pci_add_devices_from_bus(pci_device_array, 0, &addr); 136 | 137 | if (multibus_system) { 138 | pci_config_address current_addr = addr; 139 | do { 140 | addr.function++; 141 | if (pci_vid(pci_read_config(&addr, 0)) == 0xFFFF) { 142 | break; 143 | } 144 | current_addr.bus = addr.function; 145 | dev_cnt += pci_add_devices_from_bus(pci_device_array, dev_cnt, ¤t_addr); 146 | } while (addr.function < 8); 147 | } 148 | 149 | return dev_cnt; 150 | } 151 | 152 | static const char *pci_get_dev_type_class_str(pci_device_data *dev) { 153 | if (dev->generic_header_fields.class_code < 0x14) { 154 | return pci_class_code_str[dev->generic_header_fields.class_code]; 155 | } 156 | if (dev->generic_header_fields.cache_line_size == 0x40) { 157 | return "co-processor"; 158 | } 159 | return pci_unknown_str; 160 | } 161 | 162 | static const char *pci_get_dev_type_subclass_str(pci_device_data *dev) { 163 | if (dev->generic_header_fields.subclass == 0x80) { 164 | return pci_unknown_str; 165 | } 166 | 167 | int off = 0; 168 | switch (dev->generic_header_fields.class_code) { 169 | case (pci_class_mass_storage_controller): 170 | break; 171 | case (pci_class_network_controller): 172 | off = 9; 173 | break; 174 | case (pci_class_display_controller): 175 | off = 18; 176 | break; 177 | case (pci_class_memory_controller): 178 | off = 21; 179 | break; 180 | case (pci_class_simple_communication_controller): 181 | off = 24; 182 | break; 183 | case (pci_class_base_system_peripheral): 184 | off = 31; 185 | break; 186 | case (pci_class_input_device_controller): 187 | off = 37; 188 | break; 189 | case (pci_class_serial_bus_controller): 190 | off = 41; 191 | break; 192 | case (pci_class_wireless_controller): 193 | off = 51; 194 | break; 195 | case (pci_class_bridge): 196 | off = 58; 197 | break; 198 | default: 199 | return pci_unknown_str; 200 | } 201 | off += dev->generic_header_fields.subclass; 202 | return pci_subclass_str[off]; 203 | } 204 | 205 | /* Print pci device tree information 206 | * 207 | * @param device **pci_device_array -- Device array after enumerate_pci_buses() is done 208 | * @param uint8_t device_count -- Amount of devices we have 209 | */ 210 | void pci_print_devtree(device **pci_device_array, uint8_t count) { 211 | for (uint8_t off = 0; off < count; off++) { 212 | pci_device_data *dev = pci_device_array[off]->device_data; 213 | blogf("PCI @ %04x:%04x:%04x: %s %s controller\n", 214 | dev->address.bus, 215 | dev->address.device, dev->address.function, 216 | pci_get_dev_type_subclass_str(dev), 217 | pci_get_dev_type_class_str(dev) 218 | ); 219 | if (dev->bist_executed) { 220 | blog(" --> Self test executed\n"); 221 | } 222 | } 223 | } 224 | 225 | 226 | -------------------------------------------------------------------------------- /src/drivers/pci/pci_util.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2025, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | #include 40 | #include 41 | 42 | /* Read PCI Configuration dword with given address 43 | * 44 | * @param pci_config_address *addr -- PCI configuration address to read 45 | * @param uint8_t offset -- Offset in pci configuration space to use 46 | * @return uint32_t configuration word we received 47 | */ 48 | uint32_t pci_read_config(pci_config_address *addr, uint8_t offset) { 49 | addr->offset = offset; 50 | outl(to_uint32_t(addr), pci_config_port); 51 | addr->offset = 0; 52 | return inl(pci_data_port); 53 | } 54 | 55 | /* Write PCI Configuration dword with given address 56 | * 57 | * @param pci_config_address *addr -- PCI configuration address to read 58 | * @param uint8_t offset -- Offset in pci configuration space to use 59 | * @param uint32_t data -- configuration dword to write 60 | */ 61 | void pci_write_config(pci_config_address *addr, uint8_t offset, uint32_t data) { 62 | addr->offset = offset; 63 | outl(to_uint32_t(addr), pci_config_port); 64 | outl(data, pci_data_port); 65 | addr->offset = 0; 66 | } 67 | 68 | /* Start device self test if it's supported 69 | * 70 | * @param pci_device_data *dev -- Pointer to pci_device_data structure 71 | * @return bool started 72 | */ 73 | bool pci_start_selftest(pci_device_data *dev) { 74 | pci_bist_register reg; 75 | reg.register_raw = dev->generic_header_fields.built_in_self_test; 76 | if (reg.fields.bist_capable) { 77 | reg.fields.start_bist = 1; 78 | pci_write_config(&dev->address, 0x0C, reg.register_raw); 79 | return true; 80 | } 81 | return false; 82 | } 83 | 84 | -------------------------------------------------------------------------------- /src/drivers/pic_8259/pic.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include 34 | 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | 41 | pic_ocw2 pic_current_ocw2 = {0}; 42 | pic_ocw3 pic_current_ocw3 = {0}; 43 | 44 | pic_icw1 pic_current_icw1 = {0}; 45 | pic_icw2 pic_current_icw2 = {0}; 46 | pic_icw3_primary pic_picw3 = {0}; 47 | pic_icw3_secondary pic_sicw3 = {0}; 48 | pic_icw4 pic_current_icw4 = {0}; 49 | 50 | /* Helper to send control words to interrupt controller(s) 51 | * 52 | * @param uint16_t port -- which pic we're talking to 53 | * @param uint8_t *cw -- pointer to control word to send 54 | */ 55 | static inline void pic_send_cmd(uint16_t port, uint8_t *cw) { 56 | outb(*cw, port); 57 | iodelay(50); 58 | } 59 | 60 | /* Send data to programmable interrupt controller 61 | * 62 | * @param uint16_t port -- which pic we're talking to 63 | * @param uint8_t *dw -- pointer to data word to send 64 | */ 65 | static inline void pic_send_data(uint16_t port, uint8_t *ow) { 66 | outb(*ow, port+1); 67 | iodelay(50); 68 | } 69 | 70 | /* Read data (mask) from programmable_interrupt_controller 71 | * 72 | * @param uint16_t port -- which pic we're talking to 73 | * @return uint8_t mask 74 | */ 75 | static inline uint8_t pic_get_mask(uint16_t port) { 76 | return inb(port+1); 77 | } 78 | 79 | /* Send end of interrupt message to the programmable interrupt controller. 80 | * 81 | * @param uint8_t irq -- number of interrupt we're dealing with 82 | */ 83 | void pic_send_eoi(uint8_t irq) { 84 | if (irq >= 7) { 85 | outb(0x20, PIC_PRIMARY_PORT); 86 | } 87 | outb(0x20, PIC_SECONDARY_PORT); 88 | } 89 | 90 | /* Initialise the programmable interrupt controller. 91 | * 92 | * @param device *dev -- device structure for pic 93 | * @return bool true on success, false on error. 94 | */ 95 | enum DEVICE_STATUS pic_initialize(device *dev) { 96 | pic_full_configuration *pic_config = (pic_full_configuration *)dev->device_data; 97 | 98 | pic_current_icw1.icw4_needed = 1; 99 | pic_current_icw1.icw_1 = 1; 100 | 101 | // Start pic_initialisation sequence with command words 1 to 4 102 | pic_send_cmd(PIC_PRIMARY_PORT, (uint8_t*)&pic_current_icw1); 103 | pic_send_cmd(PIC_SECONDARY_PORT, (uint8_t*)&pic_current_icw1); 104 | 105 | // Send interrupt vector offsets (0, 8) 106 | // 107 | uint8_t v = 0x20; 108 | pic_send_data(PIC_PRIMARY_PORT, &v); 109 | //pic_send_data(PIC_SECONDARY_PORT, (uint8_t *)&pic_current_ocw2); 110 | v = 0x28; 111 | pic_send_data(PIC_SECONDARY_PORT, &v); 112 | 113 | // Send device cascading config (irq2 => secondary PIC, cascading identity to 114 | // secondary PIC) 115 | // 116 | pic_picw3.device_map = 4; 117 | pic_sicw3.primary_int = 2; 118 | 119 | pic_send_data(PIC_PRIMARY_PORT, (uint8_t *)&pic_picw3); 120 | pic_send_data(PIC_SECONDARY_PORT, (uint8_t *)&pic_sicw3); 121 | 122 | // Set both PICs to 8086 mode 123 | pic_current_icw4.mode = 1; 124 | 125 | pic_send_data(PIC_PRIMARY_PORT, (uint8_t *)&pic_current_icw4); 126 | pic_send_data(PIC_SECONDARY_PORT, (uint8_t *)&pic_current_icw4); 127 | 128 | // Mask away all ISA interrupts for now, each handler should unmask 129 | // corresponding line. 130 | // 131 | //uint8_t data = 0x0F & ~(1 << 2); 132 | uint8_t data = 0x00; 133 | pic_send_data(PIC_PRIMARY_PORT, &data); 134 | pic_send_data(PIC_SECONDARY_PORT, &data); 135 | 136 | pic_config->icw1 = &pic_current_icw1; 137 | pic_config->icw2 = &pic_current_icw2; 138 | pic_config->icw3_primary = &pic_picw3; 139 | pic_config->icw3_secondary = &pic_sicw3; 140 | pic_config->icw4 = &pic_current_icw4; 141 | pic_config->ocw2 = &pic_current_ocw2; 142 | pic_config->ocw3 = &pic_current_ocw3; 143 | 144 | 145 | return status_initialised; 146 | } 147 | 148 | /* Mask irq line 149 | * 150 | * @param uint8_t line -- line to mask 151 | */ 152 | void pic_mask_irq(uint8_t line) { 153 | uint16_t port = (line < 8) ? PIC_PRIMARY_PORT : PIC_SECONDARY_PORT; 154 | line = line ? (line - 8) : (port == PIC_PRIMARY_PORT); 155 | 156 | uint8_t v = pic_get_mask(line); 157 | v |= (1 << line); 158 | outb(v, port); 159 | } 160 | 161 | /* Unmask irq line 162 | * 163 | * @param uint8_t line -- line to mask 164 | */ 165 | void pic_unmask_irq(uint8_t line) { 166 | uint16_t port = (line < 8) ? PIC_PRIMARY_PORT : PIC_SECONDARY_PORT; 167 | line = (line < 8) ? line : line-8; 168 | 169 | uint8_t v = pic_get_mask(port); 170 | v &= ~(1 << line); 171 | pic_send_data(port, &v); 172 | } 173 | 174 | 175 | /* Read irq register from the programmable interrupt controller. 176 | * 177 | * @param pic_ocw3 *ocw -- command byte to send 178 | * @return uint16_t irq 179 | */ 180 | uint16_t pic_read_irq(pic_ocw3 *ocw) { 181 | pic_send_cmd(PIC_PRIMARY_PORT, (uint8_t *)ocw); 182 | pic_send_cmd(PIC_SECONDARY_PORT, (uint8_t *)ocw); 183 | uint16_t ret = inb(PIC_SECONDARY_PORT) << 8; 184 | ret |= inb(PIC_PRIMARY_PORT); 185 | return ret; 186 | } 187 | 188 | /* Get in-service register value (Which irqs are served) 189 | * 190 | * @return uint16_t isr in form of SECONDARY << 8 | PRIMARY 191 | */ 192 | uint16_t pic_read_isr(void) { 193 | pic_ocw3 ocw = {0}; 194 | ocw.nop_b0 = 1; 195 | ocw.ident = 2; 196 | return pic_read_irq(&ocw); 197 | } 198 | 199 | /* Get interrupt request register value (Which interrupts have been raised) 200 | * 201 | * @return uint16_t irr in form of SECONDARY << 8 | PRIMARY 202 | */ 203 | uint16_t pic_read_irr(void) { 204 | pic_ocw3 ocw = {0}; 205 | ocw.next = 1; 206 | ocw.nop_b0 = 1; 207 | ocw.ident = 2; 208 | return pic_read_irq(&ocw); 209 | } 210 | 211 | -------------------------------------------------------------------------------- /src/drivers/pit/pit.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2025, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #include 33 | 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | 40 | /* Read pit status for a given channel 41 | * 42 | * @param uint8_t channel -- channel to read 43 | * @return uint8_t status of the channel 44 | */ 45 | 46 | /* Setup PIT with default init. 47 | * 48 | * @param device *dev -- Device info structure 49 | * @return bool true on success, false on error. 50 | */ 51 | enum DEVICE_STATUS pit_init(device *dev __attribute__((unused))) { 52 | pit_command cmd; 53 | 54 | cmd.access_mode = lo_and_hi_byte; 55 | cmd.binary_mode = binary; 56 | cmd.operating_mode = rate_generator; 57 | cmd.selected_channel = channel_0; 58 | 59 | pit_write_command(&cmd); 60 | outb(0x00, 0x40); 61 | outb(0x10, 0x40); 62 | 63 | return status_initialised; 64 | } 65 | 66 | /* PIT Interrupt handler 67 | * 68 | */ 69 | void __attribute__((section(".rom_int_handler"))) pit_int_handler(void) { 70 | asm volatile("mov eax, 0x12345678"); 71 | asm volatile("cli"); 72 | asm volatile("hlt"); 73 | do {} while (1); 74 | } 75 | 76 | -------------------------------------------------------------------------------- /src/drivers/pit/pit_handler.S: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | */ 33 | .code32 34 | .section .text 35 | .global pit_irq_entry 36 | .extern pit_int_handler 37 | .extern bda_int_handler_cpu_state_end 38 | 39 | #include 40 | 41 | pit_irq_entry: 42 | mov eax, 0x12341234 43 | cli 44 | hlt 45 | jmp pit_irq_entry 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/drivers/serial/serial.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | */ 33 | 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | 40 | #include 41 | 42 | /* interrupt handler for serial port driver 43 | * 44 | */ 45 | void __attribute__((section(".rom_int_handler"))) serial_int_handler(void) { 46 | 47 | } 48 | 49 | /* Poll for serial port until line is empty. 50 | * 51 | * @param unsigned short port -- Port to wait for 52 | * @return 0 when line is empty, or non-zero if timed out. 53 | */ 54 | unsigned char serial_wait_for_tx_empty(unsigned short port) { 55 | for (int i = 0; i < 5000; i++) { 56 | if ((serial_get_line_status(port) & 0x01) == 0) { 57 | return 0; 58 | } 59 | asm volatile("nop":::"memory"); 60 | } 61 | return 1; 62 | } 63 | 64 | /* Initialise a serial port for comms 65 | * 66 | * @param device *dev -- Pointer to device structure 67 | * @return 0 on success or non-zero on error 68 | */ 69 | enum DEVICE_STATUS serial_init_device(device *dev) { 70 | unsigned short port = SERIAL_COM_PRIMARY; 71 | 72 | serial_uart_device *sdev = (serial_uart_device *)dev->device_data; 73 | serial_interrupts_disable(port); 74 | serial_set_baudrate(port, COM_DEFAULT_BRD); 75 | serial_set_linecontrol(port, COM_DEFAULT_LINE_CTL); 76 | if (serial_device_is_faulty(port)) { 77 | return status_faulty; 78 | } 79 | outb(0x0F, SERIAL_MCR(port)); 80 | 81 | // Enable FIFO, clear with 14 byte treshold 82 | outb(0xC7, SERIAL_FIFO_CTRL(port)); 83 | 84 | sdev->base_port = port; 85 | sdev->baudrate_divisor = COM_DEFAULT_BRD; 86 | sdev->fifo_control = 0xC7; 87 | return status_initialised; 88 | } 89 | 90 | /* Write a string over serial line 91 | * 92 | * @param unsigned short port -- Device to write to 93 | * @param const unsigned char *msg -- Absolute address to string to write 94 | * @return amount of bytes transmitted 95 | */ 96 | size_t serial_tx(unsigned short port, const char *msg, size_t len) { 97 | size_t i; 98 | 99 | for (i = 0; i < len; i++) { 100 | do { } while (serial_wait_for_tx_empty(port)); 101 | if (msg[i] == '\n') { 102 | outb('\r', port); 103 | do { } while (serial_wait_for_tx_empty(port)); 104 | } 105 | outb(msg[i], port); 106 | } 107 | return i; 108 | } 109 | 110 | /* Receive a string over serial line 111 | * 112 | * @param unsigned short port -- Device to read from 113 | * @param unsigned char *dst -- Buffer to read to 114 | * @param const size_t size -- How many bytes to read 115 | * @return amount of bytes received 116 | */ 117 | size_t serial_rx(unsigned short port, char *dst, const size_t size) { 118 | size_t i; 119 | for (i = 0; i < size; i++) { 120 | while (serial_wait_for_tx_empty(port) != 0) { 121 | continue; 122 | } 123 | dst[i] = inb(SERIAL_DATA(port)); 124 | } 125 | return i; 126 | } 127 | 128 | 129 | -------------------------------------------------------------------------------- /src/include/asm/cpu/longjmp.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #ifndef __ASM_HELPERS_H__ 33 | #define __ASM_HELPERS_H__ 34 | 35 | /* Workaround for compiler/clang issue, refer 36 | * https://github.com/llvm/llvm-project/issues/49636 37 | */ 38 | #define LONGJMP(segment, target) \ 39 | .byte 0x66; \ 40 | .byte 0xEA; \ 41 | .int target; \ 42 | .short segment; 43 | 44 | #define LONGJMP32(segment, target) \ 45 | .byte 0xEA; \ 46 | .int target; \ 47 | .short segment; 48 | 49 | #endif // __ASM_HELPERS_H__ 50 | -------------------------------------------------------------------------------- /src/include/asm/interrupts/ivt_entry.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #ifndef __ASM_INT_HELPERS__ 33 | #define __ASM_INT_HELPERS__ 34 | 35 | /* Helper macro for registering new interrupt handlers 36 | * 37 | * Note, that preboot and boot-services must use different IVT entries, as 38 | * different segment value is needed. 39 | * 40 | */ 41 | #define IVT_INT_HANDLER_ENTRY_PRE_BOOTSERVICES(handler_entry) \ 42 | cli ; \ 43 | push sp ; \ 44 | mov bp, sp ; \ 45 | mov sp, bda_int_handler_cpu_state_end ; \ 46 | pusha ; \ 47 | mov sp, mem_ebda ; \ 48 | mov bx, handler_entry ; \ 49 | jmp interrupt_handler_init_runtime ; \ 50 | 51 | #endif // __ASM_INT_HELPERS__ 52 | -------------------------------------------------------------------------------- /src/include/console/console.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef __CONSOLE_H__ 34 | #define __CONSOLE_H__ 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | typedef size_t (*tx_func)(unsigned short addr, const char *msg, size_t len); 41 | 42 | typedef struct { 43 | device *dev; 44 | size_t (*tx_func)(unsigned short port, const char *msg, size_t len); 45 | bool enabled; 46 | } console_device; 47 | 48 | /* Write log message over default output device 49 | * 50 | * @param console_device *dev -- device to use for output 51 | * @param char *msg -- message to print 52 | * 53 | */ 54 | void blog(char *msg); 55 | 56 | /* log messages, now with format string! 57 | * 58 | * @param const char *restrict format 59 | * @param ... :3 60 | * @return int bytes written 61 | */ 62 | int blogf(const char *restrict format, ...); 63 | 64 | /* log messages, now with format string from panic() and co! 65 | * 66 | * @param const char *restrict format 67 | * @param va_list ap :3 68 | * @return int bytes written 69 | */ 70 | int vfblogf(const char *restrict format, va_list ap); 71 | 72 | #endif // __CONSOLE_H__ 73 | -------------------------------------------------------------------------------- /src/include/cpu/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #ifndef __CPU_INST_COMMON_H__ 33 | #define __CPU_INST_COMMON_H__ 34 | 35 | #include 36 | #include 37 | 38 | #define get_gpr(reg) get_##reg() 39 | 40 | /* Command register 0 settings 41 | * 42 | * @member CR0_PE -- Paging enabled 43 | * @member CR0_MP -- Monitor co-process 44 | * @member CR0_EM -- x87 FPU emulation 45 | * @member CR0_TS -- Task switched 46 | * @member CR0_ET -- Extension type 47 | * @member CR0_NE -- Numeric Error 48 | * @member CR0_WP -- Write Protect 49 | * @member CR0_NW -- Not write through 50 | * @member CR0_CD -- Cache Disabled 51 | * @member CR0_PG -- Paging 52 | */ 53 | enum CR0_SETTING { 54 | CR0_PE = ( 1 << 0 ), 55 | CR0_MP = ( 1 << 1 ), 56 | CR0_EM = ( 1 << 2 ), 57 | CR0_TS = ( 1 << 3 ), 58 | CR0_ET = ( 1 << 4 ), 59 | CR0_NE = ( 1 << 5 ), 60 | CR0_WP = ( 1 << 16 ), 61 | CR0_AM = ( 1 << 18 ), 62 | CR0_NW = ( 1 << 29 ), 63 | CR0_CD = ( 1 << 30 ), 64 | CR0_PG = ( 1 << 31 ) 65 | }; 66 | 67 | /* Helper structure for tracking cpu state in 16-bit mode. 68 | * The register order matches pusha/popa when we have downwards growing stack. 69 | * 70 | */ 71 | typedef struct { 72 | uint16_t di; 73 | uint16_t si; 74 | uint16_t bp; 75 | uint16_t sp; 76 | uint16_t bx; 77 | uint16_t dx; 78 | uint16_t cx; 79 | uint16_t ax; 80 | } cpu_state_16b; 81 | 82 | /* Helper structure for tracking cpu state in 32-bit mode. 83 | * The register order matches pusha/popa when we have downwards growing stack. 84 | * 85 | */ 86 | typedef struct { 87 | uint32_t edi; 88 | uint32_t esi; 89 | uint32_t ebp; 90 | uint32_t esp; 91 | uint32_t ebx; 92 | uint32_t edx; 93 | uint32_t ecx; 94 | uint32_t eax; 95 | } cpu_state_32b; 96 | 97 | typedef struct { 98 | uint64_t r15; 99 | uint16_t r14; 100 | uint64_t r13; 101 | uint64_t r12; 102 | uint64_t r11; 103 | uint64_t r10; 104 | uint64_t r9; 105 | uint64_t r8; 106 | uint64_t rsp; 107 | uint64_t rbp; 108 | uint64_t rdi; 109 | uint64_t rsi; 110 | uint64_t rdx; 111 | uint64_t rcx; 112 | uint64_t rbx; 113 | uint64_t rax; 114 | } cpu_state_64b; 115 | 116 | static inline uint64_t __attribute__((always_inline)) get_rdi(void) { 117 | uint64_t r; 118 | asm volatile("mov %0, rdi":"=r"(r)); 119 | return r; 120 | } 121 | 122 | static inline uint64_t __attribute__((always_inline)) get_rsi(void) { 123 | uint64_t r; 124 | asm volatile("mov %0, rsi":"=r"(r)); 125 | return r; 126 | } 127 | 128 | static inline uint64_t __attribute__((always_inline)) get_rbp(void) { 129 | uint64_t r; 130 | asm volatile("mov %0, rbp":"=r"(r)); 131 | return r; 132 | } 133 | 134 | static inline uint64_t __attribute__((always_inline)) get_rsp(void) { 135 | uint64_t r; 136 | asm volatile("mov %0, rsp":"=r"(r)); 137 | return r; 138 | } 139 | 140 | static inline uint64_t __attribute__((always_inline)) get_rbx(void) { 141 | uint64_t r; 142 | asm volatile("mov %0, rbx":"=r"(r)); 143 | return r; 144 | } 145 | 146 | static inline uint64_t __attribute__((always_inline)) get_rcx(void) { 147 | uint64_t r; 148 | asm volatile("mov %0, rcx":"=r"(r)); 149 | return r; 150 | } 151 | 152 | static inline uint64_t __attribute__((always_inline)) get_rdx(void) { 153 | uint64_t r; 154 | asm volatile("mov %0, rdx":"=r"(r)); 155 | return r; 156 | } 157 | 158 | static inline uint64_t __attribute__((always_inline)) get_rax(void) { 159 | uint64_t r; 160 | asm volatile("mov %0, rax":"=r"(r)); 161 | return r; 162 | } 163 | 164 | static inline uint32_t __attribute__((always_inline)) get_cr0(void) { 165 | uint32_t r; 166 | asm volatile("mov %0, cr0":"=r"(r)); 167 | return r; 168 | } 169 | 170 | static inline void __attribute__((always_inline)) set_cr0(uint32_t v) { 171 | asm volatile("mov cr0, %0"::"r"(v)); 172 | } 173 | 174 | static inline uint32_t __attribute__((always_inline)) get_cr3(void) { 175 | uint32_t r; 176 | asm volatile("mov %0, cr3":"=r"(r)); 177 | return r; 178 | } 179 | 180 | static inline void __attribute__((always_inline)) set_cr3(uint32_t v) { 181 | asm volatile("mov cr3, %0"::"r"(v)); 182 | } 183 | 184 | static inline uint32_t __attribute__((always_inline)) get_cr4(void) { 185 | uint32_t r; 186 | asm volatile("mov %0, cr4":"=r"(r)); 187 | return r; 188 | } 189 | 190 | static inline void __attribute__((always_inline)) set_cr4(uint32_t v) { 191 | asm volatile("mov cr4, %0"::"r"(v)); 192 | } 193 | 194 | static inline uint32_t __attribute__((always_inline)) rdmsr(uint32_t msr) { 195 | uint32_t ret; 196 | asm volatile( 197 | "mov ecx, %0;" 198 | "rdmsr;" 199 | "mov %1, eax;" 200 | :"=r"(ret) 201 | :"r"(msr) 202 | :"eax","ecx" 203 | ); 204 | return ret; 205 | } 206 | 207 | static inline void __attribute__((always_inline)) wrmsr(uint32_t msr, uint32_t val) { 208 | asm volatile( 209 | "mov ecx, %0;" 210 | "mov eax, %1;" 211 | "wrmsr;" 212 | ::"r"(msr),"r"(val) 213 | :"eax","ecx" 214 | ); 215 | } 216 | 217 | /* Read gdtr to given 6-byte location 218 | * 219 | * @param void *dst -- where to read gdtr to 220 | */ 221 | static inline void __attribute__((always_inline)) get_gdtr(void *dst) { 222 | asm volatile("sgdt %0" : "=m"(dst)); 223 | } 224 | 225 | /* Write gdtr fro mgiven 6-byte location 226 | * 227 | * @param void *src -- where to read gdtr from 228 | */ 229 | static inline void __attribute((always_inline)) write_gdtr(void *src) { 230 | asm volatile("lgdt %0" :: "m"(src)); 231 | } 232 | 233 | /* Read code segment register 234 | * 235 | * @return uint16_t cs 236 | */ 237 | static inline uint16_t __attribute__((always_inline)) read_cs() { 238 | uint16_t ret; 239 | asm volatile("mov %0, cs" : "=r"(ret)); 240 | return ret; 241 | } 242 | 243 | /* Read data segment register 244 | * 245 | * @return uint16_t ds 246 | */ 247 | static inline uint16_t __attribute__((always_inline)) read_ds() { 248 | uint16_t ret; 249 | asm volatile("mov %0, ds" : "=r"(ret)); 250 | return ret; 251 | } 252 | 253 | /* Read extra segment register 254 | * 255 | * @return uint16_t es 256 | */ 257 | static inline uint16_t __attribute__((always_inline)) read_es() { 258 | uint16_t ret; 259 | asm volatile("mov %0, es" : "=r"(ret)); 260 | return ret; 261 | } 262 | 263 | /* Read stack segment register 264 | * 265 | * @return uint16_t ss 266 | */ 267 | static inline uint16_t __attribute__((always_inline)) read_ss() { 268 | uint16_t ret; 269 | asm volatile("mov %0, ss" : "=r"(ret)); 270 | return ret; 271 | } 272 | 273 | /* Read general purpose F segment register 274 | * 275 | * @return uint16_t fs 276 | */ 277 | static inline uint16_t __attribute__((always_inline)) read_fs() { 278 | uint16_t ret; 279 | asm volatile("mov %0, fs" : "=r"(ret)); 280 | return ret; 281 | } 282 | 283 | /* Read general purpose G segment register 284 | * 285 | * @return uint16_t gs 286 | */ 287 | static inline uint16_t __attribute__((always_inline)) read_gs() { 288 | uint16_t ret; 289 | asm volatile("mov %0, gs" : "=r"(ret)); 290 | return ret; 291 | } 292 | 293 | /* Write data segment register 294 | * 295 | * @param uint16_t ds -- new data segment register value 296 | */ 297 | static inline void __attribute__((always_inline)) write_ds(uint32_t ds) { 298 | asm volatile("mov ds, %0" :: "r"(ds)); 299 | } 300 | 301 | /* Write extra segment register 302 | * 303 | * @param uint16_t es -- new data segment register value 304 | */ 305 | static inline void __attribute__((always_inline)) write_es(uint32_t es) { 306 | asm volatile("mov es, %0" :: "r"(es)); 307 | } 308 | 309 | /* Write stack segment register 310 | * 311 | * @param uint16_t ss -- new data segment register value 312 | */ 313 | static inline void __attribute__((always_inline)) write_ss(uint32_t ss) { 314 | asm volatile("mov ss, %0" :: "r"(ss)); 315 | } 316 | 317 | /* Write general purpose F segment register 318 | * 319 | * @param uint16_t fs -- new data segment register value 320 | */ 321 | static inline void __attribute__((always_inline)) write_fs(uint32_t fs) { 322 | asm volatile("mov fs, %0" :: "r"(fs)); 323 | } 324 | 325 | /* Write general purpose G segment register 326 | * 327 | * @param uint16_t gs -- new data segment register value 328 | */ 329 | static inline void __attribute__((always_inline)) write_gs(uint32_t gs) { 330 | asm volatile("mov gs, %0" :: "r"(gs)); 331 | } 332 | 333 | /* Hang the cpu */ 334 | static inline void __attribute__((always_inline, noreturn)) hang(void) { 335 | do { 336 | asm volatile("cli"); 337 | asm volatile("hlt"); 338 | } while (1); 339 | } 340 | 341 | #endif // __CPU_INST_COMMON_H__ 342 | -------------------------------------------------------------------------------- /src/include/drivers/device.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef __DRIVER_DEVICE_GENERIC__ 34 | #define __DRIVER_DEVICE_GENERIC__ 35 | 36 | #include 37 | 38 | // Generic status for all devices we have. 39 | enum DEVICE_STATUS { 40 | status_unknown, // We haven't started initialising device or can't determine it's state 41 | status_not_present, // There's no device plugged into this port 42 | status_present, // We know the device is plugged in, but we haven't tried to initialize it yet. 43 | status_faulty, // device initialisation incomplete and/or device is misbehaving 44 | status_initialised, // Device initialisation completed and device is functional 45 | }; 46 | 47 | enum DEVICE_TYPE { 48 | device_access_pio, // This device is accessed primarily over pio 49 | device_access_mmio, // This device is accessed primarily over mmio 50 | device_bridge // This device provides connectivity to other devices 51 | }; 52 | 53 | // This structure holds data related to a given device. 54 | typedef struct __attribute__((packed)) { 55 | // Printable name of the device 56 | char *device_name; 57 | 58 | enum DEVICE_STATUS status : 5; 59 | enum DEVICE_TYPE type : 3; 60 | 61 | // Device specific data 62 | void *device_data; 63 | } device; 64 | 65 | /* Helper for allocating new device structures 66 | * 67 | * @param size_t size of device structure to allocate 68 | * @return pointer to our calloc'ed dev struct 69 | */ 70 | device *new_device(size_t size); 71 | 72 | /* Typedef for all processor IO device initialization functions */ 73 | typedef enum DEVICE_STATUS (*device_init_function)(device *dev); 74 | 75 | /* Initialize a given device 76 | * 77 | * @param device_init_function init -- device initialisation function to use 78 | * @param device *dev -- device structure for this device 79 | * @param char *name -- device name 80 | * @param bool critical -- Do we fail to boot if we lack this device 81 | */ 82 | void initialize_device(device_init_function init, device *dev, char *name, bool critical); 83 | 84 | #endif // __DRIVER_DEVICE_GENERIC__ 85 | -------------------------------------------------------------------------------- /src/include/drivers/kbdctl/8042.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #ifndef __8042_KBDCTL_H__ 33 | #define __8042_KBDCTL_H__ 34 | 35 | #include 36 | 37 | #include 38 | 39 | /* 8042 related definitions and declarations here. */ 40 | #define KBDCTL_DATA 0x60 41 | #define KBDCTL_STAT 0x64 42 | #define KBDCTL_CMD 0x64 43 | 44 | /* Status byte bit definitions */ 45 | #define KBDCTL_STAT_OUT_BUF 0x01 // Output / input status 46 | #define KBDCTL_STAT_IN_BUF 0x02 47 | #define KBDCTL_STAT_SYSF 0x04 // System flag 48 | #define KBDCTL_STAT_CD 0x08 // Command/Data, 0 = inbuf, 1 = ps2ctl 49 | #define KBDCTL_STAT_TIMEOUT 0x40 // Timeout error (0 = good, 1 = timeout) 50 | #define KBDCTL_STAT_PARITY 0x80 // Parity error (0 = good, 1 = timeout) 51 | 52 | /* Configuration byte bit definitions */ 53 | #define KBDCTL_CTL_P1_IE 0x01 // PS2 Port 1 interrupts enabled 54 | #define KBDCTL_CTL_P2_IE 0x02 // PS2 Port 2 interrupts enabled 55 | #define KBDCTL_CTL_SF 0x04 // System Flag (Passed POST or not) 56 | #define KBDCTL_CTL_PS1_CLKE 0x10 // First PS2 port clock enabled 57 | #define KBDCTL_CTL_PS2_CLKE 0x20 // 2nd PS2 port clock enabled 58 | #define KBDCTL_CTL_PS1_TE 0x40 // PS2 Port translation enabled 59 | 60 | #define KBDCTL_DEFAULT_CONFIG_MASK 0xBC // Disable IRQs and translation 61 | 62 | /* Controller output port bit definitions */ 63 | #define KBDCTL_CTL_OUT_SYSRST 0x01 // Pulse to reset 64 | #define KBDCTL_CTL_OUT_A20 0x02 // A20 gate output 65 | #define KBDCLT_CTL_OUT_P2_CLK 0x04 // Second ps2 port clock 66 | #define KBDCTL_CTL_OUT_P2_DATA 0x08 // PS2 port data 67 | #define KBDCTL_CTL_OUT_BUF_FULL_IRQ1 0x10 // Output buffer full @ port 1 68 | #define KBDCTL_CTL_OUT_BUFF_FULL_IRQ2 0x20 // Output buffer full @ port 2 69 | #define KBDCTL_CTL_OUT_P1_CLK 0x40 // First ps2 port clock 70 | #define KBDCTL_CTL_OUT_P1_DATA 0x80 // First ps2 port data 71 | 72 | // Command byte definitions: 73 | // 1.) Read "Byte 0" from internal ram, returns controller config byte 74 | // 2.) Read Nth byte of internal ram 75 | // 3.) Write byte0/controller configuration byte 76 | // 4.) Write Nth byte of internal ram 77 | // 5.) Disable second ps/2 port (if supported) 78 | // 6.) Enable second ps/2 port (if supported) 79 | // 7.) Test second ps/2 port (if supported) 80 | // 8.) Test ps/2 controller 81 | // 9.) Test 1st ps/2 port 82 | // 10.) Diagnostic dump (Read all ram) 83 | // 11.) Disable 1st ps/2 port 84 | // 12.) Enable 1st ps/2 port 85 | // 13.) Read controller input port 86 | // 14.) Copy bits 0-3 of input to status 4-7 87 | // 15.) Copy bits 4-7 of input to status 4-7 88 | // 16.) Read controller output port 89 | // 17.) Write next byte to Controller Output Port 90 | // Note: first check that output buffer is empty 91 | // 18.) Write next byte to ps/2 port 1 output buffer 92 | // Note: Makes it look like byte was from 1st ps/2 port 93 | // 19.) Write next byte to ps/2 port 2 output buffer 94 | // Note: Makes it look like the byte was from 2nd ps/2 port 95 | // 20.) Write next byte to ps/2 port input buffer 96 | // Note: Sends next byte to second ps/2 port) 97 | // 98 | #define KBDCTL_CMD_READ_CONFIG 0x20 99 | #define KBDCTL_CMD_READBN(x) (0x20 + x) 100 | #define KBDCTL_CMD_WRITE_CONFIG 0x60 101 | #define KBDCTL_CMD_WRITEBN(x) (0x60 + x) 102 | #define KBDCTL_CMD_DISABLE_P2 0xA7 103 | #define KBDCTL_CMD_ENABLE_P2 0xA8 104 | #define KBDCTL_CMD_TEST_P2 0xA9 105 | #define KBDCTL_CMD_TEST_CTL 0xAA 106 | #define KBDCTL_CMD_TEST_P1 0xAB 107 | #define KBDCTL_CMD_DUMP_RAM 0xAC 108 | #define KBDCTL_CMD_DISABLE_P1 0xAD 109 | #define KBDCTL_CMD_ENABLE_P1 0xAE 110 | #define KBDCTL_CMD_READ_CTL_IN 0xC0 111 | #define KBDCTL_CMD_CP_INLO_STATHI 0xC1 112 | #define KBDCTL_CMD_CP_INHI_STATHI 0xC2 113 | #define KBDCTL_CMD_READ_CTL_OUT 0xC3 114 | #define KBDCTL_CMD_WRITENEXT_CTL_OUT 0xD1 115 | #define KBDCTL_CMD_WRITENEXT_P1OUTBUF 0xD2 116 | #define KBDCTL_CMD_WRITENEXT_P2OUTBUF 0xD3 117 | #define KBDCTL_CMD_WRITENEXT_P2INBUF 0xD4 118 | #define KBDCTL_CMD_ENABLE_A20 0xDF 119 | #define KBDCTL_CMD_PULSE_OUT_LOW(x) (0xF0 | x) 120 | #define KBDCTL_CMD_CPU_HARD_RESET 0xFE 121 | #define KBDCTL_CMD_RST_DEVICE 0xFF 122 | 123 | // Device commands 124 | #define KBDCTL_DEV_CMD_RESET 0xFF 125 | 126 | // Command responses 127 | #define KBDCTL_SELFTEST_SUCCESS 0x55 128 | #define KBDCTL_STAT_ACK 0xFA 129 | #define KBDCTL_STAT_FAIL 0xFC 130 | 131 | // 8042/ps2 controoler status related information 132 | typedef struct { 133 | // Is this a dual channel controller 134 | bool dual_channel; 135 | 136 | // current configuration 137 | unsigned char current_configuration; 138 | 139 | // devices initialised 140 | int devices_initialised; 141 | 142 | // A20 line status for memory access :3 143 | bool a20line_enabled; 144 | 145 | } ps2_8042_status; 146 | 147 | // Send command to kbd controller, read response 148 | // 149 | // @param unsigned char v -- Command byte to send 150 | // @return bool true on success or fals eon error 151 | // 152 | bool kbdctl_send_cmd(unsigned char v); 153 | 154 | // Read a byte from data port once data becomes readable 155 | // 156 | // @return unsigned char data we received or -1 on error 157 | // 158 | unsigned char kbdctl_recv_data_poll(void); 159 | 160 | // Write 1 byte of data to kbdctl port once it becomes writable 161 | // 162 | // @param unsigned char v -- byte to write 163 | // @return true on success or false on timeout 164 | // 165 | bool kbdctl_send_data_poll(unsigned char v); 166 | 167 | // Disable both ps/2 ports 168 | // 169 | // @return int 0 on success or which port failed to disable on error (1, 2, or both) 170 | // 171 | int kbdctl_disable_ports(void); 172 | 173 | // Set keyboard controller byte with default config mask with 174 | // interrupts and translation layer disabled 175 | // 176 | // @return enum DEVICE_STATUS status of device 177 | // 178 | enum DEVICE_STATUS kbdctl_set_default_init(device *dev); 179 | 180 | // Perform keyboard controller self test. 181 | // 182 | // @return true on success or false on error 183 | // 184 | bool kbdctl_do_self_test(void); 185 | 186 | // Test a single device 187 | // 188 | // @param unsigned char dev_cmd -- device specific test cmd (KBDCTL_CMD_TEST_P{1,2} 189 | // @return unsigned char status of device test on success or -1 on error 190 | // 191 | unsigned char kbdctl_test_device(unsigned char dev_cmd); 192 | 193 | // Enable all ps/2 devices 194 | // 195 | // @return unsigned char devices initialised 196 | // 197 | unsigned char kbdctl_enable_devices(device *dev); 198 | 199 | // Reset a specific device 200 | // 201 | // @param int device_number -- 0 or 1 for 1st or 2nd device 202 | // @return bool true on success or false on error 203 | // 204 | bool kbdctl_reset_device(int which); 205 | 206 | #endif // __8042_KBDCTL_H__ 207 | -------------------------------------------------------------------------------- /src/include/drivers/pci/pci.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2025, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #ifndef __PCI_H__ 33 | #define __PCI_H__ 34 | 35 | #include 36 | #include 37 | 38 | #include 39 | 40 | 41 | enum pci_class_code { 42 | pci_class_unclassified = 0, 43 | pci_class_mass_storage_controller, 44 | pci_class_network_controller, 45 | pci_class_display_controller, 46 | pci_class_multimedia_controller, 47 | pci_class_memory_controller, 48 | pci_class_bridge, 49 | pci_class_simple_communication_controller, 50 | pci_class_base_system_peripheral, 51 | pci_class_input_device_controller, 52 | pci_class_docking_station, 53 | pci_class_processor, 54 | pci_class_serial_bus_controller, 55 | pci_class_wireless_controller, 56 | pci_class_intelligent_controller, 57 | pci_class_satellite_communication_controller, 58 | pci_class_encryption_controller, 59 | pci_class_signal_processing_controller, 60 | pci_class_processing_accelerator, 61 | pci_class_non_essential, 62 | pci_class_co_processor = 0x40, 63 | pci_class_unassigned = 0xFF 64 | }; 65 | 66 | enum unclassified_devices { 67 | non_vga_unclassified, 68 | vga_compatible_unclassified 69 | }; 70 | 71 | enum mass_storage_controllers { 72 | pci_mass_storage_controller_scsi_bus_controller, 73 | pci_mass_storage_controller_ide_controller, 74 | pci_mass_storage_controller_floppy_controller, 75 | pci_mass_storage_controller_ipi_bus_controller, 76 | pci_mass_storage_controller_raid_controller, 77 | pci_mass_storage_controller_ata_controller, 78 | pci_mass_storage_controller_sata_controller, 79 | pci_mass_storage_controller_serial_scsi_controller, 80 | pci_mass_storage_controller_nv_memory_controller, 81 | pci_mass_storage_controller_other_storage = 0x80 82 | }; 83 | 84 | enum pci_bridge_type { 85 | pci_host_bridge, 86 | pci_isa_bridge, 87 | pci_eisa_bridge, 88 | pci_mca_bridge, 89 | pci_pci2pci_bridge, 90 | pci_pcmcia_bridge, 91 | pci_nubus_bridge, 92 | pci_cardbus_bridge, 93 | pci_raceway_bridge, 94 | pci_pci2pci_bridge2, 95 | pci_infiband_to_pci_host, 96 | pci_other_bridge = 0x80 97 | }; 98 | 99 | typedef struct { 100 | uint32_t bar0; 101 | uint32_t bar1; 102 | uint32_t bar2; 103 | uint32_t bar3; 104 | uint32_t bar4; 105 | uint32_t bar5; 106 | uint32_t cardbus_cis_ptr; 107 | uint16_t subsystem_vendor_id; 108 | uint16_t subsystem_id; 109 | uint32_t expansion_rom_bar; 110 | uint8_t capabilities; 111 | uint16_t reserved0; 112 | uint8_t reserved2; 113 | uint32_t reserved3; 114 | uint8_t interrupt_line; 115 | uint8_t interrupt_pin; 116 | uint8_t min_grant; 117 | uint8_t max_latency; 118 | } pci_general_device_data; 119 | 120 | typedef struct { 121 | uint32_t bar0; 122 | uint32_t bar1; 123 | uint8_t primary_bus_number; 124 | uint8_t secondary_bus_number; 125 | uint8_t subordinate_bus_number; 126 | uint8_t secondary_latency_timer; 127 | uint8_t io_base; 128 | uint8_t io_limit; 129 | uint16_t secondary_status; 130 | uint16_t memory_base; 131 | uint16_t memory_limit; 132 | uint16_t prefetch_memory_base; 133 | uint16_t prefetch_memory_limit; 134 | uint32_t prefetch_base_hi; 135 | uint32_t prefetch_limit_hi; 136 | uint16_t io_base_hi; 137 | uint16_t io_limit_hi; 138 | uint8_t capabilities; 139 | uint16_t reserved0; 140 | uint8_t reserved1; 141 | uint32_t expansion_rom_bar; 142 | uint8_t interrupt_line; 143 | uint8_t interrupt_pin; 144 | uint16_t bridge_control; 145 | } pci2pci_bridge_data; 146 | 147 | typedef struct { 148 | uint16_t device_id; 149 | uint16_t vendor_id; 150 | uint16_t status; 151 | uint16_t command; 152 | uint8_t class_code; 153 | uint8_t subclass; 154 | uint8_t prog_if; 155 | uint8_t revision_id; 156 | uint8_t bist; 157 | uint8_t header_type; 158 | uint8_t latency_timer; 159 | uint8_t cache_line_size; 160 | uint32_t cb_socket_bar; 161 | uint16_t secondary_status; 162 | uint8_t reserved; 163 | uint8_t offset_of_capabilities_list; 164 | uint8_t cardbus_latency_timer; 165 | uint8_t subordinate_bus_number; 166 | uint8_t cardbus_bus_number; 167 | uint8_t pci_bus_number; 168 | uint32_t memory_base_0; 169 | uint32_t memory_limit_0; 170 | uint32_t memory_base_1; 171 | uint32_t memory_limit_1; 172 | uint32_t io_base_0; 173 | uint32_t io_limit_0; 174 | uint32_t io_base_1; 175 | uint32_t io_limit_1; 176 | uint16_t bridge_control; 177 | uint8_t interrupt_pin; 178 | uint8_t interrupt_line; 179 | uint16_t subsystem_vendor_id; 180 | uint16_t subsystem_device_id; 181 | uint32_t legacy_card_bar; 182 | } pci2cbus_bridge_data; 183 | 184 | typedef struct { 185 | uint16_t vendor_id; 186 | uint16_t device_id; 187 | uint16_t command; 188 | uint16_t status; 189 | uint8_t revision_id; 190 | uint8_t programming_interface_byte; 191 | uint8_t subclass; 192 | uint8_t class_code; 193 | uint8_t cache_line_size; 194 | uint8_t latency_timer; 195 | uint8_t header_type; 196 | uint8_t built_in_self_test; 197 | } pci_header; 198 | 199 | enum pci_header_type { 200 | pci_std_hdr, 201 | pci2pci_bridge_hdr, 202 | pci2cb_bridge_hdr, 203 | pci_mf_hdr = 0x80 204 | }; 205 | 206 | /* PCI BIST register definition 207 | * 208 | */ 209 | typedef union { 210 | uint8_t register_raw; 211 | struct __attribute__((packed)) { 212 | unsigned completion_code : 4; 213 | unsigned reserved : 2; 214 | unsigned start_bist : 1; 215 | unsigned bist_capable : 1; 216 | } fields; 217 | } pci_bist_register; 218 | 219 | /* PIO addresses for PCI configuration and data. 220 | */ 221 | static const uint16_t pci_config_port = 0x0CF8; 222 | static const uint16_t pci_data_port = 0x0CFC; 223 | 224 | /* PCI Configuration address 225 | * 226 | * @member enable -- Set to one to enable 227 | * @member reserved -- Set to 0 228 | * @member bus -- Which PCI bus we're working with 229 | * @member device -- Which PCI device in that bus we're working with 230 | * @member function -- Which device function do we want 231 | * @member offset -- Which dword out of the 256-byte configuration space 232 | * are we interested in 233 | */ 234 | typedef struct __attribute__((packed)) { 235 | unsigned offset : 8; 236 | unsigned function : 3; 237 | unsigned device : 5; 238 | unsigned bus : 8; 239 | unsigned reserved : 7; 240 | unsigned enable : 1; 241 | } pci_config_address; 242 | 243 | 244 | /* Structure for holding information about our pci subsystem 245 | * 246 | */ 247 | typedef struct { 248 | pci_config_address address; 249 | bool bist_executed; 250 | pci_header generic_header_fields; 251 | union { 252 | pci_general_device_data device_hdr; 253 | pci2pci_bridge_data pci2pci_bridge_hdr; 254 | pci2cbus_bridge_data pci2cbus_bridge_hdr; 255 | }; 256 | } pci_device_data; 257 | 258 | typedef struct __attribute__((packed)) { 259 | bool mode : 1; 260 | unsigned type : 2; 261 | bool prefetchable : 1; 262 | unsigned addr : 28; 263 | } pci_memory_bar_fields; 264 | 265 | typedef struct __attribute__((packed)) { 266 | bool mode : 1; 267 | bool reserved : 1; 268 | unsigned addr : 30; 269 | } pci_io_bar_fields; 270 | 271 | typedef union { 272 | uint32_t raw_bar; 273 | pci_memory_bar_fields memory_bar; 274 | pci_io_bar_fields io_bar; 275 | } pci_bar; 276 | 277 | /* Fetch headers for all pci devices we have plugged in 278 | * 279 | * @param device *pci_device_array -- Pointer to pci device data 280 | * @return uint8_t amount of devices found or -1 on error 281 | */ 282 | uint8_t enumerate_pci_buses(device **pci_device_array); 283 | 284 | /* Print pci device tree information 285 | * 286 | * @param device **pci_device_array -- Device array after enumerate_pci_buses() is done 287 | * @param uint8_t device_count -- Amount of devices we have 288 | */ 289 | void pci_print_devtree(device **pci_device_array, uint8_t device_count); 290 | 291 | static const char *pci_unknown_str = "other"; 292 | 293 | static const char *pci_class_code_str[] = { 294 | "unclassified", 295 | "mass storage", 296 | "network", 297 | "display", 298 | "multimedia", 299 | "memory", 300 | "bridge", 301 | "simple comms", 302 | "base system peripheral", 303 | "input device", 304 | "docking station", 305 | "processor", 306 | "serial bus", 307 | "wireless", 308 | "intelligent", 309 | "satcom", 310 | "encryption", 311 | "signal processing", 312 | "processing accelerator", 313 | "non essential", 314 | }; 315 | 316 | static const char *pci_subclass_str[] = { 317 | 318 | // Mass storage 319 | "SCSI", 320 | "IDE", 321 | "Floppy", 322 | "IPI", 323 | "RAID", 324 | "ATA", 325 | "Serial ATA", 326 | "Serial SCSI", 327 | "NV memory", 328 | 329 | // Net - 9 330 | "ethernet", 331 | "token ring", 332 | "FDDI", 333 | "ATM", 334 | "ISDN", 335 | "WorldFip", 336 | "PICMG", 337 | "infiniband", 338 | "fabric", 339 | 340 | // Display - 18 341 | "VGA", 342 | "XGA", 343 | "3D", 344 | 345 | // Memory - 21 346 | "RAM", 347 | "flash", 348 | 349 | // Simple comms - 24 350 | "serial", 351 | "parallel", 352 | "multiport serial", 353 | "modem", 354 | "iee 488", 355 | "smart card", 356 | 357 | // base system - 31 358 | "PIC", 359 | "DMA", 360 | "timer", 361 | "RTC", 362 | "PCI", 363 | "SD", 364 | "IOMMU", 365 | 366 | // input - 37 367 | "keyboard", 368 | "digitizer pen", 369 | "mouse", 370 | "scanner", 371 | "gameport", 372 | 373 | // Serial bus - 41 374 | "firewire", 375 | "access bus", 376 | "SSA", 377 | "USB", 378 | "Fibre channel", 379 | "SMbus", 380 | "InfiniBand", 381 | "IPMI", 382 | "SERCOS", 383 | "CANbus", 384 | 385 | // Wireless - 51 386 | "iRDA", 387 | "IR", 388 | "RF", 389 | "bluetooth", 390 | "broadband", 391 | "802.1a", 392 | "802.1b", 393 | 394 | // bridge - 58 395 | "Host", 396 | "ISA", 397 | "EISA", 398 | "MCA", 399 | "PCI", 400 | "PCMCIA", 401 | "NuBus", 402 | "CardBus", 403 | "RACEway", 404 | "PCI", 405 | "InfiniBand to PCI", 406 | }; 407 | 408 | 409 | #endif // __PCI_H__ 410 | -------------------------------------------------------------------------------- /src/include/drivers/pci/pci_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2025, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef __PCI_UTIL_H__ 34 | #define __PCI_UTIL_H__ 35 | 36 | #include 37 | 38 | #include 39 | 40 | /* helpers to read specific values out of pci config register 41 | * 42 | * @param uint32_t register -- register to read from 43 | * @return 44 | */ 45 | static uint16_t pci_did(uint32_t pci_reg) { 46 | return (uint16_t)(pci_reg >> 16); 47 | } 48 | 49 | static uint16_t pci_vid(uint32_t pci_reg) { 50 | return (uint16_t)(pci_reg & 0x0000FFFF); 51 | } 52 | 53 | static enum pci_class_code pci_class(uint32_t pci_reg) { 54 | return (uint8_t)(pci_reg >> 24); 55 | } 56 | 57 | static uint8_t pci_subclass(uint32_t pci_reg) { 58 | return (uint8_t)(pci_reg >> 16); 59 | } 60 | 61 | static uint8_t pci_header_type(uint32_t pci_reg) { 62 | return (uint8_t)(pci_reg >> 16); 63 | } 64 | 65 | static uint8_t pci_prog_if(uint32_t pci_reg) { 66 | return (uint8_t)(pci_reg >> 8); 67 | } 68 | 69 | static uint16_t pci_io_base(uint32_t pci_reg) { 70 | return (uint16_t)(pci_reg); 71 | } 72 | 73 | static uint16_t pci_io_limit(uint32_t pci_reg) { 74 | return (uint16_t)(pci_reg >> 16); 75 | } 76 | 77 | /* Read PCI Configuration dword with given address 78 | * 79 | * @param pci_config_address *addr -- PCI configuration address to read 80 | * @param uint8_t offset -- Offset in pci configuration space to use 81 | * @return uint32_t configuration dword we received 82 | */ 83 | uint32_t pci_read_config(pci_config_address *addr, uint8_t offset); 84 | 85 | /* Write PCI Configuration dword with given address 86 | * 87 | * @param pci_config_address *addr -- PCI configuration address to read 88 | * @param uint8_t offset -- Offset in pci configuration space to use 89 | * @param uint32_t data -- configuration dword to write 90 | */ 91 | void pci_write_config(pci_config_address *addr, uint8_t offset, uint32_t data); 92 | 93 | static pci_bist_register pci_read_bist(pci_device_data *dev) { 94 | dev->address.offset = 0; 95 | pci_bist_register ret; 96 | ret.register_raw = (uint8_t)(pci_read_config(&dev->address, 0x0C) >> 24); 97 | return ret; 98 | } 99 | 100 | static pci_bar pci_read_bar(pci_config_address *addr, uint8_t bar) { 101 | pci_bar ret; 102 | ret.raw_bar = pci_read_config(addr, (0x10 + (bar * 4))); 103 | return ret; 104 | } 105 | 106 | /* Check if bar is for memory space or I/O 107 | * 108 | * @param uint32_t bar -- bar to check 109 | * @return bool true if this is io-space bar 110 | */ 111 | static inline bool pci_io_bar(pci_bar bar) { 112 | return ((bar.raw_bar & 1) == 1); 113 | } 114 | 115 | /* decode pci io bar 116 | * 117 | * @param pci_bar bar 118 | * @return decoded io-bar address 119 | */ 120 | static inline uint32_t decode_io_bar(pci_bar bar) { 121 | return (bar.raw_bar & 0xFFFFFFFC); 122 | } 123 | 124 | /* decode pci mem bar 125 | * 126 | * @param pci_bar bar 127 | * @return decoded mem-bar address on success or 0 on error 128 | */ 129 | static inline uint32_t decode_mem_bar(pci_bar bar) { 130 | if (bar.memory_bar.type == 0) { 131 | return (bar.raw_bar & 0xFFFFFFF0); 132 | } else if (bar.memory_bar.type == 1) { 133 | return (bar.raw_bar & 0x0000FFF0); 134 | } else { 135 | return 0; 136 | } 137 | } 138 | 139 | 140 | /* Get decoded PCI bar address 141 | * 142 | * @param pci_bar bar -- bar to decode 143 | * @return uint32_t address 144 | */ 145 | static inline uint32_t pci_decode_bar(pci_bar bar) { 146 | if (pci_io_bar(bar)) { 147 | return decode_io_bar(bar); 148 | } 149 | return decode_mem_bar(bar); 150 | } 151 | 152 | /* Check if this device is a pci<->pci bridge 153 | * 154 | * @param pci_config_address *addr -- PCI configuration address to read 155 | * @return bool true if this is indeed, a pci2pci bridge 156 | */ 157 | static inline bool pci_dev_is_bridge(pci_config_address *addr) { 158 | uint32_t reg = pci_read_config(addr, 8); 159 | if (pci_class(reg) == pci_class_bridge) { 160 | enum pci_bridge_type type = pci_subclass(reg); 161 | if (type == pci_pci2pci_bridge) { 162 | return true; 163 | } 164 | } 165 | return false; 166 | } 167 | 168 | /* Check status of device self test 169 | * 170 | * @param pci_device_data *dev -- Pointer to pci_device_data structure 171 | * @return bool true if self test succeeded 172 | */ 173 | static inline bool pci_selftest_success(pci_device_data *dev) { 174 | pci_bist_register reg = pci_read_bist(dev); 175 | return (reg.fields.completion_code == 0); 176 | } 177 | 178 | /* Start device self test if it's supported 179 | * 180 | * @param pci_device_data *dev -- Pointer to pci_device_data structure 181 | * @return bool started 182 | */ 183 | bool pci_start_selftest(pci_device_data *dev); 184 | 185 | #endif // __PCI_H__ 186 | -------------------------------------------------------------------------------- /src/include/drivers/pic_8259/pic.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #ifndef __PIC_H__ 33 | #define __PIC_H__ 34 | 35 | #include 36 | 37 | #include 38 | 39 | #define PIC_EOI_MSG 0x20 40 | #define PIC_PRIMARY_PORT 0x20 41 | #define PIC_SECONDARY_PORT 0xA0 42 | 43 | /* programmamble interrupt controller buffering mode 44 | * 45 | * @member not_buffered_{p, s} -- not buffered mode for both primary and 46 | * secondary devices 47 | * @member buffered_secondary -- secondary interrupt controller is buffered 48 | * @member buffered_primary -- primary interrupt controller is buffered 49 | */ 50 | enum PIC_BUFFER_MODE { 51 | not_buffered_p = 0, 52 | not_buffered_s, 53 | buffered_secondary, 54 | buffered_primary 55 | }; 56 | 57 | /* programmamble interrupt controller end-of-interrupt modes 58 | * 59 | */ 60 | enum PIC_EOI_TYPE { 61 | non_specific_eoi = 1, 62 | no_operation, 63 | specific_eoi, 64 | rotate_in_auto_eoi, 65 | rotate_on_non_specific_eoi, 66 | set_priority, 67 | rotate_on_specific_eoi 68 | }; 69 | 70 | /* programmable interrupt controller initialisation command word 1 71 | * 72 | * @member icw4_needed -- 1 if icw4 is needed 73 | * @member cascading -- 0 if cascading, 1 if single 8259 74 | * @member iv_size -- 0 for 8-bit interrupt vectors, 1 for 4-bit 75 | * @member trigger_mode -- 0 for level, 1 for edge trigger 76 | * @member icw_1 -- always 1 77 | * @member pc_system -- always 0 78 | */ 79 | typedef struct __attribute__((packed)) { 80 | unsigned icw4_needed : 1; 81 | unsigned cascading : 1; 82 | unsigned iv_size : 1; 83 | unsigned trigger_mode : 1; 84 | unsigned icw_1 : 1; 85 | unsigned pc_system : 3; 86 | } pic_icw1; 87 | 88 | /* programmable interrupt controller initialisation command word 2 89 | * 90 | * @member unsigned int zero -- these 3 bits are always 0 for 80x86 & alike 91 | * @member unsigned int int_vector -- A7-A3 of interrupt vector for 80x86 92 | */ 93 | typedef struct __attribute__((packed)) { 94 | unsigned zero : 3; 95 | unsigned int_vector : 5; 96 | } pic_icw2; 97 | 98 | /* programmamble interrupt controller inititialisation command word 3 99 | * for primary interrupt controller. 100 | * 101 | * Each bit indicates that this interrupt has secondary device, 102 | * eg: 103 | * bit 1 is set => 2nd interrupt request has secondary device 104 | */ 105 | typedef struct { 106 | uint8_t device_map; 107 | } pic_icw3_primary; 108 | 109 | /* programmamble interrupt controller inititialisation command word 3 110 | * for secondary interrupt controller. 111 | * 112 | * @member primary_int -- primary interrupt request this device is attached to 113 | * @member zero -- always 0 114 | */ 115 | typedef struct __attribute__((packed)) { 116 | unsigned primary_int : 3; 117 | unsigned zero : 5; 118 | } pic_icw3_secondary; 119 | 120 | /* programmamble interrupt controller inititialisation command word 4 121 | * 122 | * @member mode -- 0 for 80x86, 1 for 80x85 (8086) 123 | * @member auto_eoi -- 1 for automatic end-of-interrupt, 0 for normal 124 | * @member buffered -- refer to enum PIC_BUFFER_MODE 125 | * @member sequential -- 0 for sequential, 1 for special fully nested mode 126 | * @member zero -- always 0 127 | */ 128 | typedef struct __attribute__((packed)) { 129 | unsigned mode : 1; 130 | unsigned auto_eoi : 1; 131 | enum PIC_BUFFER_MODE buffered : 2; 132 | unsigned sequential : 1; 133 | unsigned zero : 3; 134 | } pic_icw4; 135 | 136 | /* programmable interrupt controller operation word 2 for ports 21 and A1 137 | * 138 | * @member int_level -- interrupt request level to act upon 139 | * @member zero -- always 0 140 | * @member end_of_int_type -- refer to enum PIC_EOI_TYPE 141 | */ 142 | typedef struct __attribute__((packed)) { 143 | unsigned int_level : 3; 144 | unsigned zero : 2; 145 | enum PIC_EOI_TYPE type : 3; 146 | } pic_ocw2; 147 | 148 | /* programmable interrupt controller operation word 3 for ports 20 and A0 149 | * 150 | * @member next -- 1 for reading IRR, 0 for ISR 151 | * @member nop_b0 -- 1 to act if bit 0 is set, 0 to NOP 152 | * @member poll -- 1 if we've issued poll command 153 | * @member ident -- always 10 154 | * @member reset_mask -- Set to 0 to reset special mask, 1 to set it 155 | * @member nop_b5 -- 1 to act if bit 5 is set, 0 to NOP 156 | * @member zero -- always 0 157 | */ 158 | typedef struct __attribute__((packed)) { 159 | unsigned next : 1; 160 | unsigned nop_b0 : 1; 161 | unsigned poll : 1; 162 | unsigned ident : 2; 163 | unsigned reset_mask : 1; 164 | unsigned nop_b5 : 1; 165 | unsigned zero : 1; 166 | } pic_ocw3; 167 | 168 | typedef struct { 169 | pic_ocw2 *ocw2; 170 | pic_ocw3 *ocw3; 171 | pic_icw1 *icw1; 172 | pic_icw2 *icw2; 173 | pic_icw3_primary *icw3_primary; 174 | pic_icw3_secondary * icw3_secondary; 175 | pic_icw4 *icw4; 176 | } pic_full_configuration; 177 | 178 | /* Mask irq line 179 | * 180 | * @param uint8_t line -- line to mask 181 | */ 182 | void pic_mask_irq(uint8_t line); 183 | 184 | /* Unmask irq line 185 | * 186 | * @param uint8_t line -- line to mask 187 | */ 188 | void pic_unmask_irq(uint8_t line); 189 | 190 | /* Send end of interrupt message to the programmable interrupt controller. 191 | * 192 | * @param uint8_t irq -- number of interrupt we're dealing with 193 | */ 194 | void pic_send_eoi(uint8_t irq); 195 | 196 | /* Initialise the programmable interrupt controller. 197 | * 198 | * @param device *dev -- pointer to device structure for PIC 199 | * @return bool true on success or false on error. 200 | */ 201 | enum DEVICE_STATUS pic_initialize(device *dev); 202 | 203 | /* Read irq register from the programmable interrupt controller. 204 | * 205 | */ 206 | uint16_t pic_read_irq(pic_ocw3 *ocw); 207 | 208 | /* Get in-service register value (Which irqs are served) 209 | * 210 | * @return uint16_t isr in form of SECONDARY << 8 | PRIMARY 211 | */ 212 | uint16_t pic_read_isr(void); 213 | 214 | /* Get interrupt request register value (Which interrupts have been raised) 215 | * 216 | * @return uint16_t irr in form of SECONDARY << 8 | PRIMARY 217 | */ 218 | uint16_t pic_read_irr(void); 219 | 220 | #endif // __PIC_H__ 221 | -------------------------------------------------------------------------------- /src/include/drivers/pit/pit.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2025, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #ifndef __PIT_H__ 33 | #define __PIT_H__ 34 | 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | 41 | static const short pit_channel_0_port = 0x40; 42 | static const short pit_channel_1_port = 0x41; 43 | static const short pit_channel_2_port = 0x42; 44 | static const short pit_command_port = 0x43; 45 | 46 | /* Supported pit data modes: 47 | * 48 | * @member binary -- Use traditional binary values 49 | * @member bcd -- Use the silly binary decimal format 50 | * 51 | */ 52 | enum pit_binary_mode { 53 | binary, 54 | bcd 55 | }; 56 | 57 | /* Supported pit operating modes 58 | * 59 | * 0 0 0 = Mode 0 (interrupt on terminal count) 60 | * 0 0 1 = Mode 1 (hardware re-triggerable one-shot) 61 | * 0 1 0 = Mode 2 (rate generator) 62 | * 0 1 1 = Mode 3 (square wave generator) 63 | * 1 0 0 = Mode 4 (software triggered strobe) 64 | * 1 0 1 = Mode 5 (hardware triggered strobe) 65 | * 1 1 0 = Mode 2 (rate generator, same as 010b) 66 | * 1 1 1 = Mode 3 (square wave generator, same as 011b) 67 | * 68 | * @member int_on_terminal_count 69 | * @member hardware_retriggerable_single_shot 70 | * @member rate_generator 71 | * @member square_wave_generator 72 | * @member sw_triggered_strobe 73 | * @member hw_triggered_strobe 74 | * @member rate_generator_2 75 | * @member square_wave_generator_2 76 | * 77 | */ 78 | enum pit_operating_mode { 79 | int_on_terminal_count, 80 | hardware_retriggerable_single_shot, 81 | rate_generator, 82 | square_wave_generator, 83 | sw_triggered_strobe, 84 | hw_triggered_strobe, 85 | rate_generator_2, 86 | square_wave_generator_2 87 | }; 88 | 89 | /* Supported access modes 90 | * 91 | * @member latch_count_value -- Latch on count 92 | * @member lobyte_only -- Only read low 8-bit values from channel 93 | * @member hibyte_only -- Only read high 8-bit values from channel 94 | * @member lo_ and_hi_byte -- First read returns 8-bit low, 2nd 8-bit high value 95 | */ 96 | enum pit_access_mode { 97 | latch_count_value, 98 | lobyte_only, 99 | hibyte_only, 100 | lo_and_hi_byte 101 | }; 102 | 103 | /* channel mode for command 104 | * 105 | * @member channel_{0-n} -- We want to control channel 0, 1, or 2 106 | * @member read_back -- We want to read configuration of a given channel 107 | */ 108 | enum pit_channel_mode { 109 | channel_0, 110 | channel_1, 111 | channel_2, 112 | read_back 113 | }; 114 | 115 | /* Pit command format 116 | * 117 | * @member enum pit_binary_mode -- Refer matching enum 118 | * @member enum pit_operating_mode operating_mode -- Refer matching enum 119 | * @member enum pit_access_mode access_mode -- Refer matching enum 120 | * @member enum pit_channel_mode selected_channel -- Refer matching enum 121 | * 122 | */ 123 | typedef struct __attribute__((packed)) { 124 | enum pit_binary_mode binary_mode : 1; 125 | enum pit_operating_mode operating_mode : 3; 126 | enum pit_access_mode access_mode : 2; 127 | enum pit_channel_mode selected_channel : 2; 128 | } pit_command; 129 | 130 | /* Pit readback command format 131 | * 132 | * @member unsigned reserved_zero -- Always 0 133 | * @member bool readback_timer_channel_N_selected -- Toggle to select channel N 134 | * @member bool status_latching_enabled -- Toggle to enable status latching 135 | * @member bool count_latching_enabled -- Toggle to enable count latching 136 | * @member unsigned reserved_one -- Always one 137 | */ 138 | typedef struct __attribute__((packed)) { 139 | unsigned reserved_zero : 1; 140 | bool readback_timer_channel_0_selected : 1; 141 | bool readback_timer_channel_1_selected : 1; 142 | bool readback_timer_channel_2_selected : 1; 143 | bool status_latching_enabled : 1; 144 | bool count_latching_enabled : 1; 145 | unsigned reserved_one : 2; 146 | } pit_readback_command; 147 | 148 | /* Readback response format 149 | * 150 | * @member enum pit_binary_mode binary_mode 151 | * @member enum pit_operating_mode operating_mode 152 | * @member enum pit_access_mode access_mode 153 | * @member unsigned null_count_flags 154 | * @member unsigned output_pin_state 155 | */ 156 | typedef struct __attribute__((packed)) { 157 | enum pit_binary_mode binary_mode : 1; 158 | enum pit_operating_mode operating_mode : 3; 159 | enum pit_access_mode access_mode : 2; 160 | unsigned null_count_flags : 1; 161 | unsigned output_pin_state : 1; 162 | } pit_readback_status; 163 | 164 | /* Helper to write command byte for programmable interrupt controller. 165 | * 166 | * @param uint8_t cmd -- Command to write 167 | */ 168 | static inline void pit_write_command_raw(uint8_t cmd) { 169 | outb(cmd, pit_command_port); 170 | } 171 | 172 | /* Helper to write pit_command to programmable interrupt controller from 173 | * pit_command structure. 174 | * 175 | * @param pit_command *command -- Command to write 176 | */ 177 | static inline void pit_write_command(pit_command *cmd) { 178 | uint8_t *cmd_byte = (uint8_t *)cmd; 179 | pit_write_command_raw(*cmd_byte); 180 | } 181 | 182 | /* Read pit value from given channel 183 | * 184 | * @param unsigned short channel -- Channel to read from 185 | * @return uint16_t count 186 | */ 187 | static inline uint16_t pit_read_count(unsigned short channel) { 188 | pit_command cmd = {0}; 189 | pit_write_command(&cmd); 190 | 191 | return inw(channel); 192 | } 193 | 194 | /* Helper to write pit_readback_command to programmable interrupt controller from 195 | * pit_readback_command structure. 196 | * 197 | * @param pit_readback_command *command -- Command to write 198 | */ 199 | static inline void pit_write_readback_command(pit_readback_command *cmd) { 200 | uint8_t *cmd_byte = (uint8_t *)cmd; 201 | pit_write_command_raw(*cmd_byte); 202 | } 203 | 204 | /* Read pit status for a given channel 205 | * 206 | * @param uint8_t channel -- channel to read 207 | * @return uint8_t status of the channel 208 | */ 209 | uint8_t pit_get_channel_mode(uint8_t channel); 210 | 211 | /* Setup PIT with default init. 212 | * 213 | * @param device *dev -- Device info structure 214 | * @return bool true on success, false on error. 215 | */ 216 | enum DEVICE_STATUS pit_init(device *dev); 217 | 218 | #endif 219 | -------------------------------------------------------------------------------- /src/include/drivers/serial/serial.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | */ 33 | 34 | #ifndef __SERIAL_H__ 35 | #define __SERIAL_H__ 36 | 37 | #include 38 | #include 39 | 40 | #include 41 | 42 | #include 43 | #include 44 | 45 | #define SERIAL_DATA(x) (x) 46 | #define SERIAL_IE(x) (x + 1) 47 | #define SERIAL_FIFO_CTRL(x) (x + 2) 48 | #define SERIAL_LCR(x) (x + 3) 49 | #define SERIAL_MCR(x) (x + 4) 50 | #define SERIAL_LSR(x) (x + 5) 51 | #define SERIAL_MSR(x) (x + 6) 52 | #define SERIAL_SCRATCH(x) (x + 7) 53 | 54 | // Primary serial console port 55 | #define SERIAL_COM_PRIMARY 0x03F8 56 | // default baud rate divisor for 38400 brate 57 | #define COM_DEFAULT_BRD 0x0003 58 | // default line control value 59 | #define COM_DEFAULT_LINE_CTL 0x03 60 | 61 | /* Structure for interrupt identification values 62 | * 63 | */ 64 | typedef struct __attribute__((packed)) { 65 | unsigned int interrupt_pending : 1; 66 | unsigned int interrupt_state : 2; 67 | unsigned int timeout_int_pending : 1; 68 | unsigned int reserved : 2; 69 | unsigned int fifo_buffer_state : 2; 70 | } serial_int_id_register; 71 | 72 | /* Structure for serial/uart device related data 73 | * 74 | * @member unsigned short base_port -- which com-port is this 75 | * @member unsigned short baudrate_divisor -- divisor value for set baud rate 76 | * @member unsigned char line_control -- line control settings 77 | * @member unsigned char fifo_control -- fifo control settings 78 | */ 79 | typedef struct { 80 | unsigned short base_port; 81 | 82 | // baud rate, LCR, and other configuration values 83 | unsigned short baudrate_divisor; 84 | unsigned char line_control; 85 | unsigned char fifo_control; 86 | 87 | } serial_uart_device; 88 | 89 | /* Helper functions for serial devices */ 90 | 91 | /* Get serial line status 92 | * 93 | * @param unsigned short port -- port to read status from 94 | * @return unsigned char status 95 | */ 96 | static inline unsigned char serial_get_line_status(unsigned short port) { 97 | return inb(SERIAL_LSR(port)); 98 | } 99 | 100 | /* Disable interrupts for device 101 | * 102 | * @param unsigned short port -- Device from which to disable interrupts from 103 | */ 104 | static inline void serial_interrupts_disable(unsigned short port) { 105 | outb(SERIAL_IE(port), 0); 106 | } 107 | 108 | /* Enable interrupts for device 109 | * 110 | * @param unsigned short port -- Device from which to enable interrupts from 111 | */ 112 | static inline void serial_interrupts_enable(unsigned short port) { 113 | outb(SERIAL_IE(port), 0); 114 | } 115 | 116 | /* Get serial modem status 117 | * 118 | * @param unsigned short port -- port to read status from 119 | * @return unsigned char status 120 | */ 121 | static inline unsigned char serial_get_modem_status(unsigned short port) { 122 | return inb(SERIAL_MSR(port)); 123 | } 124 | 125 | /* Set Divisor Latch Access Bit 126 | * 127 | * @param unsigned short port -- on which device to set DLAB 128 | */ 129 | static inline void serial_dlab_set(unsigned short port) { 130 | outb(SERIAL_FIFO_CTRL(port), 0x80); 131 | } 132 | 133 | /* Clear Divisor Latch Access Bit 134 | * 135 | * @param unsigned short port -- on which device to clear DLAB 136 | */ 137 | static inline void serial_dlab_clear(unsigned short port) { 138 | unsigned char stat = inb(SERIAL_FIFO_CTRL(port)); 139 | stat &= ~(0x80); 140 | outb(SERIAL_FIFO_CTRL(port), stat); 141 | } 142 | 143 | /* Set baud rate for device 144 | * 145 | * @param unsigned short port -- device to set baudrate for 146 | * @param unsigned short brd -- baud rate divisor 147 | */ 148 | static inline void serial_set_baudrate(unsigned short port, unsigned short brd) { 149 | serial_dlab_set(port); 150 | outb(SERIAL_DATA(port), (unsigned char)(brd & 0x00FF)); 151 | outb(SERIAL_IE(port), (unsigned char)(brd >> 8)); 152 | serial_dlab_clear(port); 153 | } 154 | 155 | /* Set line control for device 156 | * 157 | * @param unsigned short port -- device to set lc for 158 | * @param unsigned char lcr -- line control value 159 | */ 160 | static inline void serial_set_linecontrol(unsigned short port, unsigned char lcr) { 161 | outb(SERIAL_LCR(port), lcr); 162 | } 163 | 164 | /* Check if we have faulty device. We'll do this by writing value 165 | * FA to scratch register, and then reading the value back. IF 166 | * it's changed we know we've faulty device connected. 167 | * 168 | * @param unsigned short port -- Device to test 169 | * @return non-zero if device is faulty 170 | */ 171 | static inline unsigned char serial_device_is_faulty(unsigned short port) { 172 | outb(0x1e, SERIAL_MCR(port)); 173 | outb(0xae, SERIAL_DATA(port)); 174 | return (inb(SERIAL_DATA(port)) != 0xae); 175 | } 176 | 177 | /* Poll for serial port until line is empty. 178 | * 179 | * @param unsigned short port -- Port to wait for 180 | * @return 0 when line is empty, or non-zero if timed out. 181 | */ 182 | unsigned char serial_wait_for_tx_empty(unsigned short port); 183 | 184 | /* Initialise a serial port for comms 185 | * 186 | * @param device *dev -- pointer to device structure 187 | * @return enum DEVICE_STATUS status 188 | */ 189 | enum DEVICE_STATUS serial_init_device(device *dev); 190 | 191 | /* Write a string over serial line 192 | * 193 | * @param unsigned short port -- Device to write to 194 | * @param const unsigned char *msg -- Absolute address to string to write 195 | * @param const size_t size -- size of message to print 196 | * @return amount of bytes transmitted 197 | */ 198 | size_t serial_tx(unsigned short port, const char *msg, size_t len); 199 | 200 | /* Receive a string over serial line 201 | * 202 | * @param unsigned short port -- Device to read from 203 | * @param unsigned char *dst -- Buffer to read to 204 | * @param const size_t size -- How many bytes to read 205 | * @return amount of bytes received 206 | */ 207 | size_t serial_rx(unsigned short port, char *dst, const size_t size); 208 | 209 | /* printf() over serial line 210 | * 211 | * @param unsigned short port -- Device to write to 212 | * @param const unsigned char *msg -- Absolute address to string to write 213 | * @param const size_t size -- size of message to print 214 | * @return amount of bytes transmitted 215 | */ 216 | int serprintf(const char *restrict format, ...); 217 | 218 | static inline void uart_print_info(device *dev) { 219 | serial_uart_device *sdev = dev->device_data; 220 | blogf("%s: %04x / %04x baud\n", dev->device_name, sdev->base_port, (115200 / sdev->baudrate_divisor)); 221 | } 222 | 223 | #endif // __SERIAL_H__ 224 | -------------------------------------------------------------------------------- /src/include/interrupts/asm_helpers.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #ifndef __ASM_INT_HELPERS__ 33 | #define __ASM_INT_HELPERS__ 34 | 35 | /* Helper macro for registering new interrupt handlers */ 36 | #define IVT_INT_HANDLER_ENTRY(handler_entry) \ 37 | cli \ 38 | push sp \ 39 | mov bp, sp \ 40 | mov sp, bpa_int_handler_cpu_state_end \ 41 | pusha \ 42 | mov sp, mem_ebda \ 43 | mov bx, handler_entry \ 44 | jmp interrupt_handler_init_runtime \ 45 | 46 | 47 | #endif // __ASM_INT_HELPERS__ 48 | -------------------------------------------------------------------------------- /src/include/interrupts/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef __INTERRUPTS_COMMON_H__ 34 | #define __INTERRUPTS_COMMON_H__ 35 | 36 | #define INTERRUPT_PRIMARY 1 37 | #define INTERRUPT_SECONDARY 0 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/include/interrupts/interrupts.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #ifndef __INTERRUPTS_H__ 33 | #define __INTERRUPTS_H__ 34 | 35 | /* Dummy/default interrupt handler */ 36 | void default_int_handler(void); 37 | 38 | #endif // __INTERRUPTS_H__ 39 | -------------------------------------------------------------------------------- /src/include/interrupts/ivt.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #ifndef __IVT_H__ 33 | #define __IVT_H__ 34 | 35 | #include 36 | #include 37 | 38 | /* Helper to register interrupt handler for a driver or other bit of 39 | * software that wants to listen to interrupts. 40 | * 41 | * Note, that preboot and boot-services must use different IVT entries, as 42 | * different segment value is needed. 43 | * 44 | * @param uint16_t segment -- what CS value should we have upon jump to handler 45 | * @param uint16_t offset -- where in that segment our handler is at? 46 | * @param uint16_t entry -- which interrupt are we handling 47 | */ 48 | static inline void register_int_handler(uint16_t segment, uint16_t offset, uint16_t entry) { 49 | uint16_t *ptr = (uint16_t *)((entry * 4)); 50 | ptr[0] = segment; 51 | ptr[1] = offset; 52 | } 53 | 54 | /* Helper to get currently registered interrupt handler at IVT 55 | * 56 | * @param uint32_t entry -- Which interrupt are we handling 57 | */ 58 | static inline uint32_t get_ivt_handler(uint16_t entry) { 59 | uint16_t *ptr = (uint16_t *)((entry * 4)); 60 | uint32_t ret; 61 | ret = ptr[0] << 16; 62 | ret |= ptr[1]; 63 | return ret; 64 | } 65 | 66 | 67 | #endif // __IVT_H__ 68 | -------------------------------------------------------------------------------- /src/include/itoa.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef __itoa_h__ 34 | #define __itoa_h__ 35 | 36 | /* Convert unsigned 64-bit integer to ascii characters 37 | * 38 | * @param unsigned long d -- number to parse 39 | * @param char *dst -- where to write our ascii to 40 | */ 41 | void itoa(unsigned long d, char *dst); 42 | 43 | /* Convert unsigned 64-bit integer to ascii characters 44 | * 45 | * @param unsigned long d -- number to parse 46 | * @param char *dst -- where to write our ascii to, We assume this to be 47 | * 9-byte memory buffer that's initialised to 0 48 | */ 49 | void itoah(unsigned long d, char *dst); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/include/mm/bitmap.h: -------------------------------------------------------------------------------- 1 | #ifndef _BITMAP_H_INCLUDED 2 | #define _BITMAP_H_INCLUDED 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | //! Type for a single entry in the array. 9 | typedef uint8_t* bitmap_t; 10 | 11 | //! Return the size of the bitmap in bytes for a given amount of entries 12 | static inline size_t bitmap_size(size_t num_entries) { 13 | return (num_entries + 7) / 8; 14 | } 15 | 16 | //! Return the index in the bitmap array for the given bitmap index 17 | static inline uint32_t bitmap_idx(uint32_t entry) { 18 | return entry / 8; 19 | } 20 | 21 | //! Return the bitmask for the given bitmap index 22 | static inline uint8_t bitmap_bit(uint32_t entry) { 23 | return 1 << (entry % 8); 24 | } 25 | 26 | //! Retrieve state of the given entry from bitmap 27 | static inline bool bitmap_get(bitmap_t bitmap, uint32_t entry) { 28 | return (bitmap[bitmap_idx(entry)] & bitmap_bit(entry)) != 0; 29 | } 30 | 31 | //! Set given entry in bitmap 32 | static inline void bitmap_set(bitmap_t bitmap, uint32_t entry) { 33 | bitmap[bitmap_idx(entry)] |= bitmap_bit(entry); 34 | } 35 | 36 | //! Unset given entry in bitmap 37 | static inline void bitmap_clear(bitmap_t bitmap, uint32_t entry) { 38 | bitmap[bitmap_idx(entry)] &= ~bitmap_bit(entry); 39 | } 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/include/mm/slab.h: -------------------------------------------------------------------------------- 1 | #ifndef _SLAB_H_INCLUDED 2 | #define _SLAB_H_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | // Type for indexing objects in a Slab region 10 | typedef uint16_t SlabIndexType; 11 | 12 | // Header of a Slab region 13 | typedef struct { 14 | // Size of objects in this region 15 | uint16_t allocation_size; 16 | 17 | // Number of objects in this region 18 | SlabIndexType num_entries; 19 | 20 | // Size of the bitmap in bytes 21 | uint32_t bitmap_size; 22 | } SlabHeader; 23 | 24 | /* 25 | * Initialize a new slab allocator at the given memory location. After initialization, 26 | * you can use mem_start as pointer to SlabHeader for more operations. 27 | * 28 | * @param mem_start Memory address where the slab allocator region begins 29 | * @param mem_end Memory address where the slab allocator region ends 30 | * @param allocation_size Size of single objects in this allocator 31 | */ 32 | void init_slab(uint32_t mem_start, uint32_t mem_end, size_t allocation_size); 33 | 34 | /* 35 | * Calculate the overhead of a given slab allocator. 36 | * 37 | * @param slab Pointer to SlabHeader to calculate overhead. 38 | * @returns Allocator overhead in bytes. 39 | */ 40 | static inline size_t slab_overhead(const SlabHeader* slab) { 41 | size_t overhead = sizeof(SlabHeader) + slab->bitmap_size; 42 | return overhead + (slab->allocation_size - (overhead % slab->allocation_size)); 43 | } 44 | 45 | /* 46 | * Calculate memory address for a given allocator and index 47 | * 48 | * @param slab Pointer to SlabHeader for calculation 49 | * @param idx Index of the object in the allocator 50 | * @returns Memory address of the object 51 | */ 52 | static inline uint32_t slab_mem(const SlabHeader* slab, const SlabIndexType idx) { 53 | return (idx * slab->allocation_size) + slab_overhead(slab) + (uint32_t)slab; 54 | } 55 | 56 | /* 57 | * Calculate index for a given memory address in a given allocator 58 | * 59 | * @param slab Pointer to SlabHeader for calculation 60 | * @param mem Memory address to calculate index 61 | * @returns Index of the given memory address in the allocator 62 | */ 63 | static inline SlabIndexType slab_index(const SlabHeader* slab, const uint32_t mem) { 64 | return (mem - slab_overhead(slab) - (uint32_t)slab) / slab->allocation_size; 65 | } 66 | 67 | /* 68 | * Allocate object from slab allocator region. 69 | * 70 | * @param slab mem_start given to init_slab before 71 | * @returns Address in memory with the allocated object, NULL if full 72 | */ 73 | static inline uint32_t slab_alloc(SlabHeader* slab) { 74 | bitmap_t bitmap = (bitmap_t)((uint32_t)slab + sizeof(SlabHeader)); 75 | 76 | SlabIndexType idx; 77 | for(idx = 0; idx < slab->num_entries && bitmap_get(bitmap, idx); ++idx); 78 | 79 | if(idx < slab->num_entries) { 80 | bitmap_set(bitmap, idx); 81 | return slab_mem(slab, idx); 82 | } 83 | return 0; 84 | } 85 | 86 | /* 87 | * Free object in slab allocator region. 88 | * 89 | * @param slab mem_start given to init_slab before 90 | * @param memory Address to mark as free 91 | */ 92 | static inline void slab_free(SlabHeader* slab, uint32_t mem) { 93 | bitmap_t bitmap = (bitmap_t)((uint32_t)slab + sizeof(SlabHeader)); 94 | bitmap_clear(bitmap, slab_index(slab, mem)); 95 | } 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /src/include/panic.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2025, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #ifndef __PANIC_H__ 33 | #define __PANIC_H__ 34 | 35 | #include 36 | #include 37 | 38 | #include 39 | 40 | void __attribute__((noreturn)) panic(const char *restrict msg, ...); 41 | #define panic_oom(...) panic("Out of memory while %s\n", __VA_ARGS__); 42 | 43 | #endif // __PANIC_H__ 44 | -------------------------------------------------------------------------------- /src/include/post.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2025, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #ifndef __TINYPOST_H__ 33 | #define __TINYPOST_H__ 34 | 35 | #include 36 | 37 | #include 38 | #include 39 | 40 | /* Initialize a output device, and make it our default 41 | * output device for blogf, panic, etc. 42 | * 43 | * @param device *dev -- Target device structure 44 | * @param device_init_function init_func -- Init function to use for the device 45 | * @param tx_func write_func -- Function to use for writing output to this device 46 | * @param char *name -- Name of our output device 47 | * @return bool true if switch succeeded 48 | */ 49 | bool switch_output_device(device *dev, device_init_function init_func, char *name); 50 | 51 | /* Perform power-on-self-test and bring up 52 | * systems we need early on, such as disk controllers etc. 53 | */ 54 | void post_and_init(void); 55 | 56 | 57 | 58 | #endif // __TINYPOST_H__ 59 | -------------------------------------------------------------------------------- /src/include/stdlib.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2025, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #ifndef __TINYSTDLIB_H__ 33 | #define __TINYSTDLIB_H__ 34 | 35 | #include 36 | #include 37 | 38 | #include 39 | 40 | typedef struct memory_header { 41 | bool free; 42 | uint64_t size; 43 | struct memory_header *previous; 44 | struct memory_header *next; 45 | } memory_header; 46 | 47 | typedef struct { 48 | uint64_t size; 49 | struct memory_header *start; 50 | } heap_start; 51 | 52 | void heap_init(uint64_t start, uint64_t size); 53 | void *malloc(uint64_t size); 54 | void *calloc(uint64_t nmemb, uint64_t size); 55 | void *realloc(void *ptr, uint64_t size); 56 | void free(void *ptr); 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/include/string.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #ifndef __STRING_H__ 33 | #define __STRING_H__ 34 | 35 | #include 36 | 37 | /* Get length of a null-terminated string 38 | * 39 | * @param const char *str -- string of which to count length for 40 | * @return size_t string length 41 | */ 42 | size_t strlen(const char *str); 43 | 44 | /* Compare two strings 45 | * 46 | * @param unsigned char *s1 -- String 1 47 | * @param unsigned char *s2 -- String 2 48 | * @param unsigned int n -- Only compare up to n bytes 49 | * @return amount of bytes that differ 50 | */ 51 | size_t strncmp(unsigned char *s1, unsigned char *s2, unsigned int n); 52 | 53 | /* Set memory range to specified byte 54 | * 55 | * @param const void *dst -- start address 56 | * @param unsigned char b -- what to set the memory to 57 | * @param size_t len -- how many bytes to write 58 | */ 59 | void memset(const void *dst, unsigned char c, size_t len); 60 | 61 | /* Copy len bytes of memory from region A to B 62 | * 63 | * @param const void *src -- where to copy from 64 | * @param const void *dst -- where to copy to 65 | * @param size_t len -- how many bytes to copy 66 | * @return pointer to dst 67 | */ 68 | void *memcpy(const void *src, void *dst, size_t len); 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/include/superio/superio.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | */ 33 | 34 | #ifndef __SUPERIO_H__ 35 | #define __SUPERIO_H__ 36 | 37 | void superio_init(void); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/include/sys/io.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #ifndef __SYS_IO_H__ 33 | #define __SYS_IO_H__ 34 | 35 | #include 36 | 37 | // i/o delay so that we don't have to implement it separately for 38 | // all pio devices. 39 | // 40 | // @param unsigned short time -- how many NOPs should we execute 41 | // 42 | // NOTE: This function should only be used for delays until the point 43 | // we have working sleep() / interrupts and programmamble interrupt timer 44 | // initialised. 45 | // 46 | static inline void iodelay(unsigned short time) { 47 | do { asm volatile("nop"); } while (time--); 48 | } 49 | 50 | // Very basic helpers to convert device data structures into 51 | // types we can work with when using {in,out}{b,w,l} 52 | // 53 | static inline uint8_t to_uint8_t(void *data) { 54 | return (uint8_t)(*((uint8_t *)data)); 55 | } 56 | 57 | static inline uint16_t to_uint16_t(void *data) { 58 | return (uint16_t)(*((uint16_t *)data)); 59 | } 60 | 61 | static inline uint32_t to_uint32_t(void *data) { 62 | return (uint32_t)(*((uint32_t *)data)); 63 | } 64 | 65 | // Basic cpu port i/o 66 | static inline unsigned char inb(unsigned short port) { 67 | unsigned char ret; 68 | asm volatile("in %0, %1":"=a"(ret):"dN"(port)); 69 | return ret; 70 | } 71 | 72 | static inline unsigned short inw(unsigned short port) { 73 | unsigned short ret; 74 | asm volatile("in %0, %1":"=a"(ret):"dN"(port)); 75 | return ret; 76 | } 77 | 78 | static inline unsigned int inl(unsigned short port) { 79 | unsigned int ret; 80 | asm volatile("in %0, %1":"=a"(ret):"dN"(port)); 81 | return ret; 82 | } 83 | 84 | static inline void outb(unsigned char v, unsigned short port) { 85 | asm volatile("out %1, %0"::"a"(v),"dN"(port)); 86 | } 87 | 88 | static inline void outw(unsigned short v, unsigned short port) { 89 | asm volatile("out %1, %0"::"a"(v),"dN"(port)); 90 | } 91 | 92 | static inline void outl(unsigned int v, unsigned short port) { 93 | asm volatile("out %1, %0"::"a"(v),"dN"(port)); 94 | } 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /src/interrupts/interrupts.S: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | .section .rom_text 34 | .global interrupt_handler_init_runtime 35 | .extern bda_int_handler_gdtr 36 | 37 | /* This function is used by all other interrupt handlers after they have 38 | * disabled interrupts, and stored cpu state to an appropriate location. 39 | * 40 | * We'll store GDTR, cr0, and segments here, but all other registers 41 | * should be saved by initial interrupt handler entry. 42 | * 43 | * @param bx -- offset to actual interrupt handler 44 | * Clobbers high half of ebx 45 | * 46 | * NOTE: This function is supposed to be Jumped to, not called. We'll 47 | * perform IRET at the end of our operations. 48 | */ 49 | .code16 50 | interrupt_handler_init_runtime: 51 | sgdt [bda_int_handler_gdtr] 52 | push cs 53 | push eax 54 | call switch_to_protected 55 | .code32 56 | pop eax 57 | push ds 58 | call switch_to_unreal 59 | and ebx, 0x0000FFFF 60 | or ebx, 0x000F0000 61 | call ebx 62 | pop ds 63 | lgdt [bda_int_handler_gdtr] 64 | iret 65 | 66 | -------------------------------------------------------------------------------- /src/interrupts/interrupts.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | /* Dummy/default interrupt handler. 39 | * 40 | */ 41 | void __attribute__((section(".rom_int_handler"))) default_int_handler(void) { 42 | uint16_t irr = pic_read_irr(); 43 | /* Handle interrupt here */ 44 | 45 | pic_send_eoi(irr); 46 | } 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/interrupts/ivt.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include 34 | #include 35 | 36 | #include 37 | 38 | #include 39 | 40 | /* Initialise interrupt vector table to only contain 41 | * dummy handlers that send EOI and return. 42 | * 43 | */ 44 | void init_ivt(void) { 45 | } 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/mainboards/qemu/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(tinybios PUBLIC 2 | ${CMAKE_CURRENT_SOURCE_DIR}/memory_init.S 3 | ${CMAKE_CURRENT_SOURCE_DIR}/superio/superio.c 4 | ) 5 | -------------------------------------------------------------------------------- /src/mainboards/qemu/memory_init.S: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2019, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | /* There's no need to perform memory initialisation on qemu but for 33 | * compability's sake let's have the entry and return here regardless. 34 | */ 35 | .code16 36 | .global main_memory_init 37 | .section .rom_text 38 | main_memory_init: 39 | ret 40 | 41 | -------------------------------------------------------------------------------- /src/mainboards/qemu/superio/superio.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | */ 33 | 34 | #include 35 | #include 36 | 37 | /* Initialise superio for us 38 | */ 39 | void superio_init(void) { 40 | outb(0x00, 0x03f8); 41 | outb(0x00, 0x03f8); 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/mm/malloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2025, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #ifndef __TINYMALLOC_H__ 33 | #define __TINYMALLOC_H__ 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | extern heap_start *heap; 40 | 41 | static inline memory_header *block_address(memory_header *block, uint64_t bytes_to_next) { 42 | return (memory_header *)((uint64_t)block + bytes_to_next); 43 | } 44 | 45 | static inline memory_header *block_from_ptr(void *ptr) { 46 | return (memory_header *)((uint64_t)ptr - sizeof(memory_header)); 47 | } 48 | 49 | static inline bool enough_space_for_extra_block(memory_header *block, uint64_t size) { 50 | if ((block->size - size) > (3 * sizeof(memory_header))) { 51 | return true; 52 | } 53 | return false; 54 | } 55 | 56 | void heap_init(uint64_t start, uint64_t size) { 57 | heap = (heap_start *)start; 58 | heap->size = size - sizeof(heap_start); 59 | heap->start = block_address((memory_header *)heap, sizeof(heap_start)); 60 | memset(heap->start, 0, heap->size); 61 | heap->start->free = true; 62 | heap->start->size = heap->size - sizeof(memory_header); 63 | } 64 | 65 | static memory_header *get_block(uint64_t size) { 66 | memory_header *current = heap->start; 67 | while ( 68 | (current->free == false) || 69 | (current->size < size) || 70 | (current->next != 0)) 71 | { 72 | current = current->next; 73 | } 74 | if (current->size >= size) { 75 | return current; 76 | } 77 | return 0; 78 | } 79 | 80 | 81 | static void create_new_block(memory_header *current, uint64_t size) { 82 | memory_header *next = block_address(current, size); 83 | next->size = current->size - size; 84 | next->free = true; 85 | next->previous = current; 86 | next->next = current->next; 87 | current->next = next; 88 | } 89 | 90 | static void allocate_block(memory_header *block, uint64_t size) { 91 | block->free = false; 92 | if (block->size == size) { 93 | return; 94 | } 95 | if (enough_space_for_extra_block(block, size)) { 96 | create_new_block(block, size); 97 | block->size = size; 98 | } 99 | } 100 | 101 | void *malloc(uint64_t size) { 102 | size += sizeof(memory_header); 103 | memory_header *block = get_block(size); 104 | if (block) { 105 | allocate_block(block, size); 106 | return (void *)((uint64_t)block + sizeof(memory_header)); 107 | } 108 | return 0; 109 | } 110 | 111 | void *calloc(uint64_t nmemb, uint64_t size) { 112 | void *ptr = malloc(nmemb * size); 113 | if (ptr) { 114 | memset(ptr, 0, nmemb * size); 115 | } 116 | return ptr; 117 | } 118 | 119 | static void merge_blocks(memory_header *a, memory_header *b, bool forward) { 120 | memory_header *back = (forward) ? a : b; 121 | memory_header *front = (back == a) ? b : a; 122 | 123 | back->size += front->size; 124 | back->next = front->next; 125 | 126 | } 127 | 128 | static void defragment_free(memory_header *block) { 129 | while ((block->next != 0) && (block->next->free)) { 130 | merge_blocks(block, block->next, true); 131 | } 132 | while ((block->previous) && (block != heap->start) && (block->previous->free)) { 133 | merge_blocks(block, block->previous, false); 134 | block = block->previous; 135 | } 136 | } 137 | 138 | void free(void *ptr) { 139 | memory_header *block = block_from_ptr(ptr); 140 | block->free = true; 141 | defragment_free(block); 142 | } 143 | 144 | void *realloc(void *ptr, uint64_t size) { 145 | size += sizeof(memory_header); 146 | void *ret = ptr; 147 | memory_header *block = block_from_ptr(ptr); 148 | 149 | if (size == block->size) { 150 | return ret; 151 | } 152 | 153 | if (block->size > size) { 154 | if (enough_space_for_extra_block(block, size)) { 155 | create_new_block(block, size); 156 | } 157 | block->size = size; 158 | return ret; 159 | } 160 | uint64_t size_diff = block->size - size; 161 | 162 | if (block->next->free && (block->next->size >= size_diff)) { 163 | if (block->next->next == 0) { 164 | panic("Last block!\n"); 165 | create_new_block(block, size); 166 | return ret; 167 | } 168 | if (enough_space_for_extra_block(block->next, size_diff)) { 169 | create_new_block(block->next, size_diff); 170 | } 171 | block->next = block->next->next; 172 | block->size += size_diff; 173 | return ret; 174 | } 175 | ret = calloc(1, size); 176 | if (ret) { 177 | memcpy(ptr, ret, (block->size - sizeof(memory_header))); 178 | free(ptr); 179 | } 180 | return ret; 181 | } 182 | 183 | #endif // __TINYMALLOC_H__ 184 | -------------------------------------------------------------------------------- /src/mm/slab.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | void init_slab(uint32_t mem_start, uint32_t mem_end, size_t allocation_size) { 10 | size_t mem_total = mem_end - mem_start; 11 | size_t num_entries = mem_total / allocation_size; 12 | size_t overhead = bitmap_size(num_entries) + sizeof(SlabHeader); 13 | 14 | num_entries -= (overhead + allocation_size) / allocation_size; 15 | 16 | SlabHeader* header = (SlabHeader*)mem_start; 17 | header->allocation_size = allocation_size; 18 | header->num_entries = num_entries; 19 | header->bitmap_size = bitmap_size(num_entries); 20 | 21 | bitmap_t bitmap = (bitmap_t)((uint32_t)header + sizeof(SlabHeader)); 22 | memset(bitmap, 0, header->bitmap_size); 23 | } 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/panic.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2025, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #include 33 | 34 | #include 35 | #include 36 | 37 | static inline void dump_print_register(char *name, uint64_t val) { 38 | int written = blogf("%s=%016x ", name, val); 39 | if (written <= 25) blog(" "); 40 | } 41 | 42 | #define get_reg(name) asm volatile("mov %0, " #name ";":"=r"(reg_for_dump)) 43 | #define dump(name) get_reg(name); dump_print_register(#name, reg_for_dump) 44 | #define dump_line(a, b, c, d) blog("\t"); dump(a); dump(b); dump(c); dump(d); blog("\n") 45 | 46 | #define dump_seg(name) reg_for_dump=read_##name(); dump_print_register(#name, reg_for_dump); 47 | #define dump_seg_line(a, b, c, d) blog("\t"); dump_seg(a); dump_seg(b); dump_seg(c); dump_seg(d); blog("\n") 48 | 49 | static inline void __attribute__((always_inline)) dump_registers() { 50 | blog("CPU State: \n"); 51 | uint64_t reg_for_dump; 52 | dump_line(rax, rbx, rcx, rdx); 53 | dump_line(rsi, rdi, rbp, rsp); 54 | dump_line(r8, r9, r10, r11); 55 | dump_line(r12, r13, r14, r15); 56 | dump_seg_line(cs, es, ds, ss); 57 | blog("\t"); 58 | dump(cr3); 59 | dump(cr4); 60 | blog("\n"); 61 | } 62 | 63 | static inline void __attribute__((always_inline)) dump_stack() { 64 | blog("STACK: \n"); 65 | uint64_t *rsp = (uint64_t *)get_gpr(rsp); 66 | blogf("\t%016x %016x %016x %016x\n\t%016x %016x %016x %016x\n", 67 | rsp[0], rsp[1], rsp[2], rsp[3], rsp[4], rsp[5], rsp[6], rsp[7]); 68 | 69 | blogf("\t%016x %016x %016x %016x\n\t%016x %016x %016x %016x\n", 70 | rsp[8], rsp[9], rsp[10], rsp[11], rsp[12], rsp[13], rsp[14], rsp[15]); 71 | } 72 | 73 | void __attribute__((noreturn)) panic(const char *restrict msg, ...) { 74 | blog("\n*** PANIC ***\nReason: "); 75 | va_list args; 76 | va_start(args, msg); 77 | vfblogf(msg, args); 78 | va_end(args); 79 | dump_registers(); 80 | dump_stack(); 81 | hang(); 82 | } 83 | 84 | -------------------------------------------------------------------------------- /src/post.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2025, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | 39 | #include 40 | 41 | #include 42 | #include 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | #include 52 | 53 | #include 54 | #include 55 | 56 | 57 | extern device *uart_dev; 58 | extern console_device default_console_device; 59 | extern device *keyboard_controller_device; 60 | extern device *programmable_interrupt_controller; 61 | extern device *programmable_interrupt_timer; 62 | extern device **pci_device_array; 63 | extern ata_ide **ata_ide_array; 64 | 65 | /* Initialize a output device, and make it our default 66 | * output device for blogf, panic, etc. 67 | * 68 | * @param device *dev -- Target device structure 69 | * @param device_init_function init_func -- Init function to use for the device 70 | * @param tx_func write_func -- Function to use for writing output to this device 71 | * @param char *name -- Name of our output device 72 | * @param 73 | * @return bool true if switch succeeded 74 | */ 75 | bool switch_output_device(device *dev, device_init_function init_func, tx_func write_func, char *name) { 76 | if (dev->status != status_initialised) { 77 | dev->status = init_func(dev); 78 | dev->device_name = name; 79 | if (dev->status != status_initialised) { 80 | blogf("Failed to switch to output device %s\n", name); 81 | } 82 | } 83 | default_console_device.enabled = true; 84 | default_console_device.dev = dev; 85 | default_console_device.tx_func = write_func; 86 | blogf("Switched default output device to %s\n", dev->device_name); 87 | return true; 88 | } 89 | 90 | 91 | 92 | void post_and_init(void) { 93 | uart_dev = new_device(sizeof(serial_uart_device)); 94 | switch_output_device(uart_dev, serial_init_device, serial_tx, "UART 1"); 95 | 96 | programmable_interrupt_controller = new_device(sizeof(pic_full_configuration)); 97 | keyboard_controller_device = new_device(sizeof(ps2_8042_status)); 98 | programmable_interrupt_timer = new_device(0); 99 | initialize_device(pic_initialize, programmable_interrupt_controller, "8259/PIC", false); 100 | initialize_device(kbdctl_set_default_init, keyboard_controller_device, "8042/PS2", false); 101 | initialize_device(pit_init, programmable_interrupt_timer, "825X/PIT", false); 102 | 103 | pci_device_array = calloc(32, sizeof(device **)); 104 | uint8_t devcnt = enumerate_pci_buses(pci_device_array); 105 | pci_print_devtree(pci_device_array, devcnt); 106 | ata_ide_array = calloc(1, sizeof(ata_ide **)); 107 | uint8_t ide_cnt = init_ata_controllers(pci_device_array, ata_ide_array, devcnt); 108 | } 109 | 110 | -------------------------------------------------------------------------------- /src/reset.S: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2019, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | */ 33 | 34 | .section .rom_text 35 | /* Entry at 0xF0000 */ 36 | 37 | .code16 38 | entry: 39 | cld 40 | cli 41 | 42 | // Bist result to ebp 43 | mov ebp, eax 44 | 45 | // Disable TLB 46 | xor eax, eax 47 | mov cr3, eax 48 | 49 | #include "cpu/cache.S" 50 | xor esi, esi 51 | xor edi, edi 52 | 53 | // We now have stack, store bist results there 54 | push ebp 55 | mov ebp, esp 56 | 57 | // Handle string segments 58 | // Handle main memory initialisation 59 | call main_memory_init 60 | 61 | // Move stack from cache to ram, and move bist results 62 | // as well 63 | pop ebp 64 | mov esp, 0x7c00 65 | push ebp 66 | 67 | // Disable MTRR subsystem for now, we don't really have a need 68 | // for it and I'd prefer to have the least amount possible running at 69 | // this point. The less things that can randomly break, the better. 70 | // 71 | mov ecx, MTRR_DEFTYPE_REG0 72 | rdmsr 73 | and eax, ~MTRR_ENABLE 74 | wrmsr 75 | 76 | // We've now got actual memory going on, time to switch runmodes 77 | // around so that we're not relying on segments / 20-bit addressing 78 | // 79 | call init_cpu 80 | 81 | mov ax, 0xDEAD 82 | .hang: 83 | cli 84 | hlt 85 | jmp .hang 86 | 87 | .section .reset 88 | /* Reset at 0xFFFF0 */ 89 | .global reset 90 | reset: 91 | cli 92 | jmp entry 93 | 94 | -------------------------------------------------------------------------------- /src/stdlib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(tinybios PUBLIC 2 | ${CMAKE_CURRENT_SOURCE_DIR}/string.c 3 | ${CMAKE_CURRENT_SOURCE_DIR}/itoa.c 4 | ) 5 | -------------------------------------------------------------------------------- /src/stdlib/itoa.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include 34 | 35 | /* Convert unsigned 32-bit longeger to ascii characters 36 | * 37 | * @param unsigned long d -- number to parse 38 | * @param char *dst -- where to write our ascii to 39 | */ 40 | void itoa(unsigned long d, char *dst) { 41 | unsigned long carry = 0; 42 | 43 | for (unsigned long i = 0; i < (2 * sizeof(unsigned long)); i++) { 44 | char nibble = (d & 0x0000000F); 45 | d >>= 4; 46 | if (carry) { 47 | nibble += carry; 48 | carry = 0; 49 | } 50 | if (nibble > 0x09) { 51 | carry = 1; 52 | nibble -= 0x0A; 53 | } 54 | nibble |= 0x30; 55 | dst[(2 * sizeof(unsigned long)) - i - 1] = nibble; 56 | } 57 | } 58 | 59 | /* Convert unsigned 32-bit longeger to ascii hex characters 60 | * 61 | * @param unsigned long d -- number to parse 62 | * @param char *dst -- where to write our ascii to, We assume this to be 63 | * at least 9-byte memory buffer that's initialised to 0 64 | */ 65 | void itoah(unsigned long d, char *dst) { 66 | char nibble; 67 | 68 | for (unsigned long i = 0; i < (2 * sizeof(unsigned long)); i++) { 69 | nibble = (d & 0x0000000F); 70 | d >>= 4; 71 | if (nibble < 10) { 72 | nibble |= 0x30; 73 | } else { 74 | nibble -= 0x0A; 75 | nibble += 0x41; 76 | } 77 | dst[(2*sizeof(long)) - i - 1] = nibble; 78 | } 79 | } 80 | 81 | 82 | -------------------------------------------------------------------------------- /src/stdlib/string.c: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2024, k4m1 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #include 34 | 35 | /* Get length of a null-terminated string 36 | * 37 | * @param const char *str -- string of which to count length for 38 | * @return size_t string length 39 | */ 40 | size_t strlen(const char *str) { 41 | size_t i = 0; 42 | while (str[i] != 0) { 43 | i++; 44 | } 45 | return i; 46 | } 47 | 48 | /* Compare two strings 49 | * 50 | * @param unsigned char *s1 -- String 1 51 | * @param unsigned char *s2 -- String 2 52 | * @param unsigned int n -- Only compare up to n bytes 53 | * @return amount of bytes that differ 54 | */ 55 | size_t strncmp(unsigned char *s1, unsigned char *s2, unsigned int n) { 56 | size_t ret = 0; 57 | for (unsigned int i = 0; i < n; i++) { 58 | if ((s1[i] == 0) || (s2[i] == 0)) { 59 | break; 60 | } 61 | if (s1[i] != s2[i]) { 62 | ret++; 63 | } 64 | } 65 | return ret; 66 | } 67 | 68 | void *memset(void *s, int c, size_t n) { 69 | unsigned char *dst = (unsigned char *)s; 70 | for (size_t i = 0; i < n; i++) { 71 | dst[i] = (unsigned char)c; 72 | } 73 | return dst; 74 | } 75 | 76 | /* Copy len bytes of memory from region A to B 77 | * 78 | * @param const void *src -- where to copy from 79 | * @param const void *dst -- where to copy to 80 | * @param size_t len -- how many bytes to copy 81 | */ 82 | void *memcpy(const void *src, void *dst, size_t len) { 83 | unsigned char *d = (unsigned char *)dst; 84 | unsigned char *s = (unsigned char *)src; 85 | for (size_t i = 0; i < len; i++) { 86 | d[i] = s[i]; 87 | } 88 | return d; 89 | } 90 | 91 | -------------------------------------------------------------------------------- /test_bootloader.asm: -------------------------------------------------------------------------------- 1 | bits 16 2 | org 0x7c00 3 | 4 | .start: 5 | times 128 db 0x90 6 | jmp .start 7 | hlt 8 | 9 | times 510-($-$$) db 0xFF 10 | dw 0xaa55 11 | 12 | -------------------------------------------------------------------------------- /test_disk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwk4m1/TinyBIOS/8bfd09f646db0313c2b00c8ee4e19215162d000a/test_disk --------------------------------------------------------------------------------