├── .gitignore ├── CMakeLists.txt ├── README ├── assets ├── default8x16.psfu ├── drdos8x14.psfu ├── system.8x16.psf └── test.bmp ├── bin ├── CMakeLists.txt └── test.c ├── doom └── CMakeLists.txt ├── dummy.c ├── kernel ├── CMakeLists.txt ├── arch │ └── x86 │ │ ├── mmu.c │ │ └── mmu.h ├── bmp.c ├── bmp.h ├── console.c ├── console.h ├── debug │ └── ubsan.c ├── descriptor_tables.c ├── descriptor_tables.h ├── div64.c ├── drivers │ ├── acpi.c │ ├── acpi.h │ ├── ata.c │ ├── ata.h │ ├── keyboard.c │ ├── keyboard.h │ ├── pci.c │ ├── pci.h │ ├── pci_registry.c │ ├── pci_registry.h │ ├── ports.c │ ├── ports.h │ ├── serial.c │ ├── serial.h │ ├── timer.c │ ├── timer.h │ ├── vga.c │ └── vga.h ├── dwarf.c ├── dwarf.h ├── elf.c ├── elf.h ├── fatfs │ ├── 00history.txt │ ├── 00readme.txt │ ├── diskio.c │ ├── diskio.h │ ├── ff.c │ ├── ff.h │ ├── ffconf.h │ ├── ffsystem.c │ ├── ffunicode.c │ └── integer.h ├── gdt.asm ├── interrupt.asm ├── isr.c ├── isr.h ├── kmalloc.c ├── kmalloc.h ├── main.c ├── multiboot.c ├── multiboot.h ├── psf.c ├── psf.h ├── shell.c ├── shell.h ├── stdio_impl.c └── tests │ ├── fatfs.c │ ├── pages.c │ ├── path.c │ ├── stdio.c │ ├── tests.h │ └── vector.c ├── libc ├── CMakeLists.txt ├── byteswap.h ├── common.h ├── ctype.c ├── ctype.h ├── errno.c ├── errno.h ├── float.h ├── limits.h ├── math.c ├── math.h ├── stdarg.h ├── stdbool.h ├── stddef.h ├── stdint.h ├── stdio.c ├── stdio.h ├── stdio │ ├── fprintf.c │ ├── printf.c │ ├── snprintf.c │ ├── sprintf.c │ ├── vfprintf.c │ ├── vprintf.c │ ├── vsnprintf.c │ └── vsprintf.c ├── string.c ├── string.h ├── vector.c ├── vector.h ├── wchar.c └── wchar.h ├── linker.ld ├── mkhd.sh ├── mkiso.sh └── multiboot.asm /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | *.a 3 | *.bin 4 | *.img 5 | CMakeCache.txt 6 | cmake_install.cmake 7 | CMakeFiles 8 | Makefile 9 | *.cbp 10 | .idea/ 11 | *.iso 12 | iso/ 13 | target/ 14 | build/ 15 | /*.png -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | set(CMAKE_VERBOSE_MAKEFILE on) 3 | set(CMAKE_SYSTEM_NAME "Generic" CACHE STRING "Target system.") 4 | 5 | if (CMAKE_HOST_APPLE AND CMAKE_C_LINK_FLAGS) 6 | string(REPLACE "-Wl,-search_paths_first" "" CMAKE_C_LINK_FLAGS ${CMAKE_C_LINK_FLAGS}) 7 | endif () 8 | 9 | # set(CMAKE_C_COMPILER clang) 10 | if (CMAKE_HOST_APPLE) 11 | set(CMAKE_C_COMPILER i386-elf-gcc) 12 | endif () 13 | 14 | set(CMAKE_ASM_NASM_OBJECT_FORMAT elf) 15 | enable_language(ASM_NASM) 16 | 17 | set(LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/linker.ld") 18 | set(CMAKE_C_FLAGS "-m32 -ffreestanding -fno-pie") 19 | # if clang: -Wno-error=unused-command-line-argument -nobuiltininc 20 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostdinc -fno-builtin -nostdlib -nodefaultlibs") 21 | set(CMAKE_EXE_LINKER_FLAGS "-Wl,-n -Wl,--build-id=none -Wl,-T${LINKER_SCRIPT}") 22 | 23 | add_executable(kernel.bin dummy.c multiboot.asm) 24 | target_link_libraries(kernel.bin kernel c) 25 | set_target_properties(kernel.bin PROPERTIES LINK_DEPENDS ${LINKER_SCRIPT}) 26 | 27 | add_subdirectory(kernel) 28 | add_subdirectory(libc) 29 | add_subdirectory(bin) -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | mkdir build && cd build 2 | cmake -DCMAKE_BUILD_TYPE=Debug .. 3 | cd .. 4 | make -C build 5 | 6 | # directly 7 | qemu-system-i386 -kernel kernel.bin 8 | 9 | # via Grub: 10 | # https://wiki.osdev.org/GRUB_2#Installing_GRUB_2_on_OS_X 11 | # brew install xorriso 12 | ./mkiso.sh kernel.bin 13 | qemu-system-i386 -cdrom os.iso 14 | 15 | # support exit 16 | -device isa-debug-exit,iobase=0xf4,iosize=0x04 17 | 18 | # remote gdb (port 1234): 19 | -s 20 | 21 | # stdio serial: 22 | -serial stdio 23 | 24 | # IDE drive: 25 | -drive file=hd.img,if=ide,format=raw 26 | 27 | # HAXM (macOS) 28 | -enable-hax 29 | 30 | # KVM (Linux) 31 | -enable-kvm 32 | 33 | # ----------------- 34 | # Full example: 35 | make -C build && ./mkiso.sh build/kernel.bin && ./mkhd.sh build && \ 36 | qemu-system-i386 -cdrom os.iso -serial stdio \ 37 | -device isa-debug-exit,iobase=0xf4,iosize=0x04 \ 38 | -drive file=hd.img,if=ide,format=raw -boot d 39 | -------------------------------------------------------------------------------- /assets/default8x16.psfu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/encounter/osdev/48d7c52fdbe8db63c17ad3264fa9d8c33c47af66/assets/default8x16.psfu -------------------------------------------------------------------------------- /assets/drdos8x14.psfu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/encounter/osdev/48d7c52fdbe8db63c17ad3264fa9d8c33c47af66/assets/drdos8x14.psfu -------------------------------------------------------------------------------- /assets/system.8x16.psf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/encounter/osdev/48d7c52fdbe8db63c17ad3264fa9d8c33c47af66/assets/system.8x16.psf -------------------------------------------------------------------------------- /assets/test.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/encounter/osdev/48d7c52fdbe8db63c17ad3264fa9d8c33c47af66/assets/test.bmp -------------------------------------------------------------------------------- /bin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project(bin) 3 | 4 | if (CMAKE_HOST_APPLE) 5 | set(CMAKE_C_COMPILER i386-elf-gcc) 6 | set(CMAKE_AR i386-elf-ar) 7 | set(CMAKE_RANLIB i386-elf-ranlib) 8 | endif () 9 | 10 | set(CMAKE_C_FLAGS "-m32 -std=c11 -fPIC -ffreestanding -fshort-enums -Wall -Werror") 11 | # if clang: -Wno-error=unused-command-line-argument -nobuiltininc 12 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostdinc -fno-builtin -nostdlib -nodefaultlibs") 13 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-stack-protector") # FIXME generates bad code using `mov eax, large gs:14h`? 14 | set(CMAKE_C_FLAGS_DEBUG "-gdwarf-4 -DENABLE_DWARF") 15 | #if (NOT CMAKE_HOST_APPLE) 16 | # set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fsanitize=undefined") 17 | #endif() 18 | set(CMAKE_C_FLAGS_RELEASE "-Os") 19 | set(CMAKE_EXE_LINKER_FLAGS "") 20 | 21 | include_directories(${CMAKE_SOURCE_DIR}/libc) 22 | add_executable(test test) -------------------------------------------------------------------------------- /bin/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int _start(int argc, char **argv) { 5 | return 5; // ((uintptr_t) strlen) + 256; 6 | } -------------------------------------------------------------------------------- /doom/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project(libc) 3 | 4 | set(CMAKE_ASM_NASM_OBJECT_FORMAT elf) 5 | enable_language(ASM_NASM) 6 | 7 | if (CMAKE_HOST_APPLE) 8 | set(CMAKE_C_COMPILER i386-elf-gcc) 9 | set(CMAKE_AR i386-elf-ar) 10 | set(CMAKE_RANLIB i386-elf-ranlib) 11 | endif () 12 | 13 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error") 14 | 15 | include_directories(${CMAKE_SOURCE_DIR}/libc) 16 | FILE(GLOB SOURCES *.c) 17 | FILE(GLOB HEADERS *.h) 18 | add_library(doom STATIC ${SOURCES} ${HEADERS}) -------------------------------------------------------------------------------- /dummy.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/encounter/osdev/48d7c52fdbe8db63c17ad3264fa9d8c33c47af66/dummy.c -------------------------------------------------------------------------------- /kernel/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project(kernel) 3 | 4 | set(CMAKE_ASM_NASM_OBJECT_FORMAT elf) 5 | enable_language(ASM_NASM) 6 | 7 | if (CMAKE_HOST_APPLE) 8 | set(CMAKE_C_COMPILER i386-elf-gcc) 9 | set(CMAKE_AR i386-elf-ar) 10 | set(CMAKE_RANLIB i386-elf-ranlib) 11 | endif() 12 | 13 | set(CMAKE_C_FLAGS "-m32 -std=c11 -ffreestanding -fno-pie -fshort-enums -Wall -Werror -Wno-error=unused-variable -Wno-error=attributes") 14 | # if clang: -Wno-error=unused-command-line-argument -nobuiltininc 15 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostdinc -fno-builtin -nostdlib -nodefaultlibs") 16 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-stack-protector") # FIXME generates bad code using `mov eax, large gs:14h`? 17 | set(CMAKE_C_FLAGS_DEBUG "-gdwarf-4 -DENABLE_DWARF") 18 | if (NOT CMAKE_HOST_APPLE) 19 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fsanitize=undefined") 20 | endif() 21 | set(CMAKE_C_FLAGS_RELEASE "-Os") 22 | 23 | include_directories(${CMAKE_SOURCE_DIR}/libc) 24 | set(SOURCE_FILES 25 | console 26 | descriptor_tables 27 | gdt.asm 28 | interrupt.asm 29 | isr 30 | main 31 | shell 32 | multiboot 33 | div64 34 | elf 35 | dwarf 36 | stdio_impl 37 | bmp 38 | psf 39 | kmalloc 40 | arch/x86/mmu 41 | drivers/ports 42 | drivers/timer 43 | drivers/keyboard 44 | drivers/acpi 45 | drivers/serial 46 | drivers/vga 47 | drivers/ata 48 | drivers/pci 49 | drivers/pci_registry 50 | # drivers/i825xx 51 | fatfs/diskio 52 | fatfs/ff 53 | fatfs/ffconf.h 54 | fatfs/ffsystem 55 | fatfs/ffunicode 56 | fatfs/integer.h 57 | tests/tests.h 58 | tests/vector 59 | tests/fatfs 60 | tests/stdio 61 | tests/path 62 | tests/pages) 63 | if (${CMAKE_BUILD_TYPE} MATCHES "Debug") 64 | set(SOURCE_FILES ${SOURCE_FILES} debug/ubsan) 65 | endif () 66 | add_library(kernel STATIC ${SOURCE_FILES}) -------------------------------------------------------------------------------- /kernel/arch/x86/mmu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define KERNEL_PAGE_OFFSET 0xC0000000 // FIXME make dynamic? 5 | 6 | void *load_page_table() { 7 | void *raw_ptr; 8 | __asm__ volatile("mov %%cr3, %0" : "=a"(raw_ptr)); 9 | return (uint32_t *) ((uintptr_t) raw_ptr + KERNEL_PAGE_OFFSET); 10 | } 11 | 12 | void page_table_set(uintptr_t address, uintptr_t page_addr, uint16_t flags) { 13 | uint32_t *page_table = load_page_table(); 14 | uint16_t i = (uint16_t) (page_addr >> 22); 15 | page_table[i] = (address & 0xFFC00000) | flags; 16 | __asm__ volatile("invlpg %0" : : "m"(i)); 17 | } 18 | 19 | void *phys_to_virt(void *ptr) { 20 | if ((uintptr_t) ptr > KERNEL_PAGE_OFFSET) return ptr; 21 | return (void *) ((uintptr_t) ptr + KERNEL_PAGE_OFFSET); 22 | } 23 | 24 | void *virt_to_phys(void *ptr) { 25 | if ((uintptr_t) ptr < KERNEL_PAGE_OFFSET) return ptr; 26 | return (void *) ((uintptr_t) ptr - KERNEL_PAGE_OFFSET); 27 | } -------------------------------------------------------------------------------- /kernel/arch/x86/mmu.h: -------------------------------------------------------------------------------- 1 | // 2 | // Paging flags for Page-Tables and Page-Directories. 3 | // 4 | #define X86_PAGE_PRESENT (1<<0) // set if page or page-table is present 5 | #define X86_PAGE_WRITE (1<<1) // set to allow writing to the page or page-table 6 | #define X86_PAGE_USER (1<<2) // set to make the page or page-table a user page or page-table 7 | // if this flag is cleared the page or page-table can only be accessed in supervisor mode 8 | #define X86_PAGE_PWT (1<<3) // when the PWT flag is set, write-through caching is enabled for the 9 | // page or page-table; when the flag is clear, write-back caching is 10 | // enabled for the page or page-table. 11 | // This type of caching is useful for VGA framebuffers. 12 | #define X86_PAGE_PCD (1<<4) // Page Cache Disable, set this flag to disable caching of the page or page-table 13 | #define X86_PAGE_ACCESSED (1<<5) // the processor sets this flag the first time the page or page table is accessed 14 | #define X86_PAGE_DIRTY (1<<6) // the processor sets this flag the first time a page is accessed for a write operation 15 | // this flag is only used in page-table entries and should not be set for page-directory entries 16 | #define X86_PAGE_PAGESIZE (1<<7) // page size extension flag. (Set for enable) 17 | #define X86_PAGE_GLOBAL (1<<8) // this flag is only used in page-table entries 18 | // when a page is marked global and the page global enable (PGE) flag in register 19 | // CR4 is set, the page-table or page-directory entry for the page is not invalidated 20 | // in the TLB when register CR3 is loaded 21 | #define X86_PAGE_AVAIL1 (1<<9) // Available for usage by the Kernel 22 | #define X86_PAGE_AVAIL2 (1<<10) // Available for usage by the Kernel 23 | #define X86_PAGE_AVAIL3 (1<<11) // Available for usage by the Kernel 24 | 25 | void *phys_to_virt(void *ptr); 26 | 27 | void *virt_to_phys(void *ptr); 28 | 29 | void page_table_set(uintptr_t address, uintptr_t page_addr, uint16_t flags); -------------------------------------------------------------------------------- /kernel/bmp.c: -------------------------------------------------------------------------------- 1 | #include "bmp.h" 2 | #include "kmalloc.h" 3 | 4 | #include 5 | #include 6 | 7 | uint8_t *bmp_read_image(const char *filename, bmp_info_header_t *bmp_info_header) { 8 | FILE *bmp_file; 9 | bmp_file_header_t header; 10 | uint8_t *img_data; 11 | 12 | bmp_file = fopen(filename, "r"); 13 | if (ferror(bmp_file)) 14 | return NULL; 15 | 16 | fread(&header, sizeof(bmp_file_header_t), 1, bmp_file); 17 | if (ferror(bmp_file) || header.type != 0x4D42) { 18 | fclose(bmp_file); 19 | return NULL; 20 | } 21 | 22 | fread(bmp_info_header, sizeof(bmp_info_header_t), 1, bmp_file); 23 | fseek(bmp_file, header.img_data_offset, SEEK_SET); 24 | 25 | img_data = kmalloc(bmp_info_header->img_data_size); 26 | if (img_data == NULL) { 27 | errno = ENOMEM; 28 | kfree(img_data); 29 | fclose(bmp_file); 30 | return NULL; 31 | } 32 | 33 | fread(img_data, bmp_info_header->img_data_size, 1, bmp_file); 34 | if (ferror(bmp_file)) { 35 | fclose(bmp_file); 36 | return NULL; 37 | } 38 | 39 | fclose(bmp_file); 40 | return img_data; 41 | } 42 | -------------------------------------------------------------------------------- /kernel/bmp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | typedef struct _packed bmp_file_header { 6 | uint16_t type; //specifies the file type 7 | uint32_t size; //specifies the size in bytes of the bitmap file 8 | uint32_t reserved; 9 | uint32_t img_data_offset; //species the offset in bytes from the bitmapfileheader to the bitmap bits 10 | } bmp_file_header_t; 11 | 12 | typedef struct _packed bmp_info_header { 13 | uint32_t header_size; //specifies the number of bytes required by the struct 14 | uint32_t width; //specifies width in pixels 15 | uint32_t height; //species height in pixels 16 | uint16_t planes; //specifies the number of color planes, must be 1 17 | uint16_t bit_count; //specifies the number of bit per pixel 18 | uint32_t compression;//spcifies the type of compression 19 | uint32_t img_data_size; //size of image in bytes 20 | uint32_t x_per_meter; //number of pixels per meter in x axis 21 | uint32_t y_per_meter; //number of pixels per meter in y axis 22 | uint32_t num_colors_used; //number of colors used by th ebitmap 23 | uint32_t num_colors_important; //number of colors that are important 24 | } bmp_info_header_t; 25 | 26 | uint8_t *bmp_read_image(const char *filename, bmp_info_header_t *bmp_info_header); -------------------------------------------------------------------------------- /kernel/console.c: -------------------------------------------------------------------------------- 1 | #include "console.h" 2 | #include "drivers/vga.h" 3 | #include "drivers/serial.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | static bool vga_enabled = false; 10 | static bool serial_enabled = false; 11 | 12 | bool console_vga_enabled() { 13 | return vga_enabled; 14 | } 15 | 16 | void console_set_vga_enabled(bool enabled) { 17 | vga_enabled = enabled; 18 | } 19 | 20 | bool console_serial_enabled() { 21 | return serial_enabled; 22 | } 23 | 24 | void console_set_serial_enabled(bool enabled) { 25 | serial_enabled = enabled; 26 | } 27 | 28 | /** 29 | * Print a message on the specified location 30 | * If col, row, are negative, we will use the current offset 31 | */ 32 | static void knprint(const char *str, size_t len, uint8_t vga_color) { 33 | if (vga_enabled) { 34 | int offset = -1; 35 | for (size_t i = 0; i < len; ++i) { 36 | offset = vga_print_char(str[i], offset, vga_color); 37 | } 38 | } 39 | 40 | if (serial_enabled) { 41 | for (size_t i = 0; i < len; ++i) { 42 | serial_write(str[i]); 43 | } 44 | } 45 | } 46 | 47 | void clear_screen() { 48 | if (vga_enabled) { 49 | vga_clear_screen(); 50 | } 51 | } 52 | 53 | _noreturn 54 | void panic(char *str, ...) { 55 | vga_enabled = false; 56 | 57 | va_list args; 58 | va_start(args, str); 59 | if (str != NULL) vfprintf(stderr, str, args); 60 | va_end(args); 61 | fflush(stderr); 62 | 63 | // Spin lock 64 | __asm__("cli"); 65 | while (1) __asm__("hlt"); 66 | } 67 | 68 | #if UINT32_MAX == UINTPTR_MAX 69 | #define STACK_CHK_GUARD 0xe2dee396 70 | #else 71 | #define STACK_CHK_GUARD 0x595e9fbd94fda766 72 | #endif 73 | 74 | _unused 75 | uintptr_t __stack_chk_guard = STACK_CHK_GUARD; 76 | 77 | _noreturn _unused 78 | void __stack_chk_fail() { 79 | panic("Stack smashing detected"); 80 | } 81 | 82 | // --- stdio 83 | 84 | int errno; 85 | 86 | size_t __stdout_write(FILE *f, const char *str, size_t len) { 87 | size_t rem = f->wpos - f->wbase; 88 | if (rem) knprint(f->wbase, rem, WHITE_ON_BLACK); 89 | if (len) knprint(str, len, WHITE_ON_BLACK); 90 | 91 | f->wend = f->buf + f->buf_size; 92 | f->wpos = f->wbase = f->buf; 93 | return len; 94 | } 95 | 96 | size_t __stderr_write(FILE *f, const char *str, size_t len) { 97 | size_t rem = f->wpos - f->wbase; 98 | if (rem) knprint(f->wbase, rem, RED_ON_BLACK); 99 | if (len) knprint(str, len, RED_ON_BLACK); 100 | 101 | f->wend = f->buf + f->buf_size; 102 | f->wpos = f->wbase = f->buf; 103 | return len; 104 | } 105 | 106 | size_t __serial_write(FILE *f, const char *str, size_t len) { 107 | size_t rem = f->wpos - f->wbase; 108 | for (size_t i = 0; i < rem; i++) { 109 | serial_write(f->wbase[i]); 110 | } 111 | for (size_t i = 0; i < len; i++) { 112 | serial_write(str[i]); 113 | } 114 | 115 | f->wend = f->buf + f->buf_size; 116 | f->wpos = f->wbase = f->buf; 117 | return len; 118 | } 119 | 120 | off_t __stdio_seek(FILE *file, const off_t offset, int origin) { 121 | return 0; // TODO 122 | } 123 | 124 | int __stdio_close(FILE *file) { 125 | return 0; // TODO 126 | } 127 | 128 | static char __stdout_buf[BUFSIZ + UNGET]; 129 | FILE *stdout = &(FILE) { 130 | .buf = __stdout_buf + UNGET, 131 | .buf_size = BUFSIZ, 132 | .fd = 1, 133 | .flags = F_PERM | F_NORD, 134 | .lbf = '\n', 135 | .write = __stdout_write, 136 | .seek = __stdio_seek, 137 | .close = __stdio_close, 138 | .lock = -1, 139 | }; 140 | 141 | static char __stderr_buf[BUFSIZ + UNGET]; 142 | FILE *stderr = &(FILE) { 143 | .buf = __stderr_buf + UNGET, 144 | .buf_size = BUFSIZ, 145 | .fd = 1, 146 | .flags = F_PERM | F_NORD, 147 | .lbf = '\n', 148 | .write = __stderr_write, 149 | .seek = __stdio_seek, 150 | .close = __stdio_close, 151 | .lock = -1, 152 | }; 153 | 154 | static char __serial_buf[BUFSIZ + UNGET]; 155 | FILE *serial = &(FILE) { 156 | .buf = __serial_buf + UNGET, 157 | .buf_size = BUFSIZ, 158 | .fd = 1, 159 | .flags = F_PERM | F_NORD, 160 | .lbf = '\n', 161 | .write = __serial_write, 162 | .seek = __stdio_seek, 163 | .close = __stdio_close, 164 | .lock = -1, 165 | }; -------------------------------------------------------------------------------- /kernel/console.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | bool console_vga_enabled(); 7 | void console_set_vga_enabled(bool enabled); 8 | 9 | bool console_serial_enabled(); 10 | void console_set_serial_enabled(bool enabled); 11 | 12 | void clear_screen(); 13 | 14 | _noreturn 15 | void panic(char *str, ...); 16 | 17 | extern FILE *serial; -------------------------------------------------------------------------------- /kernel/descriptor_tables.c: -------------------------------------------------------------------------------- 1 | #include "descriptor_tables.h" 2 | #include "drivers/ports.h" 3 | #include "isr.h" 4 | 5 | extern void gdt_flush(gdt_ptr_t *gdt_ptr); 6 | 7 | static void init_gdt(); 8 | 9 | static void gdt_set_gate(int32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran); 10 | 11 | extern void idt_flush(idt_ptr_t *idt_ptr); 12 | 13 | static void init_idt(); 14 | 15 | static void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags); 16 | 17 | gdt_entry_t gdt_entries[5] = {}; 18 | gdt_ptr_t gdt_ptr; 19 | idt_entry_t idt_entries[256] = {}; 20 | idt_ptr_t idt_ptr; 21 | 22 | extern isr_t interrupt_handlers[]; 23 | 24 | // Initialisation routine - zeroes all the interrupt service routines, 25 | // initialises the GDT and IDT. 26 | _unused 27 | void init_descriptor_tables() { 28 | init_gdt(); 29 | init_idt(); 30 | } 31 | 32 | static void init_gdt() { 33 | gdt_ptr.limit = sizeof(gdt_entries) - 1; 34 | gdt_ptr.base = (uint32_t) &gdt_entries; 35 | 36 | gdt_set_gate(0, 0, 0, 0, 0); // Null segment 37 | gdt_set_gate(1, 0, 0xFFFFFFFF, 0b10011010, 0b11001111); // Code segment 38 | gdt_set_gate(2, 0, 0xFFFFFFFF, 0b10010010, 0b11001111); // Data segment 39 | gdt_set_gate(3, 0, 0xFFFFFFFF, 0b11111010, 0b11001111); // User mode code segment 40 | gdt_set_gate(4, 0, 0xFFFFFFFF, 0b11110010, 0b11001111); // User mode data segment 41 | 42 | gdt_flush(&gdt_ptr); 43 | } 44 | 45 | // Set the value of one GDT entry. 46 | static void gdt_set_gate(int32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) { 47 | gdt_entries[num].base_low = (uint16_t) (base & 0xFFFF); 48 | gdt_entries[num].base_middle = (uint8_t) (base >> 16 & 0xFF); 49 | gdt_entries[num].base_high = (uint8_t) (base >> 24 & 0xFF); 50 | 51 | gdt_entries[num].limit_low = (uint16_t) (limit & 0xFFFF); 52 | gdt_entries[num].granularity = (uint8_t) (limit >> 16 & 0x0F); 53 | 54 | gdt_entries[num].granularity |= gran & 0xF0; 55 | gdt_entries[num].access = access; 56 | } 57 | 58 | static void init_idt() { 59 | idt_ptr.limit = sizeof(idt_entries) - 1; 60 | idt_ptr.base = (uint32_t) &idt_entries; 61 | 62 | // Remap the irq table. 63 | port_byte_out(0x20, 0x11); 64 | port_byte_out(0xA0, 0x11); 65 | port_byte_out(0x21, 0x20); 66 | port_byte_out(0xA1, 0x28); 67 | port_byte_out(0x21, 0x04); 68 | port_byte_out(0xA1, 0x02); 69 | port_byte_out(0x21, 0x01); 70 | port_byte_out(0xA1, 0x01); 71 | port_byte_out(0x21, 0x0); 72 | port_byte_out(0xA1, 0x0); 73 | 74 | idt_set_gate(0, (uint32_t) isr0, 0x08, 0x8E); 75 | idt_set_gate(1, (uint32_t) isr1, 0x08, 0x8E); 76 | idt_set_gate(2, (uint32_t) isr2, 0x08, 0x8E); 77 | idt_set_gate(3, (uint32_t) isr3, 0x08, 0x8E); 78 | idt_set_gate(4, (uint32_t) isr4, 0x08, 0x8E); 79 | idt_set_gate(5, (uint32_t) isr5, 0x08, 0x8E); 80 | idt_set_gate(6, (uint32_t) isr6, 0x08, 0x8E); 81 | idt_set_gate(7, (uint32_t) isr7, 0x08, 0x8E); 82 | idt_set_gate(8, (uint32_t) isr8, 0x08, 0x8E); 83 | idt_set_gate(9, (uint32_t) isr9, 0x08, 0x8E); 84 | idt_set_gate(10, (uint32_t) isr10, 0x08, 0x8E); 85 | idt_set_gate(11, (uint32_t) isr11, 0x08, 0x8E); 86 | idt_set_gate(12, (uint32_t) isr12, 0x08, 0x8E); 87 | idt_set_gate(13, (uint32_t) isr13, 0x08, 0x8E); 88 | idt_set_gate(14, (uint32_t) isr14, 0x08, 0x8E); 89 | idt_set_gate(15, (uint32_t) isr15, 0x08, 0x8E); 90 | idt_set_gate(16, (uint32_t) isr16, 0x08, 0x8E); 91 | idt_set_gate(17, (uint32_t) isr17, 0x08, 0x8E); 92 | idt_set_gate(18, (uint32_t) isr18, 0x08, 0x8E); 93 | idt_set_gate(19, (uint32_t) isr19, 0x08, 0x8E); 94 | idt_set_gate(20, (uint32_t) isr20, 0x08, 0x8E); 95 | idt_set_gate(21, (uint32_t) isr21, 0x08, 0x8E); 96 | idt_set_gate(22, (uint32_t) isr22, 0x08, 0x8E); 97 | idt_set_gate(23, (uint32_t) isr23, 0x08, 0x8E); 98 | idt_set_gate(24, (uint32_t) isr24, 0x08, 0x8E); 99 | idt_set_gate(25, (uint32_t) isr25, 0x08, 0x8E); 100 | idt_set_gate(26, (uint32_t) isr26, 0x08, 0x8E); 101 | idt_set_gate(27, (uint32_t) isr27, 0x08, 0x8E); 102 | idt_set_gate(28, (uint32_t) isr28, 0x08, 0x8E); 103 | idt_set_gate(29, (uint32_t) isr29, 0x08, 0x8E); 104 | idt_set_gate(30, (uint32_t) isr30, 0x08, 0x8E); 105 | idt_set_gate(31, (uint32_t) isr31, 0x08, 0x8E); 106 | 107 | idt_set_gate(IRQ0, (uint32_t) irq0, 0x08, 0x8E); 108 | idt_set_gate(IRQ1, (uint32_t) irq1, 0x08, 0x8E); 109 | idt_set_gate(IRQ2, (uint32_t) irq2, 0x08, 0x8E); 110 | idt_set_gate(IRQ3, (uint32_t) irq3, 0x08, 0x8E); 111 | idt_set_gate(IRQ4, (uint32_t) irq4, 0x08, 0x8E); 112 | idt_set_gate(IRQ5, (uint32_t) irq5, 0x08, 0x8E); 113 | idt_set_gate(IRQ6, (uint32_t) irq6, 0x08, 0x8E); 114 | idt_set_gate(IRQ7, (uint32_t) irq7, 0x08, 0x8E); 115 | idt_set_gate(IRQ8, (uint32_t) irq8, 0x08, 0x8E); 116 | idt_set_gate(IRQ9, (uint32_t) irq9, 0x08, 0x8E); 117 | idt_set_gate(IRQ10, (uint32_t) irq10, 0x08, 0x8E); 118 | idt_set_gate(IRQ11, (uint32_t) irq11, 0x08, 0x8E); 119 | idt_set_gate(IRQ12, (uint32_t) irq12, 0x08, 0x8E); 120 | idt_set_gate(IRQ13, (uint32_t) irq13, 0x08, 0x8E); 121 | idt_set_gate(IRQ14, (uint32_t) irq14, 0x08, 0x8E); 122 | idt_set_gate(IRQ15, (uint32_t) irq15, 0x08, 0x8E); 123 | 124 | idt_flush(&idt_ptr); 125 | } 126 | 127 | 128 | static void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) { 129 | idt_entries[num].base_lo = (uint16_t) (base & 0xFFFF); 130 | idt_entries[num].base_hi = (uint16_t) (base >> 16 & 0xFFFF); 131 | 132 | idt_entries[num].sel = sel; 133 | idt_entries[num].always0 = 0; 134 | // We must uncomment the OR below when we get to using user-mode. 135 | // It sets the interrupt gate's privilege level to 3. 136 | idt_entries[num].flags = flags /* | 0x60 */; 137 | } -------------------------------------------------------------------------------- /kernel/descriptor_tables.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void init_descriptor_tables(); 6 | 7 | // This structure contains the value of one GDT entry. 8 | // We use the attribute 'packed' to tell GCC not to change 9 | // any of the alignment in the structure. 10 | struct gdt_entry { 11 | uint16_t limit_low; // The lower 16 bits of the limit. 12 | uint16_t base_low; // The lower 16 bits of the base. 13 | uint8_t base_middle; // The next 8 bits of the base. 14 | uint8_t access; // Access flags, determine what ring this segment can be used in. 15 | uint8_t granularity; 16 | uint8_t base_high; // The last 8 bits of the base. 17 | } _packed; 18 | 19 | typedef struct gdt_entry gdt_entry_t; 20 | 21 | static_assert(sizeof(gdt_entry_t) == 8, "gdt_entry incorrect size"); 22 | 23 | struct gdt_ptr { 24 | uint16_t limit; // The upper 16 bits of all selector limits. 25 | uint32_t base; // The address of the first gdt_entry_t struct. 26 | } _packed; 27 | 28 | typedef struct gdt_ptr gdt_ptr_t; 29 | 30 | // A struct describing an interrupt gate. 31 | struct idt_entry 32 | { 33 | uint16_t base_lo; // The lower 16 bits of the address to jump to when this interrupt fires. 34 | uint16_t sel; // Kernel segment selector. 35 | uint8_t always0; // This must always be zero. 36 | uint8_t flags; // More flags. See documentation. 37 | uint16_t base_hi; // The upper 16 bits of the address to jump to. 38 | } _packed; 39 | typedef struct idt_entry idt_entry_t; 40 | 41 | static_assert(sizeof(idt_entry_t) == 8, "idt_entry incorrect size"); 42 | 43 | // A struct describing a pointer to an array of interrupt handlers. 44 | // This is in a format suitable for giving to 'lidt'. 45 | struct idt_ptr 46 | { 47 | uint16_t limit; 48 | uint32_t base; // The address of the first element in our idt_entry_t array. 49 | } _packed; 50 | typedef struct idt_ptr idt_ptr_t; 51 | 52 | // These extern directives let us access the addresses of our ASM ISR handlers. 53 | extern void isr0 (); 54 | extern void isr1 (); 55 | extern void isr2 (); 56 | extern void isr3 (); 57 | extern void isr4 (); 58 | extern void isr5 (); 59 | extern void isr6 (); 60 | extern void isr7 (); 61 | extern void isr8 (); 62 | extern void isr9 (); 63 | extern void isr10(); 64 | extern void isr11(); 65 | extern void isr12(); 66 | extern void isr13(); 67 | extern void isr14(); 68 | extern void isr15(); 69 | extern void isr16(); 70 | extern void isr17(); 71 | extern void isr18(); 72 | extern void isr19(); 73 | extern void isr20(); 74 | extern void isr21(); 75 | extern void isr22(); 76 | extern void isr23(); 77 | extern void isr24(); 78 | extern void isr25(); 79 | extern void isr26(); 80 | extern void isr27(); 81 | extern void isr28(); 82 | extern void isr29(); 83 | extern void isr30(); 84 | extern void isr31(); 85 | 86 | extern void irq0 (); 87 | extern void irq1 (); 88 | extern void irq2 (); 89 | extern void irq3 (); 90 | extern void irq4 (); 91 | extern void irq5 (); 92 | extern void irq6 (); 93 | extern void irq7 (); 94 | extern void irq8 (); 95 | extern void irq9 (); 96 | extern void irq10(); 97 | extern void irq11(); 98 | extern void irq12(); 99 | extern void irq13(); 100 | extern void irq14(); 101 | extern void irq15(); -------------------------------------------------------------------------------- /kernel/div64.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BSD-3-Clause 2 | /* 3 | * This file is copied from the coreboot repository as part of 4 | * the libpayload project: 5 | * 6 | * Copyright 2014 Google Inc. 7 | */ 8 | 9 | #include 10 | 11 | union overlay64 { 12 | uint64_t longw; 13 | struct { 14 | uint32_t lower; 15 | uint32_t higher; 16 | } words; 17 | }; 18 | 19 | uint64_t __ashldi3(uint64_t num, unsigned int shift) { 20 | union overlay64 output; 21 | 22 | output.longw = num; 23 | if (shift >= 32) { 24 | output.words.higher = output.words.lower << (shift - 32); 25 | output.words.lower = 0; 26 | } else { 27 | if (!shift) return num; 28 | output.words.higher = (output.words.higher << shift) | 29 | (output.words.lower >> (32 - shift)); 30 | output.words.lower = output.words.lower << shift; 31 | } 32 | return output.longw; 33 | } 34 | 35 | uint64_t __lshrdi3(uint64_t num, unsigned int shift) { 36 | union overlay64 output; 37 | 38 | output.longw = num; 39 | if (shift >= 32) { 40 | output.words.lower = output.words.higher >> (shift - 32); 41 | output.words.higher = 0; 42 | } else { 43 | if (!shift) return num; 44 | output.words.lower = output.words.lower >> shift | 45 | (output.words.higher << (32 - shift)); 46 | output.words.higher = output.words.higher >> shift; 47 | } 48 | return output.longw; 49 | } 50 | 51 | #define MAX_32BIT_UINT ((((uint64_t)1) << 32) - 1) 52 | 53 | static uint64_t _64bit_divide(uint64_t dividend, uint64_t divider, uint64_t *rem_p) { 54 | uint64_t result = 0; 55 | 56 | /* 57 | * If divider is zero - let the rest of the system care about the 58 | * exception. 59 | */ 60 | if (!divider) return 1 / (uint32_t) divider; 61 | 62 | /* As an optimization, let's not use 64 bit division unless we must. */ 63 | if (dividend <= MAX_32BIT_UINT) { 64 | if (divider > MAX_32BIT_UINT) { 65 | result = 0; 66 | if (rem_p) 67 | *rem_p = divider; 68 | } else { 69 | result = (uint32_t) dividend / (uint32_t) divider; 70 | if (rem_p) *rem_p = (uint32_t) dividend % (uint32_t) divider; 71 | } 72 | return result; 73 | } 74 | 75 | while (divider <= dividend) { 76 | uint64_t locald = divider; 77 | uint64_t limit = __lshrdi3(dividend, 1); 78 | int shifts = 0; 79 | 80 | while (locald <= limit) { 81 | shifts++; 82 | locald = locald + locald; 83 | } 84 | result |= __ashldi3(1, shifts); 85 | dividend -= locald; 86 | } 87 | 88 | if (rem_p) *rem_p = dividend; 89 | 90 | return result; 91 | } 92 | 93 | _unused 94 | uint64_t __udivdi3(uint64_t num, uint64_t den) { 95 | return _64bit_divide(num, den, NULL); 96 | } 97 | 98 | _unused 99 | uint64_t __umoddi3(uint64_t num, uint64_t den) { 100 | uint64_t v = 0; 101 | _64bit_divide(num, den, &v); 102 | return v; 103 | } 104 | 105 | // Returns the number of leading 0-bits in x, starting at the most significant bit position. 106 | // If x is zero, the result is undefined. 107 | _unused 108 | int __clzsi2(unsigned x) { 109 | // This uses a binary search (counting down) algorithm from Hacker's Delight. 110 | unsigned y; 111 | int n = 32; 112 | y = x >>16; if (y != 0) {n = n -16; x = y;} 113 | y = x >> 8; if (y != 0) {n = n - 8; x = y;} 114 | y = x >> 4; if (y != 0) {n = n - 4; x = y;} 115 | y = x >> 2; if (y != 0) {n = n - 2; x = y;} 116 | y = x >> 1; if (y != 0) return n - 2; 117 | return n - x; 118 | } 119 | 120 | // Returns the number of trailing 0-bits in x, starting at the least significant bit position. 121 | // If x is zero, the result is undefined. 122 | _unused 123 | int __ctzsi2(unsigned x) { 124 | // This uses a binary search algorithm from Hacker's Delight. 125 | int n = 1; 126 | if ((x & 0x0000FFFF) == 0) {n = n +16; x = x >>16;} 127 | if ((x & 0x000000FF) == 0) {n = n + 8; x = x >> 8;} 128 | if ((x & 0x0000000F) == 0) {n = n + 4; x = x >> 4;} 129 | if ((x & 0x00000003) == 0) {n = n + 2; x = x >> 2;} 130 | return n - (x & 1); 131 | } 132 | 133 | // Returns the index of the least significant 1-bit in x, or the value zero if x is zero. 134 | // The least significant bit is index one. 135 | _unused 136 | int __ffsdi2 (unsigned x) { 137 | return (x == 0) ? 0 : __builtin_ctz(x) + 1; 138 | } -------------------------------------------------------------------------------- /kernel/drivers/acpi.c: -------------------------------------------------------------------------------- 1 | #include "acpi.h" 2 | #include "ports.h" 3 | 4 | #define KBRD_INTRFC 0x64 5 | 6 | /* keyboard interface bits */ 7 | #define KBRD_BIT_KDATA 0 /* keyboard data is in buffer (output buffer is empty) (bit 0) */ 8 | #define KBRD_BIT_UDATA 1 /* user data is in buffer (command buffer is empty) (bit 1) */ 9 | 10 | #define KBRD_IO 0x60 /* keyboard IO port */ 11 | #define KBRD_RESET 0xFE /* reset CPU command */ 12 | 13 | #define bit(n) (1<<(n)) 14 | #define check_flag(flags, n) ((flags) & bit(n)) 15 | 16 | // Not actually ACPI, but I'll get there eventually. 17 | _noreturn 18 | void reboot() { 19 | uint8_t temp; 20 | 21 | __asm__ volatile("cli"); /* disable all interrupts */ 22 | 23 | /* Clear all keyboard buffers (output and command buffers) */ 24 | do { 25 | temp = port_byte_in(KBRD_INTRFC); /* empty user data */ 26 | if (check_flag(temp, KBRD_BIT_KDATA) != 0) 27 | port_byte_in(KBRD_IO); /* empty keyboard data */ 28 | } while (check_flag(temp, KBRD_BIT_UDATA) != 0); 29 | 30 | port_byte_out(KBRD_INTRFC, KBRD_RESET); /* pulse CPU reset line */ 31 | loop: 32 | __asm__ volatile("hlt"); /* if that didn't work, halt the CPU */ 33 | goto loop; /* if a NMI is received, halt again */ 34 | } -------------------------------------------------------------------------------- /kernel/drivers/acpi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | _noreturn 6 | void reboot(); -------------------------------------------------------------------------------- /kernel/drivers/ata.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define ATA_SR_BSY 0x80 // Busy 6 | #define ATA_SR_DRDY 0x40 // Drive ready 7 | #define ATA_SR_DF 0x20 // Drive write fault 8 | #define ATA_SR_DSC 0x10 // Drive seek complete 9 | #define ATA_SR_DRQ 0x08 // Data request ready 10 | #define ATA_SR_CORR 0x04 // Corrected data 11 | #define ATA_SR_IDX 0x02 // Index 12 | #define ATA_SR_ERR 0x01 // Error 13 | 14 | #define ATA_ER_BBK 0x80 // Bad block 15 | #define ATA_ER_UNC 0x40 // Uncorrectable data 16 | #define ATA_ER_MC 0x20 // Media changed 17 | #define ATA_ER_IDNF 0x10 // ID mark not found 18 | #define ATA_ER_MCR 0x08 // Media change request 19 | #define ATA_ER_ABRT 0x04 // Command aborted 20 | #define ATA_ER_TK0NF 0x02 // Track 0 not found 21 | #define ATA_ER_AMNF 0x01 // No address mark 22 | 23 | #define ATA_CMD_READ_PIO 0x20 24 | #define ATA_CMD_READ_PIO_EXT 0x24 25 | #define ATA_CMD_READ_DMA 0xC8 26 | #define ATA_CMD_READ_DMA_EXT 0x25 27 | #define ATA_CMD_WRITE_PIO 0x30 28 | #define ATA_CMD_WRITE_PIO_EXT 0x34 29 | #define ATA_CMD_WRITE_DMA 0xCA 30 | #define ATA_CMD_WRITE_DMA_EXT 0x35 31 | #define ATA_CMD_CACHE_FLUSH 0xE7 32 | #define ATA_CMD_CACHE_FLUSH_EXT 0xEA 33 | #define ATA_CMD_PACKET 0xA0 34 | #define ATA_CMD_IDENTIFY_PACKET 0xA1 35 | #define ATA_CMD_IDENTIFY 0xEC 36 | 37 | #define ATAPI_CMD_READ 0xA8 38 | #define ATAPI_CMD_EJECT 0x1B 39 | 40 | #define ATA_IDENT_DEVICETYPE 0 41 | #define ATA_IDENT_CYLINDERS 2 42 | #define ATA_IDENT_HEADS 6 43 | #define ATA_IDENT_SECTORS 12 44 | #define ATA_IDENT_SERIAL 20 45 | #define ATA_IDENT_MODEL 54 46 | #define ATA_IDENT_CAPABILITIES 98 47 | #define ATA_IDENT_FIELDVALID 106 48 | #define ATA_IDENT_MAX_LBA 120 49 | #define ATA_IDENT_COMMANDSETS 164 50 | #define ATA_IDENT_MAX_LBA_EXT 200 51 | 52 | #define IDE_ATA 0x00 53 | #define IDE_ATAPI 0x01 54 | 55 | #define ATA_MASTER 0x00 56 | #define ATA_SLAVE 0x01 57 | 58 | #define ATA_REG_DATA 0x00 59 | #define ATA_REG_ERROR 0x01 60 | #define ATA_REG_FEATURES 0x01 61 | #define ATA_REG_SECCOUNT0 0x02 62 | #define ATA_REG_LBA0 0x03 63 | #define ATA_REG_LBA1 0x04 64 | #define ATA_REG_LBA2 0x05 65 | #define ATA_REG_HDDEVSEL 0x06 66 | #define ATA_REG_COMMAND 0x07 67 | #define ATA_REG_STATUS 0x07 68 | #define ATA_REG_SECCOUNT1 0x08 69 | #define ATA_REG_LBA3 0x09 70 | #define ATA_REG_LBA4 0x0A 71 | #define ATA_REG_LBA5 0x0B 72 | #define ATA_REG_CONTROL 0x0C 73 | #define ATA_REG_ALTSTATUS 0x0C 74 | #define ATA_REG_DEVADDRESS 0x0D 75 | 76 | // Channels: 77 | #define ATA_PRIMARY 0x00 78 | #define ATA_SECONDARY 0x01 79 | 80 | // Directions: 81 | #define ATA_READ 0x00 82 | #define ATA_WRITE 0x01 83 | 84 | struct ide_device { 85 | uint8_t reserved; // 0 (Empty) or 1 (This Drive really exists). 86 | uint8_t channel; // 0 (Primary Channel) or 1 (Secondary Channel). 87 | uint8_t drive; // 0 (Master Drive) or 1 (Slave Drive). 88 | uint16_t type; // 0: ATA, 1:ATAPI. 89 | uint16_t signature; // Drive Signature 90 | uint16_t capabilities;// Features. 91 | uint32_t command_sets; // Command Sets Supported. 92 | uint32_t size; // Size in Sectors. 93 | char model[41]; // Model in string. 94 | }; 95 | 96 | extern struct ide_device ide_devices[4]; 97 | 98 | void ata_init(); 99 | 100 | uint8_t ide_ata_access(uint8_t direction, uint8_t drive, uint32_t lba, 101 | uint8_t numsects, uint16_t selector, uint32_t edi); -------------------------------------------------------------------------------- /kernel/drivers/keyboard.c: -------------------------------------------------------------------------------- 1 | #include "keyboard.h" 2 | #include "ports.h" 3 | #include "timer.h" 4 | #include "../console.h" 5 | #include "../isr.h" 6 | #include "../shell.h" 7 | 8 | #include 9 | 10 | #define BACKSPACE 0x0E 11 | #define ENTER 0x1C 12 | #define L_SHIFT 0x2A 13 | #define R_SHIFT 0x36 14 | #define L_SHIFT_RELEASE 0xAA 15 | #define R_SHIFT_RELEASE 0xB6 16 | #define ARROW_UP 0x48 17 | #define ARROW_DOWN 0x50 18 | 19 | #define ASCII_MAX 58 20 | const char *sc_name[ASCII_MAX] = { 21 | "ERROR", "Esc", "1", "2", "3", "4", "5", "6", 22 | "7", "8", "9", "0", "-", "=", "Backspace", "Tab", "Q", "W", "E", 23 | "R", "T", "Y", "U", "I", "O", "P", "[", "]", "Enter", "Lctrl", 24 | "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "`", 25 | "LShift", "\\", "Z", "X", "C", "V", "B", "N", "M", ",", ".", 26 | "/", "RShift", "Keypad *", "LAlt", "Spacebar" 27 | }; 28 | const char sc_ascii[ASCII_MAX] = { 29 | 0, 0, '!', '@', '#', '$', '%', '^', 30 | '&', '*', '(', ')', '_', '+', 0, 0, 'Q', 'W', 'E', 'R', 'T', 'Y', 31 | 'U', 'I', 'O', 'P', '{', '}', 0, 0, 'A', 'S', 'D', 'F', 'G', 32 | 'H', 'J', 'K', 'L', ':', '"', '~', 0, '\\', 'Z', 'X', 'C', 'V', 33 | 'B', 'N', 'M', '<', '>', '?', 0, 0, 0, ' ' 34 | }; 35 | const char sc_ascii_lower[ASCII_MAX] = { 36 | 0, 0, '1', '2', '3', '4', '5', '6', 37 | '7', '8', '9', '0', '-', '=', 0, 0, 'q', 'w', 'e', 'r', 't', 'y', 38 | 'u', 'i', 'o', 'p', '[', ']', 0, 0, 'a', 's', 'd', 'f', 'g', 39 | 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', 40 | 'b', 'n', 'm', ',', '.', '/', 0, 0, 0, 0 41 | }; 42 | 43 | static bool shift_pressed = false; 44 | 45 | static void irq_callback(_unused registers_t regs) { 46 | unsigned char c = port_byte_in(0x60); 47 | if (c == L_SHIFT || c == R_SHIFT) { 48 | shift_pressed = true; 49 | } else if (c == L_SHIFT_RELEASE || c == R_SHIFT_RELEASE) { 50 | shift_pressed = false; 51 | } else if (c == BACKSPACE) { 52 | key_buffer_backspace(); 53 | } else if (c == ENTER) { 54 | key_buffer_return(); 55 | } else if (c == ARROW_UP) { 56 | shell_handle_up(); 57 | } else if (c == ARROW_DOWN) { 58 | shell_handle_down(); 59 | } 60 | 61 | if (c > ASCII_MAX) { 62 | return; 63 | } else if (!shift_pressed && sc_ascii_lower[c]) { 64 | key_buffer_append(sc_ascii_lower[c]); 65 | } else if (sc_ascii[c]) { 66 | key_buffer_append(sc_ascii[c]); 67 | } 68 | } 69 | 70 | void init_keyboard() { 71 | register_interrupt_handler(IRQ1, &irq_callback); 72 | } -------------------------------------------------------------------------------- /kernel/drivers/keyboard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void init_keyboard(); 4 | 5 | void key_buffer_set(char *input); 6 | 7 | void key_buffer_print(); -------------------------------------------------------------------------------- /kernel/drivers/pci.c: -------------------------------------------------------------------------------- 1 | #include "pci.h" 2 | #include "ports.h" 3 | #include "../console.h" 4 | 5 | #include 6 | 7 | #define PCI_VENDOR_NONE 0xFFFF 8 | 9 | static vc_vector *pci_devices; 10 | 11 | uint32_t pci_config_read_long(uint32_t id, uint8_t offset) { 12 | port_long_out(0xCF8, (uint32_t) 0x80000000 | id | (offset & 0xFC)); 13 | return port_long_in(0xCFC); 14 | } 15 | 16 | uint16_t pci_config_read_word(uint32_t id, uint8_t offset) { 17 | return (uint16_t) (pci_config_read_long(id, offset) >> (offset & 2) * 8 & 0xFFFF); 18 | } 19 | 20 | uint8_t pci_config_read_byte(uint32_t id, uint8_t offset) { 21 | return (uint8_t) (pci_config_read_word(id, offset) & 0xFF); 22 | } 23 | 24 | void pci_config_write_byte(uint32_t id, uint8_t offset, uint8_t val) { 25 | port_long_out(0xCF8, (uint32_t) 0x80000000 | id | (offset & 0xFC)); 26 | port_byte_out(0xCFC, val); 27 | } 28 | 29 | uint16_t pci_read_vendor(uint32_t id) { 30 | return pci_config_read_word(id, PCI_HEADER_VENDOR_ID); 31 | } 32 | 33 | uint8_t pci_read_header_type(uint32_t id) { 34 | return (uint8_t) (pci_config_read_word(id, PCI_HEADER_TYPE_ID) & 0xFF); 35 | } 36 | 37 | // lower half = subclass, upper half = base class 38 | uint16_t pci_read_class(uint32_t id) { 39 | return pci_config_read_word(id, PCI_HEADER_CLASS); 40 | } 41 | 42 | // lower half = primary, upper half = secondary 43 | uint16_t pci_read_bus_number(uint32_t id) { 44 | return pci_config_read_word(id, PCI_HEADER_BUS_NUM); 45 | } 46 | 47 | // lower half = revision, upper half = prog IF 48 | uint16_t pci_read_revision(uint32_t id) { 49 | return pci_config_read_word(id, PCI_HEADER_REVISION); 50 | } 51 | 52 | void pci_check_bus(uint8_t bus); 53 | 54 | bool pci_check_function(uint32_t id) { 55 | uint32_t val = pci_config_read_long(id, PCI_HEADER_VENDOR_ID); 56 | uint16_t vendor_id = (uint16_t) (val & 0xFFFF); 57 | uint16_t device_id = (uint16_t) (val >> 16 & 0xFFFF); 58 | if (vendor_id == PCI_VENDOR_NONE) return false; 59 | 60 | uint16_t class = pci_read_class(id); 61 | uint16_t revision = pci_read_revision(id); 62 | uint8_t header_type = pci_read_header_type(id); 63 | vc_vector_push_back(pci_devices, &(pci_device_t) { 64 | .loc = { 65 | .bus = PCI_ID_BUS(id), 66 | .device = PCI_ID_DEV(id), 67 | .function = PCI_ID_FUNC(id) 68 | }, 69 | .class = class, 70 | .vendor_id = vendor_id, 71 | .device_id = device_id, 72 | .revision_id = (uint8_t) (revision & 0xFF), 73 | .prog_if = (uint8_t) (revision >> 8 & 0xFF), 74 | .bar0 = pci_config_read_long(id, PCI_HEADER_BAR0_ADDR), 75 | .bar1 = pci_config_read_long(id, PCI_HEADER_BAR1_ADDR), 76 | .bar2 = header_type == 0x00 ? pci_config_read_long(id, PCI_HEADER_BAR2_ADDR) : 0, 77 | .bar3 = header_type == 0x00 ? pci_config_read_long(id, PCI_HEADER_BAR3_ADDR) : 0, 78 | .bar4 = header_type == 0x00 ? pci_config_read_long(id, PCI_HEADER_BAR4_ADDR) : 0, 79 | .bar5 = header_type == 0x00 ? pci_config_read_long(id, PCI_HEADER_BAR5_ADDR) : 0, 80 | }); 81 | 82 | // PCI-to-PCI bridge 83 | if (class == 0x0604) { 84 | // FIXME breaks VMWare 85 | // pci_check_bus(pci_config_read_byte(id, PCI_HEADER_SEC_BUS)); 86 | } 87 | return true; 88 | } 89 | 90 | void pci_check_device(uint8_t bus, uint8_t device) { 91 | uint32_t pci_id = PCI_ID(bus, device, 0); 92 | if (!pci_check_function(pci_id)) return; 93 | 94 | uint8_t header_type = pci_read_header_type(pci_id); 95 | if ((header_type & 0x80) != 0) { 96 | for (uint8_t function = 1; function < 8; function++) { 97 | pci_check_function(PCI_ID(bus, device, function)); 98 | } 99 | } 100 | } 101 | 102 | void pci_check_bus(uint8_t bus) { 103 | uint8_t device; 104 | for (device = 0; device < 32; device++) { 105 | pci_check_device(bus, device); 106 | } 107 | } 108 | 109 | void pci_check_all_buses() { 110 | uint8_t header_type = pci_read_header_type(PCI_ID(0, 0, 0)); 111 | if ((header_type & 0x80) == 0) { 112 | // Single PCI host controller 113 | pci_check_bus(0); 114 | } else { 115 | // Multiple PCI host controllers 116 | for (uint8_t function = 0; function < 8; function++) { 117 | if (pci_read_vendor(PCI_ID(0, 0, function)) != PCI_VENDOR_NONE) break; 118 | pci_check_bus(function); 119 | } 120 | } 121 | } 122 | 123 | void pci_init() { 124 | pci_devices = vc_vector_create(8, sizeof(pci_device_t), NULL); 125 | pci_check_all_buses(); 126 | vc_vector_reserve_count(pci_devices, 0); // Shrink 127 | } 128 | 129 | vc_vector *pci_get_devices() { 130 | return pci_devices; 131 | } -------------------------------------------------------------------------------- /kernel/drivers/pci.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #define PCI_ID(bus, dev, func) ((uint32_t) (bus & 0xFF) << 16 | (dev & 0x1F) << 11 | (func & 0x07) << 8) 7 | #define PCI_DEVICE_ID(dev) (PCI_ID(dev->loc.bus, dev->loc.device, dev->loc.function)) 8 | #define PCI_ID_BUS(id) ((uint8_t) ((id) >> 16 & 0xFF)) 9 | #define PCI_ID_DEV(id) ((uint8_t) ((id) >> 11 & 0x1F)) 10 | #define PCI_ID_FUNC(id) ((uint8_t) ((id) >> 8 & 0x07)) 11 | 12 | #define PCI_HEADER_VENDOR_ID 0x00 13 | #define PCI_HEADER_DEVICE_ID 0x02 14 | #define PCI_HEADER_REVISION 0x08 15 | #define PCI_HEADER_CLASS 0x0A 16 | #define PCI_HEADER_TYPE_ID 0x0E 17 | #define PCI_HEADER_BUS_NUM 0x18 18 | #define PCI_HEADER_SEC_BUS 0x19 19 | #define PCI_HEADER_IRQ_LINE 0x3C // 8 bits 20 | 21 | #define PCI_HEADER_BAR0_ADDR 0x10 22 | #define PCI_HEADER_BAR1_ADDR 0x14 23 | #define PCI_HEADER_BAR2_ADDR 0x18 24 | #define PCI_HEADER_BAR3_ADDR 0x1C 25 | #define PCI_HEADER_BAR4_ADDR 0x20 26 | #define PCI_HEADER_BAR5_ADDR 0x24 27 | 28 | struct pci_device_loc { 29 | uint8_t bus; 30 | uint8_t device; 31 | uint8_t function; 32 | }; 33 | typedef struct pci_device_loc pci_device_loc_t; 34 | 35 | struct pci_device { 36 | pci_device_loc_t loc; 37 | uint16_t class; 38 | uint16_t vendor_id; 39 | uint16_t device_id; 40 | uint8_t revision_id; 41 | uint8_t prog_if; 42 | uint32_t bar0; 43 | uint32_t bar1; 44 | uint32_t bar2; 45 | uint32_t bar3; 46 | uint32_t bar4; 47 | uint32_t bar5; 48 | }; 49 | typedef struct pci_device pci_device_t; 50 | 51 | void pci_init(); 52 | 53 | vc_vector *pci_get_devices(); 54 | 55 | uint32_t pci_config_read_long(uint32_t id, uint8_t offset); 56 | 57 | uint16_t pci_config_read_word(uint32_t id, uint8_t offset); 58 | 59 | uint8_t pci_config_read_byte(uint32_t id, uint8_t offset); 60 | 61 | void pci_config_write_byte(uint32_t id, uint8_t offset, uint8_t val); -------------------------------------------------------------------------------- /kernel/drivers/pci_registry.c: -------------------------------------------------------------------------------- 1 | #include "pci_registry.h" 2 | 3 | const char *pci_device_name(uint16_t vendor_id, uint16_t device_id) { 4 | return "Unknown Device"; 5 | } 6 | 7 | // ------------------------------------------------------------------------------------------------ 8 | const char *pci_class_name(uint16_t class, uint8_t prog_if) { 9 | switch (class) { 10 | case PCI_VGA_COMPATIBLE: return "VGA-Compatible Device"; 11 | case PCI_STORAGE_SCSI: return "SCSI Storage Controller"; 12 | case PCI_STORAGE_IDE: return "IDE Interface"; 13 | case PCI_STORAGE_FLOPPY: return "Floppy Disk Controller"; 14 | case PCI_STORAGE_IPI: return "IPI Bus Controller"; 15 | case PCI_STORAGE_RAID: return "RAID Bus Controller"; 16 | case PCI_STORAGE_ATA: return "ATA Controller"; 17 | case PCI_STORAGE_SATA: return "SATA Controller"; 18 | case PCI_STORAGE_OTHER: return "Mass Storage Controller"; 19 | case PCI_NETWORK_ETHERNET: return "Ethernet Controller"; 20 | case PCI_NETWORK_TOKEN_RING: return "Token Ring Controller"; 21 | case PCI_NETWORK_FDDI: return "FDDI Controller"; 22 | case PCI_NETWORK_ATM: return "ATM Controller"; 23 | case PCI_NETWORK_ISDN: return "ISDN Controller"; 24 | case PCI_NETWORK_WORLDFIP: return "WorldFip Controller"; 25 | case PCI_NETWORK_PICGMG: return "PICMG Controller"; 26 | case PCI_NETWORK_OTHER: return "Network Controller"; 27 | case PCI_DISPLAY_VGA: return "VGA-Compatible Controller"; 28 | case PCI_DISPLAY_XGA: return "XGA-Compatible Controller"; 29 | case PCI_DISPLAY_3D: return "3D Controller"; 30 | case PCI_DISPLAY_OTHER: return "Display Controller"; 31 | case PCI_MULTIMEDIA_VIDEO: return "Multimedia Video Controller"; 32 | case PCI_MULTIMEDIA_AUDIO: return "Multimedia Audio Controller"; 33 | case PCI_MULTIMEDIA_PHONE: return "Computer Telephony Device"; 34 | case PCI_MULTIMEDIA_AUDIO_DEVICE: return "Audio Device"; 35 | case PCI_MULTIMEDIA_OTHER: return "Multimedia Controller"; 36 | case PCI_MEMORY_RAM: return "RAM Memory"; 37 | case PCI_MEMORY_FLASH: return "Flash Memory"; 38 | case PCI_MEMORY_OTHER: return "Memory Controller"; 39 | case PCI_BRIDGE_HOST: return "Host Bridge"; 40 | case PCI_BRIDGE_ISA: return "ISA Bridge"; 41 | case PCI_BRIDGE_EISA: return "EISA Bridge"; 42 | case PCI_BRIDGE_MCA: return "MicroChannel Bridge"; 43 | case PCI_BRIDGE_PCI: return "PCI Bridge"; 44 | case PCI_BRIDGE_PCMCIA: return "PCMCIA Bridge"; 45 | case PCI_BRIDGE_NUBUS: return "NuBus Bridge"; 46 | case PCI_BRIDGE_CARDBUS: return "CardBus Bridge"; 47 | case PCI_BRIDGE_RACEWAY: return "RACEway Bridge"; 48 | case PCI_BRIDGE_OTHER: return "Bridge Device"; 49 | case PCI_COMM_SERIAL: return "Serial Controller"; 50 | case PCI_COMM_PARALLEL: return "Parallel Controller"; 51 | case PCI_COMM_MULTIPORT: return "Multiport Serial Controller"; 52 | case PCI_COMM_MODEM: return "Modem"; 53 | case PCI_COMM_OTHER: return "Communication Controller"; 54 | case PCI_SYSTEM_PIC: return "PIC"; 55 | case PCI_SYSTEM_DMA: return "DMA Controller"; 56 | case PCI_SYSTEM_TIMER: return "Timer"; 57 | case PCI_SYSTEM_RTC: return "RTC"; 58 | case PCI_SYSTEM_PCI_HOTPLUG: return "PCI Hot-Plug Controller"; 59 | case PCI_SYSTEM_SD: return "SD Host Controller"; 60 | case PCI_SYSTEM_OTHER: return "System Peripheral"; 61 | case PCI_INPUT_KEYBOARD: return "Keyboard Controller"; 62 | case PCI_INPUT_PEN: return "Pen Controller"; 63 | case PCI_INPUT_MOUSE: return "Mouse Controller"; 64 | case PCI_INPUT_SCANNER: return "Scanner Controller"; 65 | case PCI_INPUT_GAMEPORT: return "Gameport Controller"; 66 | case PCI_INPUT_OTHER: return "Input Controller"; 67 | case PCI_DOCKING_GENERIC: return "Generic Docking Station"; 68 | case PCI_DOCKING_OTHER: return "Docking Station"; 69 | case PCI_PROCESSOR_386: return "386"; 70 | case PCI_PROCESSOR_486: return "486"; 71 | case PCI_PROCESSOR_PENTIUM: return "Pentium"; 72 | case PCI_PROCESSOR_ALPHA: return "Alpha"; 73 | case PCI_PROCESSOR_MIPS: return "MIPS"; 74 | case PCI_PROCESSOR_CO: return "CO-Processor"; 75 | case PCI_SERIAL_FIREWIRE: return "FireWire (IEEE 1394)"; 76 | case PCI_SERIAL_SSA: return "SSA"; 77 | case PCI_SERIAL_USB: 78 | switch (prog_if) { 79 | case PCI_SERIAL_USB_UHCI: return "USB (UHCI)"; 80 | case PCI_SERIAL_USB_OHCI: return "USB (OHCI)"; 81 | case PCI_SERIAL_USB_EHCI: return "USB2"; 82 | case PCI_SERIAL_USB_XHCI: return "USB3"; 83 | case PCI_SERIAL_USB_OTHER: return "USB Controller"; 84 | default: return "Unknown USB Class"; 85 | } 86 | case PCI_SERIAL_FIBER: return "Fiber Channel"; 87 | case PCI_SERIAL_SMBUS: return "SMBus"; 88 | case PCI_WIRELESS_IRDA: return "iRDA Compatible Controller"; 89 | case PCI_WIRLESSS_IR: return "Consumer IR Controller"; 90 | case PCI_WIRLESSS_RF: return "RF Controller"; 91 | case PCI_WIRLESSS_BLUETOOTH: return "Bluetooth"; 92 | case PCI_WIRLESSS_BROADBAND: return "Broadband"; 93 | case PCI_WIRLESSS_ETHERNET_A: return "802.1a Controller"; 94 | case PCI_WIRLESSS_ETHERNET_B: return "802.1b Controller"; 95 | case PCI_WIRELESS_OTHER: return "Wireless Controller"; 96 | case PCI_INTELLIGENT_I2O: return "I2O Controller"; 97 | case PCI_SATELLITE_TV: return "Satellite TV Controller"; 98 | case PCI_SATELLITE_AUDIO: return "Satellite Audio Controller"; 99 | case PCI_SATELLITE_VOICE: return "Satellite Voice Controller"; 100 | case PCI_SATELLITE_DATA: return "Satellite Data Controller"; 101 | case PCI_CRYPT_NETWORK: return "Network and Computing Encryption Device"; 102 | case PCI_CRYPT_ENTERTAINMENT: return "Entertainment Encryption Device"; 103 | case PCI_CRYPT_OTHER: return "Encryption Device"; 104 | case PCI_SP_DPIO: return "DPIO Modules"; 105 | case PCI_SP_OTHER: return "Signal Processing Controller"; 106 | default: return "Unknown PCI Class"; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /kernel/drivers/pci_registry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | const char *pci_device_name(uint16_t vendor_id, uint16_t device_id); 6 | const char *pci_class_name(uint16_t class, uint8_t prog_if); 7 | 8 | // PCI Vendors 9 | #define PCI_VENDOR_INTEL 0x8086 10 | 11 | // PCI Classes 12 | #define PCI_CLASS_LEGACY 0x00 13 | #define PCI_CLASS_STORAGE 0x01 14 | #define PCI_CLASS_NETWORK 0x02 15 | #define PCI_CLASS_DISPLAY 0x03 16 | #define PCI_CLASS_MULTIMEDIA 0x04 17 | #define PCI_CLASS_MEMORY 0x05 18 | #define PCI_CLASS_BRIDGE_DEVICE 0x06 19 | #define PCI_CLASS_COMMUNICATION 0x07 20 | #define PCI_CLASS_PERIHPERALS 0x08 21 | #define PCI_CLASS_INPUT_DEVICES 0x09 22 | #define PCI_CLASS_DOCKING_STATION 0x0a 23 | #define PCI_CLASS_PROCESSOR 0x0b 24 | #define PCI_CLASS_SERIAL_BUS 0x0c 25 | #define PCI_CLASS_WIRELESS 0x0d 26 | #define PCI_CLASS_INTELLIGENT_IO 0x0e 27 | #define PCI_CLASS_SATELLITE 0x0f 28 | #define PCI_CLASS_CRYPT 0x10 29 | #define PCI_CLASS_SIGNAL_PROCESSING 0x11 30 | #define PCI_CLASS_UNDEFINED 0xff 31 | 32 | // Undefined Class 33 | #define PCI_UNCLASSIFIED 0x0000 34 | #define PCI_VGA_COMPATIBLE 0x0001 35 | 36 | // Mass Storage Controller 37 | #define PCI_STORAGE_SCSI 0x0100 38 | #define PCI_STORAGE_IDE 0x0101 39 | #define PCI_STORAGE_FLOPPY 0x0102 40 | #define PCI_STORAGE_IPI 0x0103 41 | #define PCI_STORAGE_RAID 0x0104 42 | #define PCI_STORAGE_ATA 0x0105 43 | #define PCI_STORAGE_SATA 0x0106 44 | #define PCI_STORAGE_OTHER 0x0180 45 | 46 | // Network Controller 47 | #define PCI_NETWORK_ETHERNET 0x0200 48 | #define PCI_NETWORK_TOKEN_RING 0x0201 49 | #define PCI_NETWORK_FDDI 0x0202 50 | #define PCI_NETWORK_ATM 0x0203 51 | #define PCI_NETWORK_ISDN 0x0204 52 | #define PCI_NETWORK_WORLDFIP 0x0205 53 | #define PCI_NETWORK_PICGMG 0x0206 54 | #define PCI_NETWORK_OTHER 0x0280 55 | 56 | // Display Controller 57 | #define PCI_DISPLAY_VGA 0x0300 58 | #define PCI_DISPLAY_XGA 0x0301 59 | #define PCI_DISPLAY_3D 0x0302 60 | #define PCI_DISPLAY_OTHER 0x0380 61 | 62 | // Multimedia Controller 63 | #define PCI_MULTIMEDIA_VIDEO 0x0400 64 | #define PCI_MULTIMEDIA_AUDIO 0x0401 65 | #define PCI_MULTIMEDIA_PHONE 0x0402 66 | #define PCI_MULTIMEDIA_AUDIO_DEVICE 0x0403 67 | #define PCI_MULTIMEDIA_OTHER 0x0480 68 | 69 | // Memory Controller 70 | #define PCI_MEMORY_RAM 0x0500 71 | #define PCI_MEMORY_FLASH 0x0501 72 | #define PCI_MEMORY_OTHER 0x0580 73 | 74 | // Bridge Device 75 | #define PCI_BRIDGE_HOST 0x0600 76 | #define PCI_BRIDGE_ISA 0x0601 77 | #define PCI_BRIDGE_EISA 0x0602 78 | #define PCI_BRIDGE_MCA 0x0603 79 | #define PCI_BRIDGE_PCI 0x0604 80 | #define PCI_BRIDGE_PCMCIA 0x0605 81 | #define PCI_BRIDGE_NUBUS 0x0606 82 | #define PCI_BRIDGE_CARDBUS 0x0607 83 | #define PCI_BRIDGE_RACEWAY 0x0608 84 | #define PCI_BRIDGE_OTHER 0x0680 85 | 86 | // Simple Communication Controller 87 | #define PCI_COMM_SERIAL 0x0700 88 | #define PCI_COMM_PARALLEL 0x0701 89 | #define PCI_COMM_MULTIPORT 0x0702 90 | #define PCI_COMM_MODEM 0x0703 91 | #define PCI_COMM_GPIB 0x0704 92 | #define PCI_COMM_SMARTCARD 0x0705 93 | #define PCI_COMM_OTHER 0x0780 94 | 95 | // Base System Peripherals 96 | #define PCI_SYSTEM_PIC 0x0800 97 | #define PCI_SYSTEM_DMA 0x0801 98 | #define PCI_SYSTEM_TIMER 0x0802 99 | #define PCI_SYSTEM_RTC 0x0803 100 | #define PCI_SYSTEM_PCI_HOTPLUG 0x0804 101 | #define PCI_SYSTEM_SD 0x0805 102 | #define PCI_SYSTEM_OTHER 0x0880 103 | 104 | // Input Devices 105 | #define PCI_INPUT_KEYBOARD 0x0900 106 | #define PCI_INPUT_PEN 0x0901 107 | #define PCI_INPUT_MOUSE 0x0902 108 | #define PCI_INPUT_SCANNER 0x0903 109 | #define PCI_INPUT_GAMEPORT 0x0904 110 | #define PCI_INPUT_OTHER 0x0980 111 | 112 | // Docking Stations 113 | #define PCI_DOCKING_GENERIC 0x0a00 114 | #define PCI_DOCKING_OTHER 0x0a80 115 | 116 | // Processors 117 | #define PCI_PROCESSOR_386 0x0b00 118 | #define PCI_PROCESSOR_486 0x0b01 119 | #define PCI_PROCESSOR_PENTIUM 0x0b02 120 | #define PCI_PROCESSOR_ALPHA 0x0b10 121 | #define PCI_PROCESSOR_POWERPC 0x0b20 122 | #define PCI_PROCESSOR_MIPS 0x0b30 123 | #define PCI_PROCESSOR_CO 0x0b40 124 | 125 | // Serial Bus Controllers 126 | #define PCI_SERIAL_FIREWIRE 0x0c00 127 | #define PCI_SERIAL_ACCESS 0x0c01 128 | #define PCI_SERIAL_SSA 0x0c02 129 | #define PCI_SERIAL_USB 0x0c03 130 | #define PCI_SERIAL_FIBER 0x0c04 131 | #define PCI_SERIAL_SMBUS 0x0c05 132 | 133 | #define PCI_SERIAL_USB_UHCI 0x00 134 | #define PCI_SERIAL_USB_OHCI 0x10 135 | #define PCI_SERIAL_USB_EHCI 0x20 136 | #define PCI_SERIAL_USB_XHCI 0x30 137 | #define PCI_SERIAL_USB_OTHER 0x80 138 | 139 | // Wireless Controllers 140 | #define PCI_WIRELESS_IRDA 0x0d00 141 | #define PCI_WIRLESSS_IR 0x0d01 142 | #define PCI_WIRLESSS_RF 0x0d10 143 | #define PCI_WIRLESSS_BLUETOOTH 0x0d11 144 | #define PCI_WIRLESSS_BROADBAND 0x0d12 145 | #define PCI_WIRLESSS_ETHERNET_A 0x0d20 146 | #define PCI_WIRLESSS_ETHERNET_B 0x0d21 147 | #define PCI_WIRELESS_OTHER 0x0d80 148 | 149 | // Intelligent I/O Controllers 150 | #define PCI_INTELLIGENT_I2O 0x0e00 151 | 152 | // Satellite Communication Controllers 153 | #define PCI_SATELLITE_TV 0x0f00 154 | #define PCI_SATELLITE_AUDIO 0x0f01 155 | #define PCI_SATELLITE_VOICE 0x0f03 156 | #define PCI_SATELLITE_DATA 0x0f04 157 | 158 | // Encryption/Decryption Controllers 159 | #define PCI_CRYPT_NETWORK 0x1000 160 | #define PCI_CRYPT_ENTERTAINMENT 0x1001 161 | #define PCI_CRYPT_OTHER 0x1080 162 | 163 | // Data Acquisition and Signal Processing Controllers 164 | #define PCI_SP_DPIO 0x1100 165 | #define PCI_SP_OTHER 0x1180 -------------------------------------------------------------------------------- /kernel/drivers/ports.c: -------------------------------------------------------------------------------- 1 | #include "ports.h" 2 | 3 | unsigned char port_byte_in(uint16_t port) { 4 | uint8_t result; 5 | __asm__ volatile("in %1, %0" : "=a"(result) : "Nd"(port)); 6 | return result; 7 | } 8 | 9 | void port_byte_out(uint16_t port, uint8_t data) { 10 | __asm__ volatile("out %0, %1" : : "a"(data), "Nd"(port)); 11 | } 12 | 13 | uint16_t port_word_in(uint16_t port) { 14 | uint16_t result; 15 | __asm__ volatile("in %1, %0" : "=a"(result) : "Nd"(port)); 16 | return result; 17 | } 18 | 19 | void port_word_out(uint16_t port, uint16_t data) { 20 | __asm__("out %0, %1" : : "a"(data), "Nd"(port)); 21 | } 22 | 23 | uint32_t port_long_in(uint16_t port) { 24 | uint32_t result; 25 | __asm__ volatile("in %1, %0" : "=a"(result) : "Nd"(port)); 26 | return result; 27 | } 28 | 29 | void port_long_out(uint16_t port, uint32_t data) { 30 | __asm__ volatile("out %0, %1" : : "a"(data), "Nd"(port)); 31 | } -------------------------------------------------------------------------------- /kernel/drivers/ports.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define I86_PIT_REG_COUNTER0 0x40 6 | #define I86_PIT_REG_COUNTER1 0x41 7 | #define I86_PIT_REG_COUNTER2 0x42 8 | #define I86_PIT_REG_COMMAND 0x43 9 | 10 | uint8_t port_byte_in(uint16_t port); 11 | 12 | void port_byte_out(uint16_t port, uint8_t data); 13 | 14 | uint16_t port_word_in(uint16_t port); 15 | 16 | void port_word_out(uint16_t port, uint16_t data); 17 | 18 | uint32_t port_long_in(uint16_t port); 19 | 20 | void port_long_out(uint16_t port, uint32_t data); -------------------------------------------------------------------------------- /kernel/drivers/serial.c: -------------------------------------------------------------------------------- 1 | #include "serial.h" 2 | #include "ports.h" 3 | 4 | #define COM1_BASE 0x3f8 5 | 6 | void serial_init() { 7 | port_byte_out(COM1_BASE + 1, 0x00); // Disable all interrupts 8 | port_byte_out(COM1_BASE + 3, 0x80); // Enable DLAB (set baud rate divisor) 9 | port_byte_out(COM1_BASE + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud 10 | port_byte_out(COM1_BASE + 1, 0x00); // (hi byte) 11 | port_byte_out(COM1_BASE + 3, 0x03); // 8 bits, no parity, one stop bit 12 | port_byte_out(COM1_BASE + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold 13 | port_byte_out(COM1_BASE + 4, 0x0B); // IRQs enabled, RTS/DSR set 14 | } 15 | 16 | bool serial_received() { 17 | return (port_byte_in(COM1_BASE + 5) & 1) != 0; 18 | } 19 | 20 | char serial_read() { 21 | while (serial_received() == 0); 22 | return port_byte_in(COM1_BASE); 23 | } 24 | 25 | bool serial_transmit_empty() { 26 | return (port_byte_in(COM1_BASE + 5) & 0x20) != 0; 27 | } 28 | 29 | void serial_write(char a) { 30 | if (a == '\n') serial_write('\r'); 31 | while (serial_transmit_empty() == 0); 32 | port_byte_out(COM1_BASE, (unsigned char) a); 33 | } -------------------------------------------------------------------------------- /kernel/drivers/serial.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void serial_init(); 6 | 7 | bool serial_received(); 8 | 9 | char serial_read(); 10 | 11 | bool serial_transmit_empty(); 12 | 13 | void serial_write(char a); -------------------------------------------------------------------------------- /kernel/drivers/timer.c: -------------------------------------------------------------------------------- 1 | #include "timer.h" 2 | #include "../isr.h" 3 | #include "../console.h" 4 | #include "ports.h" 5 | 6 | uint32_t tick = 0; 7 | 8 | static void timer_callback(registers_t regs) { 9 | tick++; 10 | // kprint("Tick: "); 11 | // kprint_uint32(tick); 12 | // kprint_char('\n'); 13 | } 14 | 15 | void init_timer(uint32_t frequency) { 16 | // Firstly, register our timer callback. 17 | register_interrupt_handler(IRQ0, &timer_callback); 18 | 19 | // The value we send to the PIT is the value to divide it's input clock 20 | // (1193180 Hz) by, to get our required frequency. Important to note is 21 | // that the divisor must be small enough to fit into 16-bits. 22 | uint16_t divisor = (uint16_t) (1193180 / frequency); 23 | 24 | // Send the command byte. 25 | port_byte_out(I86_PIT_REG_COMMAND, 0x36); 26 | 27 | // Send the frequency divisor. 28 | port_byte_out(I86_PIT_REG_COUNTER0, (uint8_t) (divisor & 0xFF)); 29 | port_byte_out(I86_PIT_REG_COUNTER0, (uint8_t) (divisor >> 8 & 0xFF)); 30 | 31 | tick = 0; 32 | } 33 | 34 | uint32_t get_tick() { 35 | return tick; 36 | } -------------------------------------------------------------------------------- /kernel/drivers/timer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void init_timer(uint32_t frequency); 6 | 7 | uint32_t get_tick(); -------------------------------------------------------------------------------- /kernel/drivers/vga.c: -------------------------------------------------------------------------------- 1 | #include "vga.h" 2 | #include "ports.h" 3 | #include "../console.h" 4 | #include "../kmalloc.h" 5 | #include "../psf.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // EGA text console 13 | uint16_t *console_fb_addr = NULL; 14 | 15 | // RGB text console 16 | void *rgb_fb_addr = NULL; 17 | framebuffer_info_t rgb_fb_info = {}; 18 | 19 | psf_font_t rgb_console_font = {}; 20 | void *rgb_console_font_glyphs = NULL; 21 | 22 | unsigned int rgb_console_rows = 0; 23 | unsigned int rgb_console_cols = 0; 24 | int rgb_console_offset = 0; 25 | 26 | typedef struct _packed rgb_console_buffer_entry { 27 | vga_rgb_color_t fg; 28 | _unused uint8_t __padding; 29 | vga_rgb_color_t bg; 30 | char c; 31 | } rgb_console_buffer_entry_t; 32 | 33 | rgb_console_buffer_entry_t *rgb_console_buffer = NULL; 34 | 35 | static void vga_console_repaint(); 36 | 37 | void vga_init(void *fb_addr, uint8_t type, framebuffer_info_t *fb_info) { 38 | if (type == VGA_FB_TYPE_EGA_TEXT) { 39 | console_fb_addr = fb_addr; 40 | } else if (type == VGA_FB_TYPE_RGB) { 41 | rgb_fb_addr = fb_addr; 42 | rgb_fb_info = *fb_info; 43 | } 44 | } 45 | 46 | int vga_load_font(const char *filename) { 47 | if (rgb_fb_addr == NULL) return 1; 48 | 49 | int prev_width = 0, prev_height = 0; 50 | void *old_glyphs = rgb_console_font_glyphs; 51 | if (old_glyphs != NULL) { 52 | prev_width = rgb_console_font.width; 53 | prev_height = rgb_console_font.height; 54 | } 55 | 56 | rgb_console_font_glyphs = psf_read_font(filename, &rgb_console_font); 57 | if (rgb_console_font_glyphs == NULL) { 58 | rgb_console_font_glyphs = old_glyphs; 59 | fprintf(stderr, "Failed to read font %s (err: %d)\n", filename, errno); 60 | return 2; 61 | } 62 | kfree(old_glyphs); 63 | 64 | rgb_console_cols = rgb_fb_info.width / rgb_console_font.width; 65 | rgb_console_rows = rgb_fb_info.height / rgb_console_font.height; 66 | 67 | size_t buffer_size = rgb_console_rows * rgb_console_cols * sizeof(rgb_console_buffer_entry_t); 68 | rgb_console_buffer_entry_t *new_buffer = kmalloc(buffer_size); 69 | if (new_buffer == NULL) { 70 | errno = ENOMEM; 71 | fprintf(stderr, "Failed to allocate memory for console buffer.\n"); 72 | return 1; 73 | } 74 | memset(new_buffer, 0, buffer_size); 75 | 76 | if (rgb_console_buffer != NULL) { 77 | size_t prev_size = (rgb_fb_info.width / prev_width) 78 | * (rgb_fb_info.height / prev_height) 79 | * sizeof(rgb_console_buffer_entry_t); 80 | if (prev_size > buffer_size) { 81 | size_t diff = prev_size - buffer_size; 82 | memcpy(new_buffer, (void *) rgb_console_buffer + diff, buffer_size); 83 | // FIXME refactor to avoid this kludgy division 84 | rgb_console_offset -= diff / sizeof(rgb_console_buffer_entry_t); 85 | if (rgb_console_offset < 0) rgb_console_offset = 0; 86 | } else { 87 | memcpy(new_buffer, rgb_console_buffer, prev_size); 88 | memset((void *) new_buffer + prev_size, 0, buffer_size - prev_size); 89 | } 90 | kfree(rgb_console_buffer); 91 | } 92 | rgb_console_buffer = new_buffer; 93 | vga_console_repaint(); 94 | return 0; 95 | } 96 | 97 | static inline void vga_set_pixel(int x, int y, uint32_t val) { 98 | *(uint32_t *) (rgb_fb_addr + x * 4 + rgb_fb_info.pitch * y) = val; 99 | } 100 | 101 | void vga_fill_rect(int x1, int y1, int x2, int y2, vga_rgb_color_t *color) { 102 | if (rgb_fb_addr == NULL || rgb_fb_info.bpp != 32) return; 103 | uint32_t val = ((uint32_t) color->red << rgb_fb_info.red_field_position) 104 | | ((uint32_t) color->green << rgb_fb_info.green_field_position) 105 | | ((uint32_t) color->blue << rgb_fb_info.blue_field_position); 106 | 107 | int xmin = MAX(MIN(x1, x2), 0); 108 | int xmax = MIN(MAX(x1, x2), rgb_fb_info.width); 109 | int ymin = MAX(MIN(y1, y2), 0); 110 | int ymax = MIN(MAX(y1, y2), rgb_fb_info.height); 111 | for (int y = ymin; y < ymax; y++) { 112 | for (int x = xmin; x < xmax; x++) { 113 | vga_set_pixel(x, y, val); 114 | } 115 | } 116 | } 117 | 118 | void vga_display_image_bgra(int x, int y, bmp_info_header_t *header, uint8_t *image) { 119 | if (rgb_fb_addr == NULL || rgb_fb_info.bpp != 32) return; 120 | 121 | int xmax = MIN(x + header->width, rgb_fb_info.width); 122 | int ymax = MIN(y + header->height, rgb_fb_info.height); 123 | for (int y1 = y; y1 < ymax; y1++) { 124 | for (int x1 = x; x1 < xmax; x1++) { 125 | uint8_t *pixel = image + ((x1 + ((header->height - y1) * header->width)) * 4); 126 | vga_set_pixel(x1, y1, (uint32_t) *pixel << rgb_fb_info.blue_field_position 127 | | (uint32_t) *(pixel + 1) << rgb_fb_info.green_field_position 128 | | (uint32_t) *(pixel + 2) << rgb_fb_info.red_field_position); 129 | } 130 | } 131 | } 132 | 133 | static inline uint32_t vga_rgb_color(vga_rgb_color_t *color) { 134 | return ((uint32_t) color->red << rgb_fb_info.red_field_position) 135 | | ((uint32_t) color->green << rgb_fb_info.green_field_position) 136 | | ((uint32_t) color->blue << rgb_fb_info.blue_field_position); 137 | } 138 | 139 | static void vga_print_glyph(int offset, char c, vga_rgb_color_t *fg_color, vga_rgb_color_t *bg_color) { 140 | if (rgb_fb_addr == NULL || rgb_fb_info.bpp != 32) return; 141 | 142 | int row = offset / rgb_console_cols; 143 | int x = (offset % rgb_console_cols) * rgb_console_font.width; 144 | int y = row * rgb_console_font.height; 145 | 146 | uint32_t fg_val = vga_rgb_color(fg_color); 147 | uint32_t bg_val = vga_rgb_color(bg_color); 148 | 149 | int xmax = MIN(x + rgb_console_font.width, rgb_fb_info.width); 150 | int ymax = MIN(y + rgb_console_font.height, rgb_fb_info.height); 151 | uint8_t *glyph = rgb_console_font_glyphs + (rgb_console_font.bytes_per_glyph * (uint8_t) c); 152 | 153 | for (int y1 = y; y1 < ymax; y1++) { 154 | for (int x1 = x; x1 < xmax; x1++) { 155 | uint8_t gb = *(glyph + (y1 - y)); 156 | vga_set_pixel(x1, y1, (gb >> (8 - (x1 - x))) & 1 ? fg_val : bg_val); 157 | } 158 | } 159 | } 160 | 161 | int vga_print_char(char c, int offset, char attr) { 162 | if (rgb_fb_addr != NULL) { 163 | if (rgb_console_font_glyphs == NULL) return 0; 164 | if (offset < 0) { 165 | offset = rgb_console_offset; 166 | } else if (offset >= rgb_console_rows * rgb_console_cols) { 167 | return rgb_console_offset; 168 | } 169 | 170 | if (c == '\b') { 171 | offset--; 172 | } else if (c == '\n') { 173 | unsigned int row = offset / rgb_console_cols; 174 | offset = (row + 1) * rgb_console_cols; 175 | } else { 176 | vga_rgb_color_t fg_color = {255, 255, 255}; 177 | vga_rgb_color_t bg_color = {0, 0, 0}; 178 | 179 | // FIXME make more dynamic 180 | if (attr == RED_ON_BLACK) { 181 | fg_color = (vga_rgb_color_t) {255, 0, 0}; 182 | bg_color = (vga_rgb_color_t) {0, 0, 0}; 183 | } 184 | 185 | rgb_console_buffer[offset] = (rgb_console_buffer_entry_t) {.c = c, .fg = fg_color, .bg = bg_color}; 186 | if (!c) c = ' '; 187 | vga_print_glyph(offset++, c, &fg_color, &bg_color); 188 | } 189 | rgb_console_offset = offset = vga_handle_scrolling(offset); 190 | } else if (console_fb_addr != NULL) { 191 | if (!attr) attr = WHITE_ON_BLACK; 192 | 193 | if (offset < 0) { 194 | offset = vga_get_cursor_offset(); 195 | } else if (offset >= MAX_ROWS * MAX_COLS) { 196 | console_fb_addr[MAX_COLS * MAX_ROWS - 1] = vga_entry('E', RED_ON_WHITE); 197 | return vga_get_cursor_offset(); 198 | } 199 | 200 | if (c == '\b') { 201 | offset--; 202 | } else if (c == '\n') { 203 | offset = vga_get_offset(0, vga_get_offset_row(offset) + 1); 204 | } else { 205 | console_fb_addr[offset++] = ((uint16_t) attr << 8 | c); 206 | } 207 | vga_set_cursor_offset(offset = vga_handle_scrolling(offset)); 208 | } 209 | 210 | return offset; 211 | } 212 | 213 | int vga_get_cursor_offset() { 214 | if (console_fb_addr == NULL) return 0; 215 | 216 | port_byte_out(REG_SCREEN_CTRL, 14); 217 | int offset = port_byte_in(REG_SCREEN_DATA) << 8; /* High byte: << 8 */ 218 | port_byte_out(REG_SCREEN_CTRL, 15); 219 | offset += port_byte_in(REG_SCREEN_DATA); 220 | return offset; 221 | } 222 | 223 | void vga_set_cursor_offset(int offset) { 224 | if (console_fb_addr == NULL) return; 225 | 226 | port_byte_out(REG_SCREEN_CTRL, 14); 227 | port_byte_out(REG_SCREEN_DATA, (unsigned char) (offset >> 8)); 228 | port_byte_out(REG_SCREEN_CTRL, 15); 229 | port_byte_out(REG_SCREEN_DATA, (unsigned char) (offset & 0xff)); 230 | } 231 | 232 | void vga_clear_screen() { 233 | if (console_fb_addr != NULL) { 234 | memset(console_fb_addr, 0, MAX_COLS * MAX_ROWS * sizeof(*console_fb_addr)); 235 | vga_set_cursor_offset(vga_get_offset(0, 0)); 236 | } else if (rgb_fb_addr != NULL) { 237 | vga_fill_rect(0, 0, rgb_fb_info.width, rgb_fb_info.height, &(vga_rgb_color_t) {0, 0, 0}); 238 | memset(rgb_console_buffer, 0, rgb_console_rows * rgb_console_cols * sizeof(rgb_console_buffer_entry_t)); 239 | rgb_console_offset = 0; 240 | } 241 | } 242 | 243 | static void vga_console_repaint() { 244 | for (size_t i = 0; i < rgb_console_rows * rgb_console_cols; ++i) { 245 | rgb_console_buffer_entry_t *entry = &rgb_console_buffer[i]; 246 | char c = entry->c; 247 | if (!c) c = ' '; // FIXME improve 248 | vga_print_glyph(i, c, &entry->fg, &entry->bg); 249 | } 250 | } 251 | 252 | // Advance the text cursor, scrolling the video buffer if necessary. 253 | int vga_handle_scrolling(int cursor_offset) { 254 | if (console_fb_addr != NULL) { 255 | if (cursor_offset < MAX_ROWS * MAX_COLS) 256 | return cursor_offset; 257 | 258 | for (int i = 1; i < MAX_ROWS; i++) { 259 | memcpy(console_fb_addr + vga_get_offset(0, i - 1), 260 | console_fb_addr + vga_get_offset(0, i), 261 | MAX_COLS * sizeof(*console_fb_addr)); 262 | } 263 | 264 | memset(console_fb_addr + vga_get_offset(0, MAX_ROWS - 1), 265 | 0, MAX_COLS * sizeof(*console_fb_addr)); 266 | 267 | cursor_offset -= MAX_COLS; 268 | } else if (rgb_fb_addr != NULL) { 269 | if (cursor_offset < rgb_console_rows * rgb_console_cols) 270 | return cursor_offset; 271 | 272 | size_t end_offset = (rgb_console_rows - 1) * rgb_console_cols; 273 | memmove(rgb_console_buffer, rgb_console_buffer + rgb_console_cols, 274 | end_offset * sizeof(rgb_console_buffer_entry_t)); 275 | memset(rgb_console_buffer + end_offset, 0, rgb_console_cols * sizeof(rgb_console_buffer_entry_t)); 276 | cursor_offset -= rgb_console_cols; 277 | vga_console_repaint(); 278 | } 279 | 280 | return cursor_offset; 281 | } -------------------------------------------------------------------------------- /kernel/drivers/vga.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../bmp.h" 5 | 6 | #define MAX_ROWS 25 7 | #define MAX_COLS 80 8 | 9 | // Screen device I/O ports 10 | #define REG_SCREEN_CTRL 0x3D4 11 | #define REG_SCREEN_DATA 0x3D5 12 | 13 | #define VGA_FB_TYPE_INDEXED 0 14 | #define VGA_FB_TYPE_RGB 1 15 | #define VGA_FB_TYPE_EGA_TEXT 2 16 | 17 | typedef struct framebuffer_info { 18 | uint32_t pitch; 19 | uint32_t width; 20 | uint32_t height; 21 | uint8_t bpp; 22 | uint32_t palette_addr; 23 | uint16_t palette_num_colors; 24 | uint8_t red_field_position; 25 | uint8_t red_mask_size; 26 | uint8_t green_field_position; 27 | uint8_t green_mask_size; 28 | uint8_t blue_field_position; 29 | uint8_t blue_mask_size; 30 | } framebuffer_info_t; 31 | 32 | typedef struct vga_rgb_color { 33 | uint8_t red; 34 | uint8_t green; 35 | uint8_t blue; 36 | } vga_rgb_color_t; 37 | 38 | void vga_init(void *fb_addr, uint8_t type, framebuffer_info_t *fb_info); 39 | 40 | int vga_load_font(const char *filename); 41 | 42 | void vga_fill_rect(int x1, int y1, int x2, int y2, vga_rgb_color_t *color); 43 | 44 | void vga_display_image_bgra(int x, int y, bmp_info_header_t *header, uint8_t *image); 45 | 46 | // --- Console 47 | 48 | int vga_print_char(char c, int offset, char attr); 49 | 50 | int vga_handle_scrolling(int cursor_offset); 51 | 52 | int vga_get_cursor_offset(); 53 | 54 | void vga_set_cursor_offset(int offset); 55 | 56 | void vga_clear_screen(); 57 | 58 | enum vga_text_color { 59 | VGA_COLOR_BLACK = 0, 60 | VGA_COLOR_BLUE = 1, 61 | VGA_COLOR_GREEN = 2, 62 | VGA_COLOR_CYAN = 3, 63 | VGA_COLOR_RED = 4, 64 | VGA_COLOR_MAGENTA = 5, 65 | VGA_COLOR_BROWN = 6, 66 | VGA_COLOR_LIGHT_GREY = 7, 67 | VGA_COLOR_DARK_GREY = 8, 68 | VGA_COLOR_LIGHT_BLUE = 9, 69 | VGA_COLOR_LIGHT_GREEN = 10, 70 | VGA_COLOR_LIGHT_CYAN = 11, 71 | VGA_COLOR_LIGHT_RED = 12, 72 | VGA_COLOR_LIGHT_MAGENTA = 13, 73 | VGA_COLOR_LIGHT_BROWN = 14, 74 | VGA_COLOR_WHITE = 15, 75 | }; 76 | typedef enum vga_text_color vga_text_color_t; 77 | 78 | static inline uint8_t vga_entry_color(vga_text_color_t fg, vga_text_color_t bg) { 79 | return fg | bg << 4; 80 | } 81 | 82 | // Attribute byte for our default colour scheme. 83 | #define WHITE_ON_BLACK (vga_entry_color(VGA_COLOR_WHITE, VGA_COLOR_BLACK)) 84 | #define RED_ON_BLACK (vga_entry_color(VGA_COLOR_RED, VGA_COLOR_BLACK)) 85 | #define RED_ON_WHITE (vga_entry_color(VGA_COLOR_RED, VGA_COLOR_WHITE)) 86 | 87 | static inline uint16_t vga_entry(unsigned char uc, uint8_t color) { 88 | return (uint16_t) uc | (uint16_t) color << 8; 89 | } 90 | 91 | static inline int vga_get_offset(int col, int row) { 92 | return row * MAX_COLS + col; 93 | } 94 | 95 | static inline int vga_get_offset_row(int offset) { 96 | return offset / MAX_COLS; 97 | } 98 | 99 | static inline int vga_get_offset_col(int offset) { 100 | return offset - (vga_get_offset_row(offset) * MAX_COLS); 101 | } -------------------------------------------------------------------------------- /kernel/dwarf.c: -------------------------------------------------------------------------------- 1 | #include "dwarf.h" 2 | #include "console.h" 3 | #include "elf.h" 4 | #include "kmalloc.h" 5 | 6 | #include 7 | #include 8 | 9 | void dwarf_find_file(uintptr_t address) { 10 | // FILE *file; 11 | } 12 | 13 | void *dwarf_find_debug_info() { 14 | void *debug_line_ptr = NULL; 15 | // uint32_t read = 0; 16 | 17 | elf_file_t *elf_file; 18 | if ((elf_file = elf_open("kernel.bin")) == NULL) goto fail; 19 | elf_print_sections(elf_file); 20 | 21 | elf_section_header_t *debug_line_section = elf_find_section(elf_file, ".debug_line"); 22 | if (debug_line_section == NULL || debug_line_section->size > UINT16_MAX) goto fail; 23 | 24 | // ret = f_lseek(&file, debug_line_section->offset); 25 | // if (ret != FR_OK) goto fail; 26 | // 27 | // uint16_t debug_line_section_size = (uint16_t) debug_line_section->size; 28 | // kprint("debug_line_section_size = "); kprint_uint16(debug_line_section_size); kprint_char('\n'); 29 | // debug_line_ptr = malloc(debug_line_section_size); 30 | // if (debug_line_ptr == NULL) goto fail; 31 | // 32 | // ret = f_read(&file, debug_line_ptr, debug_line_section_size, &read); 33 | // if (ret != FR_OK || read != debug_line_section_size) goto fail; 34 | // 35 | // dwarf_debug_line_header_t *debug_line_header = debug_line_ptr; 36 | // kprint_uint32(debug_line_header->length); 37 | // kprint_char('\n'); 38 | 39 | goto end; 40 | 41 | fail: 42 | printf("Failed to read DWARF info: %d\n", errno); 43 | 44 | end: 45 | elf_close(elf_file); 46 | kfree(debug_line_ptr); 47 | return NULL; 48 | } -------------------------------------------------------------------------------- /kernel/dwarf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct _packed dwarf_debug_line_header { 6 | uint32_t length; 7 | uint16_t version; 8 | uint32_t header_length; 9 | uint8_t min_instruction_length; 10 | uint8_t default_is_stmt; 11 | int8_t line_base; 12 | uint8_t line_range; 13 | uint8_t opcode_base; 14 | uint8_t std_opcode_lengths[12]; 15 | }; 16 | typedef struct dwarf_debug_line_header dwarf_debug_line_header_t; 17 | 18 | void *dwarf_find_debug_info(); -------------------------------------------------------------------------------- /kernel/elf.c: -------------------------------------------------------------------------------- 1 | #include "elf.h" 2 | #include "console.h" 3 | #include "kmalloc.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | // #define ELF_DEBUG 10 | 11 | bool _check_elf_header(elf_header_t *header) { 12 | if (header->magic == ELF_HEADER_MAGIC_LE) { 13 | if (header->arch_bits != ELF_ARCH_BITS_32) { 14 | return false; 15 | } 16 | if (header->endianness != ELF_ENDIANNESS_LITTLE) { 17 | return false; 18 | } 19 | if (header->machine_type != ELF_IS_X86) { 20 | return false; 21 | } 22 | if (header->header_size > sizeof(elf_header_t)) { 23 | return false; 24 | } 25 | if (header->section_header_entry_size > sizeof(elf_section_header_t)) { 26 | return false; 27 | } 28 | return true; 29 | } else { 30 | return false; 31 | } 32 | } 33 | 34 | static bool _elf_read_header(elf_file_t *file) { 35 | if (file->header != NULL) return true; 36 | if (fseek(file->fd, 0, SEEK_SET)) return false; 37 | 38 | void *buf = NULL; 39 | size_t header_size = sizeof(elf_header_t), read = 0; 40 | if ((buf = kmalloc(header_size)) == NULL) { 41 | errno = ENOMEM; 42 | return false; 43 | } 44 | read = fread(buf, header_size, 1, file->fd); 45 | if (ferror(file->fd) || !read || !_check_elf_header(buf)) { 46 | kfree(buf); 47 | return false; 48 | } 49 | 50 | file->header = buf; 51 | return true; 52 | } 53 | 54 | static bool _elf_read_section_header_table(elf_file_t *file) { 55 | if (file->sht_start != NULL) return true; 56 | if (!_elf_read_header(file)) return false; 57 | 58 | size_t read = 0; 59 | elf_header_t *header = file->header; 60 | if (fseek(file->fd, header->section_header_offset, SEEK_SET)) 61 | return false; 62 | 63 | void *buf = NULL; 64 | uint16_t sh_table_size = header->section_header_entry_size * 65 | header->section_header_num_entries; 66 | if ((buf = kmalloc(sh_table_size)) == NULL) { 67 | errno = ENOMEM; 68 | return false; 69 | } 70 | read = fread(buf, sh_table_size, 1, file->fd); 71 | if (ferror(file->fd) || !read) { 72 | kfree(buf); 73 | return false; 74 | } 75 | 76 | file->sht_start = buf; 77 | return true; 78 | } 79 | 80 | static bool _elf_read_sht_str_section(elf_file_t *file) { 81 | if (file->sht_str_section != NULL) return true; 82 | if (!_elf_read_header(file)) return false; 83 | 84 | elf_header_t *header = file->header; 85 | elf_section_header_t *section_header = elf_get_section(file, header->section_header_section_names_idx); 86 | if (section_header == NULL) return NULL; 87 | file->sht_str_section = elf_read_section(file, section_header); 88 | return file->sht_str_section != NULL; 89 | } 90 | 91 | elf_section_header_t *elf_find_section(elf_file_t *file, const char *name) { 92 | if (!_elf_read_section_header_table(file) 93 | || !_elf_read_sht_str_section(file)) 94 | return NULL; 95 | 96 | uint16_t num_entries = file->header->section_header_num_entries; 97 | for (uint16_t i = 0; i < num_entries; ++i) { 98 | elf_section_header_t *section_header = (void *) file->sht_start + file->header->section_header_entry_size * i; 99 | if (strcmp(name, file->sht_str_section + section_header->name) == 0) return section_header; 100 | } 101 | return NULL; 102 | } 103 | 104 | elf_section_header_t *elf_get_section(elf_file_t *file, 105 | uint16_t index) { 106 | if (!_elf_read_section_header_table(file)) 107 | return NULL; 108 | 109 | uint16_t num_entries = file->header->section_header_num_entries; 110 | if (index > num_entries - 1) return NULL; 111 | return (void *) file->sht_start + file->header->section_header_entry_size * index; 112 | } 113 | 114 | void *elf_read_section(elf_file_t *file, elf_section_header_t *section_header) { 115 | if (!_elf_read_header(file)) return false; 116 | 117 | if (section_header == NULL || 118 | section_header->size > UINT16_MAX || 119 | fseek(file->fd, section_header->offset, SEEK_SET)) 120 | return NULL; 121 | 122 | void *buf = NULL; 123 | uint16_t section_size = (uint16_t) section_header->size; 124 | if ((buf = kmalloc(section_size)) == NULL) { 125 | errno = ENOMEM; 126 | return NULL; 127 | } 128 | if (!fread(buf, section_size, 1, file->fd) || ferror(file->fd)) { 129 | kfree(buf); 130 | return NULL; 131 | } 132 | 133 | return buf; 134 | } 135 | 136 | static const char *elf_section_type(elf_section_header_type_t type) { 137 | switch (type) { 138 | case ELF_SHT_NULL: 139 | return "SHT_NULL"; 140 | case ELF_SHT_PROGBITS: 141 | return "SHT_PROGBITS"; 142 | case ELF_SHT_SYMTAB: 143 | return "SHT_SYMTAB"; 144 | case ELF_SHT_STRTAB: 145 | return "SHT_STRTAB"; 146 | case ELF_SHT_RELA: 147 | return "SHT_RELA"; 148 | case ELF_SHT_HASH: 149 | return "SHT_HASH"; 150 | case ELF_SHT_DYNAMIC: 151 | return "SHT_DYNAMIC"; 152 | case ELF_SHT_NOTE: 153 | return "SHT_NOTE"; 154 | case ELF_SHT_NOBITS: 155 | return "SHT_NOBITS"; 156 | case ELF_SHT_REL: 157 | return "SHT_REL"; 158 | case ELF_SHT_SHLIB: 159 | return "SHT_SHLIB"; 160 | case ELF_SHT_DYNSYM: 161 | return "SHT_DYNSYM"; 162 | case ELF_SHT_LOPROC: 163 | return "SHT_LOPROC"; 164 | case ELF_SHT_HIPROC: 165 | return "SHT_HIPROC"; 166 | case ELF_SHT_LOUSER: 167 | return "SHT_LOUSER"; 168 | case ELF_SHT_HIUSER: 169 | return "SHT_HIUSER"; 170 | default: 171 | return "UNKNOWN"; 172 | } 173 | } 174 | 175 | static const char *elf_obj_type(elf_obj_type_t type) { 176 | switch (type) { 177 | case ELF_ET_NONE: return "None"; 178 | case ELF_ET_REL: return "Relocatable"; 179 | case ELF_ET_EXEC: return "Executable"; 180 | case ELF_ET_DYN: return "Dynamic"; 181 | case ELF_ET_CORE: return "Core"; 182 | default: return "UNKNOWN"; 183 | } 184 | } 185 | 186 | void elf_print_sections(elf_file_t *file) { 187 | if (!_elf_read_header(file) 188 | || !_elf_read_section_header_table(file) 189 | || !_elf_read_sht_str_section(file)) 190 | return; 191 | 192 | elf_header_t *header = file->header; 193 | printf("ELF type: %s\n", elf_obj_type(header->obj_type)); 194 | printf("ELF entry offset: %Xh\n", header->program_entry_offset); 195 | 196 | uint16_t num_entries = header->section_header_num_entries; 197 | for (uint16_t i = 0; i < num_entries; ++i) { 198 | elf_section_header_t *section_header = (void *) file->sht_start + header->section_header_entry_size * i; 199 | if (section_header->type == ELF_SHT_NULL) continue; // Skip null header 200 | printf("Section %03d %s: offset "PRIx32", size "PRIx32", VMA "PRIXUPTR", type %s\n", 201 | i, file->sht_str_section + section_header->name, 202 | section_header->offset, section_header->size, 203 | section_header->address, 204 | elf_section_type(section_header->type)); 205 | } 206 | } 207 | 208 | elf_file_t *elf_open(const char *filename) { 209 | elf_file_t *file = kmalloc(sizeof(elf_file_t)); 210 | if (file == NULL) { 211 | errno = ENOMEM; 212 | return NULL; 213 | } 214 | memset(file, 0, sizeof(elf_file_t)); 215 | 216 | file->fd = fopen(filename, "r"); 217 | if (ferror(file->fd) 218 | || !_elf_read_header(file) 219 | || !_elf_read_section_header_table(file)) { 220 | elf_close(file); 221 | return NULL; 222 | } 223 | 224 | return file; 225 | } 226 | 227 | void elf_close(elf_file_t *file) { 228 | if (file == NULL) return; 229 | if (file->fd != NULL) fclose(file->fd); 230 | kfree(file->header); 231 | kfree(file->sht_start); 232 | kfree(file->sht_str_section); 233 | kfree(file); 234 | } -------------------------------------------------------------------------------- /kernel/elf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #define ELF_HEADER_MAGIC_LE ((uint32_t) 0x7F | 'E' << 8 | 'L' << 16 | 'F' << 24) 7 | 8 | enum elf_header_arch_bits { 9 | ELF_ARCH_BITS_32 = 1, 10 | ELF_ARCH_BITS_64 = 2 11 | }; 12 | typedef enum elf_header_arch_bits elf_header_arch_bits_t; 13 | 14 | static_assert(sizeof(elf_header_arch_bits_t) == sizeof(uint8_t), 15 | "elf_header_arch_bits too large"); 16 | 17 | enum elf_header_endianness { 18 | ELF_ENDIANNESS_LITTLE = 1, 19 | ELF_ENDIANNESS_BIG = 2 20 | }; 21 | typedef enum elf_header_endianness elf_header_endianness_t; 22 | 23 | static_assert(sizeof(elf_header_endianness_t) == sizeof(uint8_t), 24 | "elf_header_endianness too large"); 25 | 26 | enum elf_machine_type { 27 | ELF_IS_NONE = 0, 28 | ELF_IS_SPARC = 2, 29 | ELF_IS_X86 = 3, 30 | ELF_IS_MIPS = 8, 31 | ELF_IS_POWERPC = 0x14, 32 | ELF_IS_ARM = 0x28, 33 | ELF_IS_SUPERH = 0x2A, 34 | ELF_IS_IA_64 = 0x32, 35 | ELF_IS_X86_64 = 0x3E, 36 | ELF_IS_AARCH64 = 0xB7, 37 | 38 | // uint16_t padding 39 | __ELF_IS_UNUSED = 0x100 40 | }; 41 | typedef enum elf_machine_type elf_machine_type_t; 42 | 43 | static_assert(sizeof(elf_machine_type_t) == sizeof(uint16_t), 44 | "elf_machine_type incorrect size"); 45 | 46 | enum elf_obj_type { 47 | ELF_ET_NONE = 0, // No file type 48 | ELF_ET_REL = 1, // Relocatable file 49 | ELF_ET_EXEC = 2, // Executable file 50 | ELF_ET_DYN = 3, // Shared object file (& PIE executables) 51 | ELF_ET_CORE = 4, // Core file 52 | ELF_ET_LOPROC = 0xFF00, 53 | ELF_ET_HIPROC = 0xFFFF 54 | }; 55 | typedef enum elf_obj_type elf_obj_type_t; 56 | 57 | static_assert(sizeof(elf_obj_type_t) == sizeof(uint16_t), 58 | "elf_obj_type incorrect size"); 59 | 60 | struct _packed elf_header { 61 | uint32_t magic; 62 | elf_header_arch_bits_t arch_bits; 63 | elf_header_endianness_t endianness; 64 | uint8_t elf_version; 65 | uint8_t __padding[9]; 66 | elf_obj_type_t obj_type; 67 | elf_machine_type_t machine_type; 68 | uint32_t version; // ????? 69 | uint32_t program_entry_offset; 70 | uint32_t program_header_offset; 71 | uint32_t section_header_offset; 72 | uint32_t flags; // unused on x86 73 | uint16_t header_size; 74 | uint16_t program_header_entry_size; 75 | uint16_t program_header_num_entries; 76 | uint16_t section_header_entry_size; 77 | uint16_t section_header_num_entries; 78 | uint16_t section_header_section_names_idx; 79 | }; 80 | typedef struct elf_header elf_header_t; 81 | 82 | static_assert(sizeof(elf_header_t) == 52, 83 | "elf_header incorrect size"); 84 | 85 | enum elf_section_header_type { 86 | ELF_SHT_NULL = 0, // Unused 87 | ELF_SHT_PROGBITS = 1, // Program bits 88 | ELF_SHT_SYMTAB = 2, // Symbol table 89 | ELF_SHT_STRTAB = 3, // String table 90 | ELF_SHT_RELA = 4, // Relocation entries w/ explicit addends 91 | ELF_SHT_HASH = 5, // Symbol hash table 92 | ELF_SHT_DYNAMIC = 6, // Dynamic linking information 93 | ELF_SHT_NOTE = 7, // Auxiliary information 94 | ELF_SHT_NOBITS = 8, // Program bits with zero size in file 95 | ELF_SHT_REL = 9, // Relocation entries w/o explicit addends 96 | ELF_SHT_SHLIB = 10, // Reserved 97 | ELF_SHT_DYNSYM = 11, // Dynamic symbol table 98 | ELF_SHT_LOPROC = 0x70000000, 99 | ELF_SHT_HIPROC = 0x7FFFFFFF, 100 | ELF_SHT_LOUSER = 0x80000000, 101 | ELF_SHT_HIUSER = 0xFFFFFFFF, 102 | }; 103 | typedef enum elf_section_header_type elf_section_header_type_t; 104 | 105 | static_assert(sizeof(elf_section_header_type_t) == sizeof(uint32_t), 106 | "elf_section_header_type incorrect size"); 107 | 108 | struct _packed elf_section_header { 109 | uint32_t name; // name offset in string section 110 | elf_section_header_type_t type; 111 | uint32_t flags; // flags 112 | uint32_t address; // virtual address 113 | uint32_t offset; // offset from beginning of file 114 | uint32_t size; // section size in bytes 115 | uint32_t link; // index link (?) 116 | uint32_t info; // extra info 117 | uint32_t address_align; // 0 or 1 = no alignment constraint 118 | uint32_t entity_size; // 0 = not fixed-size 119 | }; 120 | typedef struct elf_section_header elf_section_header_t; 121 | 122 | //static_assert(sizeof(elf_section_header_t) == 32, 123 | // "elf_section_header incorrect size"); 124 | 125 | enum elf_program_header_type { 126 | ELF_PT_NULL = 0, // Unused 127 | ELF_PT_LOAD = 1, // Loadable segment 128 | ELF_PT_DYNAMIC = 2, // Dynamic linking information 129 | ELF_PT_INTERP = 3, // Interpreter 130 | ELF_PT_NOTE = 4, // Auxiliary information 131 | ELF_PT_SHLIB = 5, // Reserved 132 | ELF_PT_PHDR = 6, // Program header table 133 | ELF_PT_LOPROC = 0x70000000, 134 | ELF_PT_HIPROC = 0x7FFFFFFF 135 | }; 136 | typedef enum elf_program_header_type elf_program_header_type_t; 137 | 138 | struct _packed elf_program_header { 139 | elf_program_header_type_t type; 140 | uint32_t offset; // Offset from start of file 141 | uint32_t vaddr; // Virtual address 142 | uint32_t paddr; // Physical address (ignored?) 143 | uint32_t file_size; // Size in file 144 | uint32_t memory_size; // Size in memory 145 | uint32_t flags; // ? 146 | uint32_t align; // Memory alignment 147 | }; 148 | typedef struct elf_program_header elf_program_header_t; 149 | 150 | struct elf_file { 151 | FILE *fd; 152 | elf_header_t *header; 153 | elf_section_header_t *sht_start; 154 | char *sht_str_section; 155 | }; 156 | typedef struct elf_file elf_file_t; 157 | 158 | // --- Public 159 | 160 | elf_section_header_t *elf_find_section(elf_file_t *file, const char *name); 161 | 162 | elf_section_header_t *elf_get_section(elf_file_t *file, uint16_t index); 163 | 164 | void *elf_read_section(elf_file_t *file, elf_section_header_t *section_header); 165 | 166 | void elf_print_sections(elf_file_t *file); 167 | 168 | elf_file_t *elf_open(const char *filename); 169 | 170 | void elf_close(elf_file_t *file); -------------------------------------------------------------------------------- /kernel/fatfs/00readme.txt: -------------------------------------------------------------------------------- 1 | FatFs Module Source Files R0.13b 2 | 3 | 4 | FILES 5 | 6 | 00readme.txt This file. 7 | 00history.txt Revision history. 8 | ff.c FatFs module. 9 | ffconf.h Configuration file of FatFs module. 10 | ff.h Common include file for FatFs and application module. 11 | diskio.h Common include file for FatFs and disk I/O module. 12 | diskio.c An example of glue function to attach existing disk I/O module to FatFs. 13 | integer.h Integer type definitions for FatFs. 14 | ffunicode.c Optional Unicode utility functions. 15 | ffsystem.c An example of optional O/S related functions. 16 | 17 | 18 | Low level disk I/O module is not included in this archive because the FatFs 19 | module is only a generic file system layer and it does not depend on any specific 20 | storage device. You need to provide a low level disk I/O module written to 21 | control the storage device that attached to the target system. 22 | 23 | -------------------------------------------------------------------------------- /kernel/fatfs/diskio.c: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------*/ 2 | /* Low level disk I/O module skeleton for FatFs (C)ChaN, 2016 */ 3 | /*-----------------------------------------------------------------------*/ 4 | /* If a working storage control module is available, it should be */ 5 | /* attached to the FatFs via a glue function rather than modifying it. */ 6 | /* This is an example of glue functions to attach various exsisting */ 7 | /* storage control modules to the FatFs module with a defined API. */ 8 | /*-----------------------------------------------------------------------*/ 9 | 10 | #include "diskio.h" /* FatFs lower layer API */ 11 | #include "../drivers/ata.h" 12 | 13 | #include 14 | 15 | /*-----------------------------------------------------------------------*/ 16 | /* Get Drive Status */ 17 | /*-----------------------------------------------------------------------*/ 18 | 19 | DSTATUS disk_status( 20 | BYTE pdrv /* Physical drive nmuber to identify the drive */ 21 | ) { 22 | if (pdrv < 3 && ide_devices[pdrv].reserved) { 23 | return 0; 24 | } 25 | return STA_NODISK; 26 | } 27 | 28 | /*-----------------------------------------------------------------------*/ 29 | /* Inidialize a Drive */ 30 | /*-----------------------------------------------------------------------*/ 31 | 32 | DSTATUS disk_initialize( 33 | BYTE pdrv /* Physical drive nmuber to identify the drive */ 34 | ) { 35 | if (pdrv < 3 && ide_devices[pdrv].reserved) { 36 | return 0; 37 | } 38 | return STA_NODISK; 39 | } 40 | 41 | /*-----------------------------------------------------------------------*/ 42 | /* Read Sector(s) */ 43 | /*-----------------------------------------------------------------------*/ 44 | 45 | DRESULT disk_read( 46 | BYTE pdrv, /* Physical drive nmuber to identify the drive */ 47 | BYTE *buff, /* Data buffer to store read data */ 48 | DWORD sector, /* Start sector in LBA */ 49 | UINT count /* Number of sectors to read */ 50 | ) { 51 | if (pdrv < 3 && ide_devices[pdrv].reserved) { 52 | if (ide_ata_access(0, pdrv, sector, (uint8_t) count, 0, (uintptr_t) buff)) { 53 | return RES_ERROR; 54 | } 55 | return RES_OK; 56 | } 57 | return RES_PARERR; 58 | } 59 | 60 | /*-----------------------------------------------------------------------*/ 61 | /* Write Sector(s) */ 62 | /*-----------------------------------------------------------------------*/ 63 | 64 | DRESULT disk_write( 65 | BYTE pdrv, /* Physical drive nmuber to identify the drive */ 66 | const BYTE *buff, /* Data to be written */ 67 | DWORD sector, /* Start sector in LBA */ 68 | UINT count /* Number of sectors to write */ 69 | ) { 70 | if (pdrv < 3 && ide_devices[pdrv].reserved) { 71 | if (ide_ata_access(1, pdrv, sector, (uint8_t) count, 0, (uintptr_t) buff)) { 72 | return RES_ERROR; 73 | } 74 | return RES_OK; 75 | } 76 | return RES_WRPRT; 77 | } 78 | 79 | /*-----------------------------------------------------------------------*/ 80 | /* Miscellaneous Functions */ 81 | /*-----------------------------------------------------------------------*/ 82 | 83 | DRESULT disk_ioctl( 84 | BYTE pdrv, /* Physical drive nmuber (0..) */ 85 | BYTE cmd, /* Control code */ 86 | void *buff /* Buffer to send/receive control data */ 87 | ) { 88 | // TODO 89 | // printf("disk_ioctl: unimplemented %d\n", pdrv); 90 | return RES_OK; 91 | } 92 | 93 | -------------------------------------------------------------------------------- /kernel/fatfs/diskio.h: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------/ 2 | / Low level disk interface modlue include file (C)ChaN, 2014 / 3 | /-----------------------------------------------------------------------*/ 4 | 5 | #ifndef _DISKIO_DEFINED 6 | #define _DISKIO_DEFINED 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #include "integer.h" 13 | 14 | 15 | /* Status of Disk Functions */ 16 | typedef BYTE DSTATUS; 17 | 18 | /* Results of Disk Functions */ 19 | typedef enum { 20 | RES_OK = 0, /* 0: Successful */ 21 | RES_ERROR, /* 1: R/W Error */ 22 | RES_WRPRT, /* 2: Write Protected */ 23 | RES_NOTRDY, /* 3: Not Ready */ 24 | RES_PARERR /* 4: Invalid Parameter */ 25 | } DRESULT; 26 | 27 | 28 | /*---------------------------------------*/ 29 | /* Prototypes for disk control functions */ 30 | 31 | 32 | DSTATUS disk_initialize (BYTE pdrv); 33 | DSTATUS disk_status (BYTE pdrv); 34 | DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); 35 | DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); 36 | DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); 37 | 38 | 39 | /* Disk Status Bits (DSTATUS) */ 40 | 41 | #define STA_NOINIT 0x01 /* Drive not initialized */ 42 | #define STA_NODISK 0x02 /* No medium in the drive */ 43 | #define STA_PROTECT 0x04 /* Write protected */ 44 | 45 | 46 | /* Command code for disk_ioctrl fucntion */ 47 | 48 | /* Generic command (Used by FatFs) */ 49 | #define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ 50 | #define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ 51 | #define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ 52 | #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ 53 | #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ 54 | 55 | /* Generic command (Not used by FatFs) */ 56 | #define CTRL_POWER 5 /* Get/Set power status */ 57 | #define CTRL_LOCK 6 /* Lock/Unlock media removal */ 58 | #define CTRL_EJECT 7 /* Eject media */ 59 | #define CTRL_FORMAT 8 /* Create physical format on the media */ 60 | 61 | /* MMC/SDC specific ioctl command */ 62 | #define MMC_GET_TYPE 10 /* Get card type */ 63 | #define MMC_GET_CSD 11 /* Get CSD */ 64 | #define MMC_GET_CID 12 /* Get CID */ 65 | #define MMC_GET_OCR 13 /* Get OCR */ 66 | #define MMC_GET_SDSTAT 14 /* Get SD status */ 67 | #define ISDIO_READ 55 /* Read data form SD iSDIO register */ 68 | #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ 69 | #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ 70 | 71 | /* ATA/CF specific ioctl command */ 72 | #define ATA_GET_REV 20 /* Get F/W revision */ 73 | #define ATA_GET_MODEL 21 /* Get model name */ 74 | #define ATA_GET_SN 22 /* Get serial number */ 75 | 76 | #ifdef __cplusplus 77 | } 78 | #endif 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /kernel/fatfs/ffsystem.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------*/ 2 | /* Sample Code of OS Dependent Functions for FatFs */ 3 | /* (C)ChaN, 2017 */ 4 | /*------------------------------------------------------------------------*/ 5 | 6 | 7 | #include "ff.h" 8 | #include "../kmalloc.h" 9 | 10 | #if FF_USE_LFN == 3 /* Dynamic memory allocation */ 11 | 12 | /*------------------------------------------------------------------------*/ 13 | /* Allocate a memory block */ 14 | /*------------------------------------------------------------------------*/ 15 | 16 | void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on not enough core) */ 17 | UINT msize /* Number of bytes to allocate */ 18 | ) 19 | { 20 | return kmalloc(msize); /* Allocate a new memory block with POSIX API */ 21 | } 22 | 23 | 24 | /*------------------------------------------------------------------------*/ 25 | /* Free a memory block */ 26 | /*------------------------------------------------------------------------*/ 27 | 28 | void ff_memfree ( 29 | void* mblock /* Pointer to the memory block to free (nothing to do for null) */ 30 | ) 31 | { 32 | kfree(mblock); /* Free the memory block with POSIX API */ 33 | } 34 | 35 | #endif 36 | 37 | 38 | 39 | #if FF_FS_REENTRANT /* Mutal exclusion */ 40 | 41 | /*------------------------------------------------------------------------*/ 42 | /* Create a Synchronization Object */ 43 | /*------------------------------------------------------------------------*/ 44 | /* This function is called in f_mount() function to create a new 45 | / synchronization object for the volume, such as semaphore and mutex. 46 | / When a 0 is returned, the f_mount() function fails with FR_INT_ERR. 47 | */ 48 | 49 | //const osMutexDef_t Mutex[FF_VOLUMES]; /* CMSIS-RTOS */ 50 | 51 | 52 | int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ 53 | BYTE vol, /* Corresponding volume (logical drive number) */ 54 | FF_SYNC_t* sobj /* Pointer to return the created sync object */ 55 | ) 56 | { 57 | /* Win32 */ 58 | *sobj = CreateMutex(NULL, FALSE, NULL); 59 | return (int)(*sobj != INVALID_HANDLE_VALUE); 60 | 61 | /* uITRON */ 62 | // T_CSEM csem = {TA_TPRI,1,1}; 63 | // *sobj = acre_sem(&csem); 64 | // return (int)(*sobj > 0); 65 | 66 | /* uC/OS-II */ 67 | // OS_ERR err; 68 | // *sobj = OSMutexCreate(0, &err); 69 | // return (int)(err == OS_NO_ERR); 70 | 71 | /* FreeRTOS */ 72 | // *sobj = xSemaphoreCreateMutex(); 73 | // return (int)(*sobj != NULL); 74 | 75 | /* CMSIS-RTOS */ 76 | // *sobj = osMutexCreate(Mutex + vol); 77 | // return (int)(*sobj != NULL); 78 | } 79 | 80 | 81 | /*------------------------------------------------------------------------*/ 82 | /* Delete a Synchronization Object */ 83 | /*------------------------------------------------------------------------*/ 84 | /* This function is called in f_mount() function to delete a synchronization 85 | / object that created with ff_cre_syncobj() function. When a 0 is returned, 86 | / the f_mount() function fails with FR_INT_ERR. 87 | */ 88 | 89 | int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */ 90 | FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ 91 | ) 92 | { 93 | /* Win32 */ 94 | return (int)CloseHandle(sobj); 95 | 96 | /* uITRON */ 97 | // return (int)(del_sem(sobj) == E_OK); 98 | 99 | /* uC/OS-II */ 100 | // OS_ERR err; 101 | // OSMutexDel(sobj, OS_DEL_ALWAYS, &err); 102 | // return (int)(err == OS_NO_ERR); 103 | 104 | /* FreeRTOS */ 105 | // vSemaphoreDelete(sobj); 106 | // return 1; 107 | 108 | /* CMSIS-RTOS */ 109 | // return (int)(osMutexDelete(sobj) == osOK); 110 | } 111 | 112 | 113 | /*------------------------------------------------------------------------*/ 114 | /* Request Grant to Access the Volume */ 115 | /*------------------------------------------------------------------------*/ 116 | /* This function is called on entering file functions to lock the volume. 117 | / When a 0 is returned, the file function fails with FR_TIMEOUT. 118 | */ 119 | 120 | int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */ 121 | FF_SYNC_t sobj /* Sync object to wait */ 122 | ) 123 | { 124 | /* Win32 */ 125 | return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0); 126 | 127 | /* uITRON */ 128 | // return (int)(wai_sem(sobj) == E_OK); 129 | 130 | /* uC/OS-II */ 131 | // OS_ERR err; 132 | // OSMutexPend(sobj, FF_FS_TIMEOUT, &err)); 133 | // return (int)(err == OS_NO_ERR); 134 | 135 | /* FreeRTOS */ 136 | // return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE); 137 | 138 | /* CMSIS-RTOS */ 139 | // return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK); 140 | } 141 | 142 | 143 | /*------------------------------------------------------------------------*/ 144 | /* Release Grant to Access the Volume */ 145 | /*------------------------------------------------------------------------*/ 146 | /* This function is called on leaving file functions to unlock the volume. 147 | */ 148 | 149 | void ff_rel_grant ( 150 | FF_SYNC_t sobj /* Sync object to be signaled */ 151 | ) 152 | { 153 | /* Win32 */ 154 | ReleaseMutex(sobj); 155 | 156 | /* uITRON */ 157 | // sig_sem(sobj); 158 | 159 | /* uC/OS-II */ 160 | // OSMutexPost(sobj); 161 | 162 | /* FreeRTOS */ 163 | // xSemaphoreGive(sobj); 164 | 165 | /* CMSIS-RTOS */ 166 | // osMutexRelease(sobj); 167 | } 168 | 169 | #endif 170 | 171 | -------------------------------------------------------------------------------- /kernel/fatfs/integer.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------*/ 2 | /* Integer type definitions for FatFs module */ 3 | /*-------------------------------------------*/ 4 | 5 | #ifndef FF_INTEGER 6 | #define FF_INTEGER 7 | 8 | #include 9 | 10 | #ifdef _WIN32 /* FatFs development platform */ 11 | 12 | #include 13 | typedef unsigned __int64 QWORD; 14 | 15 | #else /* Embedded platform */ 16 | 17 | /* These types MUST be 16-bit or 32-bit */ 18 | typedef int32_t INT; 19 | typedef uint32_t UINT; 20 | 21 | /* This type MUST be 8-bit */ 22 | typedef uint8_t BYTE; 23 | 24 | /* These types MUST be 16-bit */ 25 | typedef int16_t SHORT; 26 | typedef uint16_t WORD; 27 | typedef uint16_t WCHAR; 28 | 29 | /* These types MUST be 32-bit */ 30 | typedef int32_t LONG; 31 | typedef uint32_t DWORD; 32 | 33 | /* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */ 34 | typedef uint64_t QWORD; 35 | 36 | #endif 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /kernel/gdt.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | [GLOBAL gdt_flush] ; Allows the C code to call gdt_flush(). 3 | [GLOBAL idt_flush] ; Allows the C code to call idt_flush(). 4 | 5 | gdt_flush: 6 | mov eax, [esp+4] ; Get the pointer to the GDT, passed as a parameter. 7 | lgdt [eax] ; Load the new GDT pointer 8 | 9 | mov ax, 0x10 ; 0x10 is the offset in the GDT to our data segment 10 | mov ds, ax ; Load all data segment selectors 11 | mov es, ax 12 | mov fs, ax 13 | mov gs, ax 14 | mov ss, ax 15 | jmp 0x08:.flush ; 0x08 is the offset to our code segment: Far jump! 16 | .flush: 17 | ret 18 | 19 | idt_flush: 20 | mov eax, [esp+4] ; Get the pointer to the IDT, passed as a parameter. 21 | lidt [eax] ; Load the IDT pointer. 22 | ret -------------------------------------------------------------------------------- /kernel/interrupt.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | extern isr_handler 3 | extern irq_handler 4 | 5 | %macro ISR_NOERRCODE 1 6 | global isr%1 7 | isr%1: 8 | cli 9 | push byte 0 10 | push byte %1 11 | jmp isr_common_stub 12 | %endmacro 13 | 14 | %macro ISR_ERRCODE 1 15 | global isr%1 16 | isr%1: 17 | cli 18 | push byte %1 19 | jmp isr_common_stub 20 | %endmacro 21 | 22 | %macro IRQ 2 23 | global irq%1 24 | irq%1: 25 | cli 26 | push byte 0 27 | push byte %2 28 | jmp irq_common_stub 29 | %endmacro 30 | 31 | ISR_NOERRCODE 0 32 | ISR_NOERRCODE 1 33 | ISR_NOERRCODE 2 34 | ISR_NOERRCODE 3 35 | ISR_NOERRCODE 4 36 | ISR_NOERRCODE 5 37 | ISR_NOERRCODE 6 38 | ISR_NOERRCODE 7 39 | ISR_ERRCODE 8 40 | ISR_NOERRCODE 9 41 | ISR_ERRCODE 10 42 | ISR_ERRCODE 11 43 | ISR_ERRCODE 12 44 | ISR_ERRCODE 13 45 | ISR_ERRCODE 14 46 | ISR_NOERRCODE 15 47 | ISR_NOERRCODE 16 48 | ISR_NOERRCODE 17 49 | ISR_NOERRCODE 18 50 | ISR_NOERRCODE 19 51 | ISR_NOERRCODE 20 52 | ISR_NOERRCODE 21 53 | ISR_NOERRCODE 22 54 | ISR_NOERRCODE 23 55 | ISR_NOERRCODE 24 56 | ISR_NOERRCODE 25 57 | ISR_NOERRCODE 26 58 | ISR_NOERRCODE 27 59 | ISR_NOERRCODE 28 60 | ISR_NOERRCODE 29 61 | ISR_NOERRCODE 30 62 | ISR_NOERRCODE 31 63 | 64 | IRQ 0, 32 65 | IRQ 1, 33 66 | IRQ 2, 34 67 | IRQ 3, 35 68 | IRQ 4, 36 69 | IRQ 5, 37 70 | IRQ 6, 38 71 | IRQ 7, 39 72 | IRQ 8, 40 73 | IRQ 9, 41 74 | IRQ 10, 42 75 | IRQ 11, 43 76 | IRQ 12, 44 77 | IRQ 13, 45 78 | IRQ 14, 46 79 | IRQ 15, 47 80 | 81 | isr_common_stub: 82 | pusha ; push edi, esi, ebp, esp, ebx, edx, ecx, eax 83 | 84 | ; push mxcsr 85 | sub esp, 4 86 | stmxcsr [esp] 87 | 88 | ; push cr2 89 | mov eax, cr2 90 | push eax 91 | 92 | call isr_handler 93 | 94 | ; discard cr2 95 | add esp, 4 96 | 97 | ; restore mxcsr 98 | ldmxcsr [esp] 99 | add esp, 4 100 | 101 | popa ; pop edi, esi, ebp, esp, ebx, edx, ecx, eax 102 | add esp, 8 ; discard error code and ISR number 103 | sti ; re-enable interrupts 104 | iret ; restore cs, eip, eflags, ss, esp 105 | 106 | irq_common_stub: 107 | pusha ; push edi, esi, ebp, esp, ebx, edx, ecx, eax 108 | 109 | ; push mxcsr 110 | sub esp, 4 111 | stmxcsr [esp] 112 | 113 | ; push cr2 114 | mov eax, cr2 115 | push eax 116 | 117 | call irq_handler 118 | 119 | ; discard cr2 120 | add esp, 4 121 | 122 | ; restore mxcsr 123 | ldmxcsr [esp] 124 | add esp, 4 125 | 126 | popa ; pop edi, esi, ebp, esp, ebx, edx, ecx, eax 127 | add esp, 8 ; discard error code and IRQ number 128 | sti ; re-enable interrupts 129 | iret ; restore cs, eip, eflags, ss, esp -------------------------------------------------------------------------------- /kernel/isr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "isr.h" 3 | #include "console.h" 4 | #include "drivers/ports.h" 5 | 6 | isr_t interrupt_handlers[256] = {}; 7 | 8 | void register_interrupt_handler(uint8_t n, isr_t handler) { 9 | interrupt_handlers[n] = handler; 10 | } 11 | 12 | _unused 13 | void isr_handler(registers_t regs) { 14 | panic("Received interrupt: %lu (err: %Xh, CR2 %Xh) @ %P\n", 15 | regs.int_no, regs.err_code, regs.cr2, (uintptr_t) regs.eip); 16 | } 17 | 18 | _unused 19 | void irq_handler(registers_t regs) { 20 | isr_t handler = interrupt_handlers[regs.int_no]; 21 | if (handler) handler(regs); 22 | 23 | // Send an EOI (end of interrupt) signal to the PICs. 24 | // If this interrupt involved the slave. 25 | if (regs.int_no >= IRQ8) { 26 | // Send reset signal to slave. 27 | port_byte_out(I86_PIC2_REG_COMMAND, I86_PIC_OCW2_MASK_EOI); 28 | } 29 | // Send reset signal to master. (As well as slave, if necessary). 30 | port_byte_out(I86_PIC1_REG_COMMAND, I86_PIC_OCW2_MASK_EOI); 31 | } -------------------------------------------------------------------------------- /kernel/isr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define IRQ0 32 // Timer 6 | #define IRQ1 33 // Keyboard 7 | #define IRQ2 34 // Cascade for 8259A Slave controller 8 | #define IRQ3 35 // Serial port 2 9 | #define IRQ4 36 // Serial port 1 10 | #define IRQ5 37 // AT systems: Parallel Port 2. PS/2 systems: reserved 11 | #define IRQ6 38 // Diskette drive 12 | #define IRQ7 39 // Parallel Port 1 13 | #define IRQ8 40 // CMOS Real time clock 14 | #define IRQ9 41 // CGA vertical retrace 15 | #define IRQ10 42 // Reserved 16 | #define IRQ11 43 // Reserved 17 | #define IRQ12 44 // AT systems: reserved. PS/2: auxiliary device 18 | #define IRQ13 45 // FPU 19 | #define IRQ14 46 // Hard disk controller 20 | #define IRQ15 47 // Reserved 21 | 22 | #define I86_PIC1_REG_COMMAND 0x20 // command register 23 | #define I86_PIC1_REG_STATUS 0x20 // status register 24 | #define I86_PIC1_REG_DATA 0x21 // data register 25 | #define I86_PIC1_REG_IMR 0x21 // interrupt mask register (imr) 26 | 27 | #define I86_PIC2_REG_COMMAND 0xA0 28 | #define I86_PIC2_REG_STATUS 0xA0 29 | #define I86_PIC2_REG_DATA 0xA1 30 | #define I86_PIC2_REG_IMR 0xA1 31 | 32 | #define I86_PIC_OCW2_MASK_L1 1 //00000001 //Level 1 interrupt level 33 | #define I86_PIC_OCW2_MASK_L2 2 //00000010 //Level 2 interrupt level 34 | #define I86_PIC_OCW2_MASK_L3 4 //00000100 //Level 3 interrupt level 35 | #define I86_PIC_OCW2_MASK_EOI 0x20 //00100000 //End of Interrupt command 36 | #define I86_PIC_OCW2_MASK_SL 0x40 //01000000 //Select command 37 | #define I86_PIC_OCW2_MASK_ROTATE 0x80 //10000000 //Rotation command 38 | 39 | typedef struct registers { 40 | uint32_t cr2, mxcsr; 41 | uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha. 42 | uint32_t int_no, err_code; // Interrupt number and error code (if applicable) 43 | uint32_t eip, cs, eflags, useresp, ss; // Pushed by the processor automatically. 44 | } registers_t; 45 | 46 | // Enables registration of callbacks for interrupts or IRQs. 47 | // For IRQs, to ease confusion, use the #defines above as the 48 | // first parameter. 49 | typedef void (*isr_t)(registers_t); 50 | 51 | void register_interrupt_handler(uint8_t n, isr_t handler); -------------------------------------------------------------------------------- /kernel/kmalloc.c: -------------------------------------------------------------------------------- 1 | #include "kmalloc.h" 2 | #include "stdio.h" 3 | #include "console.h" 4 | #include "arch/x86/mmu.h" 5 | 6 | #include 7 | #include 8 | 9 | #define MALLOC_DEBUG 10 | 11 | #define PAGE_SIZE 0x400000 12 | uintptr_t mmap_end = 0; 13 | void *start_chunk; 14 | 15 | // Initialized from multiboot 16 | void *malloc_memory_start = NULL; 17 | void *malloc_memory_end = NULL; 18 | static bool initial_alloc = true; 19 | 20 | typedef struct chunk_header chunk_header_t; 21 | 22 | struct chunk_header { 23 | chunk_header_t *next; 24 | chunk_header_t *prev; 25 | size_t size; 26 | unsigned short used; 27 | }; 28 | 29 | static_assert(sizeof(chunk_header_t) % 4 == 0, "chunk_header is misaligned"); 30 | 31 | static int try_reclaim(chunk_header_t *start, size_t size) { 32 | chunk_header_t *current_chunk = start; 33 | if (current_chunk->next == NULL) return false; 34 | 35 | size_t unused = current_chunk->size; 36 | current_chunk = current_chunk->next; 37 | while (!current_chunk->used) { 38 | chunk_header_t *next_chunk = current_chunk->next; 39 | if (next_chunk == NULL) { 40 | return 2; // Hit end of chunks 41 | } 42 | 43 | unused += (uintptr_t) next_chunk - (uintptr_t) current_chunk; 44 | // FIXME do i need ALIGN here? 45 | if (unused >= ALIGN(size, 4) + sizeof(chunk_header_t)) { 46 | next_chunk->prev = start; 47 | start->next = next_chunk; 48 | return 1; 49 | } 50 | current_chunk = next_chunk; 51 | } 52 | return 0; 53 | } 54 | 55 | static bool ensure_pages(void *new_end) { 56 | uintptr_t phys_end = (uintptr_t) virt_to_phys(new_end); 57 | fprintf(serial, "Ensuring pages up to %P -> %P\n", new_end, phys_end); 58 | while (mmap_end < phys_end) { 59 | uintptr_t next_page = mmap_end; 60 | if (next_page == 0) { 61 | next_page = ALIGN((uintptr_t) malloc_memory_start, PAGE_SIZE); 62 | } 63 | if (next_page + PAGE_SIZE > (uintptr_t) malloc_memory_end) { 64 | // Oops, out of memory 65 | return false; 66 | } 67 | page_table_set(next_page, (uintptr_t) phys_to_virt((void *) next_page), 0x83); 68 | mmap_end = next_page + PAGE_SIZE; 69 | } 70 | return true; 71 | } 72 | 73 | static chunk_header_t *find_unused_chunk(const size_t chunk_size) { 74 | if (initial_alloc) { 75 | if (malloc_memory_start == NULL) 76 | return NULL; 77 | 78 | start_chunk = phys_to_virt((void *) ALIGN((uintptr_t) malloc_memory_start, PAGE_SIZE)); 79 | ensure_pages(start_chunk + sizeof(chunk_header_t) + chunk_size); 80 | 81 | initial_alloc = false; 82 | 83 | // First chunk @ start of memory 84 | #ifdef MALLOC_DEBUG 85 | fprintf(serial, "new chunk @ start: %zu\n", chunk_size); 86 | #endif 87 | chunk_header_t *header = start_chunk; 88 | memset(header, 0, sizeof(chunk_header_t)); 89 | return header; 90 | } 91 | 92 | chunk_header_t *header = start_chunk; 93 | while (true) { 94 | if (!header->used) { 95 | if (header->size >= chunk_size) { 96 | // Unused chunk is large enough, go ahead and use it 97 | #ifdef MALLOC_DEBUG 98 | fprintf(serial, "reusing large enough chunk %P, %zu > %zu\n", header, header->size, chunk_size); 99 | #endif 100 | return header; 101 | } 102 | int ret = try_reclaim(header, chunk_size); 103 | if (ret == 1) { 104 | // There's a next chunk, and we were able to reclaim enough unused space 105 | return header; 106 | } else if (ret == 2) { 107 | // We hit the end of allocated chunks, so do some housekeeping 108 | if (header->prev != NULL) { 109 | header->prev->next = NULL; 110 | header = header->prev; 111 | } else { 112 | // Should not be true, unless something crazy happened 113 | header->next = NULL; 114 | } 115 | } 116 | } 117 | 118 | // Allocate new chunk if end 119 | if (header->next == NULL) { 120 | void *next = (void *) header + sizeof(chunk_header_t) + ALIGN(header->size, 4); 121 | if (!ensure_pages(next + chunk_size + sizeof(chunk_header_t))) return NULL; 122 | #ifdef MALLOC_DEBUG 123 | fprintf(serial, "alloc new chunk %P size: %zu\n", next, chunk_size); 124 | #endif 125 | 126 | chunk_header_t *next_header = memset(next, 0, sizeof(chunk_header_t)); 127 | header->next = next_header; 128 | next_header->prev = header; 129 | return next; 130 | } 131 | 132 | // Find space in between chunks 133 | uintptr_t end_of_chunk = (uintptr_t) header + sizeof(chunk_header_t) + ALIGN(header->size, 4); 134 | if (end_of_chunk > (uintptr_t) header->next) { 135 | panic("kmalloc: misaligned chunk %P (size %zu). Expected end: %P, actual next: %P\n", 136 | header, header->size, end_of_chunk, header->next); 137 | } 138 | uintptr_t unused_size = (uintptr_t) header->next - end_of_chunk; 139 | if (unused_size > chunk_size + sizeof(chunk_header_t)) { 140 | #ifdef MALLOC_DEBUG 141 | fprintf(serial, "found size between chunk: %zu > %zu\n", unused_size, chunk_size); 142 | fprintf(serial, " chunk 1: %P (size %zu) | chunk 2: %P\n", header, header->size, header->next); 143 | #endif 144 | chunk_header_t *next_header = (chunk_header_t *) end_of_chunk; 145 | memset(next_header, 0, sizeof(chunk_header_t)); 146 | next_header->next = header->next; 147 | next_header->prev = header; 148 | header->next->prev = next_header; 149 | header->next = next_header; 150 | return next_header; 151 | } 152 | 153 | header = header->next; 154 | } 155 | 156 | return NULL; 157 | } 158 | 159 | void *kmalloc(size_t size) { 160 | #ifdef MALLOC_DEBUG 161 | fprintf(serial, "malloc called with size %zu\n", size); 162 | #endif 163 | if (size == 0) return NULL; 164 | 165 | chunk_header_t *header = find_unused_chunk(size); 166 | if (header == NULL) return NULL; 167 | 168 | header->used = true; 169 | header->size = size; 170 | return (void *) header + sizeof(chunk_header_t); 171 | } 172 | 173 | void kfree(void *ptr) { 174 | if (ptr == NULL) return; 175 | chunk_header_t *header = ptr - sizeof(chunk_header_t); 176 | header->used = false; 177 | #ifdef MALLOC_DEBUG 178 | fprintf(serial, "freed chunk %P w/ size %zu\n", header, header->size); 179 | #endif 180 | } 181 | 182 | void *krealloc(void *ptr, size_t new_size) { 183 | if (ptr == NULL) return kmalloc(new_size); 184 | 185 | chunk_header_t *header = ptr - sizeof(chunk_header_t); 186 | if (header->size >= new_size || try_reclaim(header, new_size)) { 187 | header->size = new_size; 188 | return ptr; 189 | } 190 | 191 | void *new = kmalloc(new_size); 192 | memcpy(new, ptr, header->size); 193 | kfree(ptr); 194 | return new; 195 | } 196 | 197 | // FIXME move everything below 198 | 199 | const char *suffixes[7] = { 200 | "", 201 | "KB", 202 | "MB", 203 | "GB", 204 | "TB", 205 | "PB", 206 | "EB" 207 | }; 208 | 209 | static char *pretty_bytes(uint64_t bytes, char *buf, size_t len) { 210 | uint8_t s = 0; 211 | uint64_t count = bytes; 212 | while (count >= 1024 && s < 7) { 213 | s++; 214 | count /= 1024; 215 | } 216 | 217 | buf[snprintf(buf, len, "%llu%s", count, suffixes[s])] = 0; 218 | return buf; 219 | } 220 | 221 | void print_chunk_debug(void *ptr, bool recursive) { 222 | printf("memory_start = %P, end = %P, mmap_end = %P\n", malloc_memory_start, malloc_memory_end, mmap_end); 223 | 224 | uint32_t used = 0; 225 | if (ptr == NULL) ptr = start_chunk + sizeof(chunk_header_t); 226 | chunk_header_t *header = ptr - sizeof(chunk_header_t); 227 | char str_size[10]; 228 | do { 229 | pretty_bytes(header->size, str_size, 10); 230 | printf(". %P | next: %P, prev: %P, used: %d, size: %s\n", 231 | header, header->next, header->prev, header->used, str_size); 232 | 233 | if (header->used) { 234 | if (header->next != NULL) { 235 | used += (uintptr_t) header->next - (uintptr_t) header; 236 | } else { 237 | used += sizeof(chunk_header_t) + header->size; 238 | } 239 | } 240 | if (recursive && header->next != NULL) { 241 | header = header->next; 242 | } else { 243 | break; 244 | } 245 | } while (true); 246 | 247 | if (recursive) { 248 | uint32_t est_free = (uintptr_t) malloc_memory_end - (uintptr_t) malloc_memory_start - used; 249 | char str_used[10], str_free[10]; 250 | pretty_bytes(used, str_used, 10); 251 | pretty_bytes(est_free, str_free, 10); 252 | printf("used = %s, est. free = %s\n", str_used, str_free); 253 | } 254 | } -------------------------------------------------------------------------------- /kernel/kmalloc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void *kmalloc(size_t size); 6 | 7 | void *krealloc(void *ptr, size_t new_size); 8 | 9 | void kfree(void *ptr); 10 | 11 | void print_chunk_debug(void *ptr, bool recursive); -------------------------------------------------------------------------------- /kernel/main.c: -------------------------------------------------------------------------------- 1 | #include "console.h" 2 | #include "descriptor_tables.h" 3 | #include "multiboot.h" 4 | #include "shell.h" 5 | #include "arch/x86/mmu.h" 6 | #include "drivers/ata.h" 7 | #include "drivers/keyboard.h" 8 | #include "drivers/pci.h" 9 | #include "drivers/serial.h" 10 | #include "drivers/timer.h" 11 | #include "drivers/vga.h" 12 | #include "fatfs/ff.h" 13 | 14 | #include 15 | #include 16 | 17 | #ifdef ENABLE_DWARF 18 | #include "dwarf.h" 19 | #endif 20 | 21 | _noreturn _unused 22 | void kernel_main(uint32_t multiboot_magic, void *multiboot_info) { 23 | serial_init(); 24 | console_set_serial_enabled(true); 25 | 26 | multiboot_init(multiboot_magic, multiboot_info); 27 | pci_init(); 28 | ata_init(); 29 | 30 | bool fs_mounted = false; 31 | printf("Mounting drive 0... "); 32 | FATFS fs; 33 | FRESULT ret = f_mount(&fs, "", 1); 34 | if (ret == FR_OK) { 35 | printf("OK\n"); 36 | fs_mounted = true; 37 | } else { 38 | printf("fail %d\n", ret); 39 | } 40 | 41 | #ifdef ENABLE_DWARF 42 | // dwarf_find_debug_info(); 43 | #endif 44 | 45 | vga_load_font("assets/default8x16.psfu"); 46 | clear_screen(); 47 | 48 | shell_init(fs_mounted); 49 | __asm__ volatile("sti"); 50 | 51 | while (1) { 52 | __asm__ volatile("hlt"); 53 | __asm__ volatile("cli"); 54 | shell_read(); 55 | key_buffer_print(); 56 | __asm__ volatile("sti"); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /kernel/multiboot.c: -------------------------------------------------------------------------------- 1 | #include "multiboot.h" 2 | #include "console.h" 3 | #include "arch/x86/mmu.h" 4 | #include "drivers/vga.h" 5 | 6 | #include 7 | #include 8 | 9 | #define KERNEL_OFFSET 0x200000 // FIXME 10 | #define BASE_VIDEO_ADDRESS ((void *) 0xB8000) 11 | 12 | #define MULTIBOOT_CHECK_FLAG(flags, flag) (((flags) & (flag)) == (flag)) 13 | 14 | extern void *malloc_memory_start; 15 | extern void *malloc_memory_end; 16 | 17 | void multiboot_init(uint32_t magic, void *info_ptr) { 18 | if (magic != MULTIBOOT_MAGIC) { 19 | panic("multiboot_magic: Invalid magic "PRIX32"\n", magic); 20 | } 21 | 22 | struct multiboot_info *info = (struct multiboot_info *) phys_to_virt(info_ptr); 23 | printf("multiboot_info = "PRIXPTR", flags = "PRIx32"\n", info, info->flags); 24 | 25 | // Check for base memory information. 26 | if (MULTIBOOT_CHECK_FLAG(info->flags, MULTIBOOT_INFO_MEMORY)) { 27 | malloc_memory_start = (void *) 0x100000 + KERNEL_OFFSET; 28 | // 1 MiB + (info->mem_upper * 1 KiB) 29 | malloc_memory_end = malloc_memory_start + (info->mem_upper * 0x400) - KERNEL_OFFSET; 30 | printf("upper_memory_end = "PRIXPTR"\n", malloc_memory_end); 31 | } else { 32 | panic("multiboot: Memory information required"); 33 | } 34 | 35 | // Check for boot device. 36 | if (MULTIBOOT_CHECK_FLAG(info->flags, MULTIBOOT_INFO_BOOTDEV)) { 37 | printf("boot_device = "PRIx32"h\n", info->boot_device); 38 | } 39 | 40 | // Check for command line. 41 | if (MULTIBOOT_CHECK_FLAG(info->flags, MULTIBOOT_INFO_CMDLINE)) { 42 | char *cmdline = (char *) phys_to_virt((void *) info->cmdline); 43 | printf("cmdline size %d = %s\n", strlen(cmdline), cmdline); 44 | } 45 | 46 | // Check for modules. 47 | if (MULTIBOOT_CHECK_FLAG(info->flags, MULTIBOOT_INFO_MODS)) { 48 | struct multiboot_mod_list *mod; 49 | int i; 50 | 51 | printf("mods_count = "PRIu32", mods_addr = "PRIXUPTR"\n", info->mods_count, info->mods_addr); 52 | for (i = 0, mod = (struct multiboot_mod_list *) phys_to_virt((void *) info->mods_addr); 53 | i < info->mods_count; 54 | i++, mod++) { 55 | printf(" mod_start = "PRIXUPTR", mod_end = "PRIXUPTR", cmdline = %s\n", 56 | mod->mod_start, mod->mod_end, (char *) phys_to_virt((void *) mod->cmdline)); 57 | } 58 | } 59 | 60 | // Check for ELF section header table information. 61 | if (MULTIBOOT_CHECK_FLAG(info->flags, MULTIBOOT_INFO_ELF_SHDR)) { 62 | struct multiboot_elf_section_header_table *elf_sec = &info->u.elf_sec; 63 | printf("multiboot_elf_sec: num = "PRIu32", size = "PRIu32", addr = "PRIXUPTR", shndx = "PRIu32"\n", 64 | elf_sec->num, elf_sec->size, elf_sec->addr, elf_sec->shndx); 65 | } 66 | 67 | // Check for memory map information 68 | if (MULTIBOOT_CHECK_FLAG(info->flags, MULTIBOOT_INFO_MEM_MAP)) { 69 | printf("mmap_addr = "PRIXUPTR", mmap_length = "PRIx32"\n", info->mmap_addr, info->mmap_length); 70 | 71 | struct multiboot_mmap_entry *mmap; 72 | struct multiboot_mmap_entry *largest_available_entry = NULL; 73 | for (mmap = (struct multiboot_mmap_entry *) phys_to_virt((void *) info->mmap_addr); 74 | (uintptr_t) mmap < (uintptr_t) phys_to_virt((void *) info->mmap_addr + info->mmap_length); 75 | mmap = (struct multiboot_mmap_entry *) 76 | ((uintptr_t) mmap + mmap->size + sizeof(mmap->size))) { 77 | if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE && 78 | (largest_available_entry == NULL || mmap->len > largest_available_entry->len)) { 79 | largest_available_entry = mmap; 80 | } 81 | 82 | printf(" size = "PRIx32", base_addr = "PRIXUPTR64S", length = "PRIX64S", type = "PRIu32"\n", 83 | mmap->size, mmap->addr, mmap->len, mmap->type); 84 | } 85 | 86 | if (largest_available_entry != NULL) { 87 | malloc_memory_start = (void *) (uintptr_t) largest_available_entry->addr + KERNEL_OFFSET; 88 | malloc_memory_end = malloc_memory_start + largest_available_entry->len - KERNEL_OFFSET; 89 | printf("malloc_memory_start = "PRIXPTR", end = "PRIXPTR"\n", malloc_memory_start, malloc_memory_end); 90 | } 91 | } 92 | 93 | // Check for VBE info. 94 | if (MULTIBOOT_CHECK_FLAG(info->flags, MULTIBOOT_INFO_VBE_INFO)) { 95 | printf("vbe_control_info = "PRIXUPTR", vbe_mode_info = "PRIXUPTR", vbe_mode = %d\n", 96 | info->vbe_control_info, info->vbe_mode_info, info->vbe_mode); 97 | } 98 | 99 | // Check for VGA framebuffer information. 100 | if (MULTIBOOT_CHECK_FLAG(info->flags, MULTIBOOT_INFO_FRAMEBUFFER_INFO)) { 101 | printf("framebuffer_addr = "PRIXUPTR64", type = %d, bpp = %d\n", 102 | info->framebuffer_addr, info->framebuffer_type, info->framebuffer_bpp); 103 | uintptr_t fbaddr = (uintptr_t) info->framebuffer_addr; 104 | page_table_set(fbaddr, fbaddr, 0x83); // Add framebuffer to page table 105 | 106 | vga_init((void *) fbaddr, info->framebuffer_type, &(framebuffer_info_t) { 107 | .pitch = info->framebuffer_pitch, 108 | .width = info->framebuffer_width, 109 | .height = info->framebuffer_height, 110 | .bpp = info->framebuffer_bpp, 111 | .palette_addr = info->framebuffer_palette_addr, 112 | .palette_num_colors = info->framebuffer_palette_num_colors, 113 | .red_field_position = info->framebuffer_red_field_position, 114 | .red_mask_size = info->framebuffer_red_mask_size, 115 | .green_field_position = info->framebuffer_green_field_position, 116 | .green_mask_size = info->framebuffer_green_mask_size, 117 | .blue_field_position = info->framebuffer_blue_field_position, 118 | .blue_mask_size = info->framebuffer_blue_mask_size, 119 | }); 120 | 121 | switch (info->framebuffer_type) { 122 | case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT: 123 | console_set_vga_enabled(true); 124 | break; 125 | 126 | case MULTIBOOT_FRAMEBUFFER_TYPE_RGB: 127 | console_set_vga_enabled(true); 128 | break; 129 | 130 | default: 131 | break; 132 | } 133 | } else { 134 | // Assume text console & hardcoded FB address for now 135 | vga_init(phys_to_virt(BASE_VIDEO_ADDRESS), 2, 0); 136 | console_set_vga_enabled(true); // FIXME 137 | } 138 | } -------------------------------------------------------------------------------- /kernel/multiboot.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* multiboot.h - Multiboot header file. */ 4 | /* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to 8 | * deal in the Software without restriction, including without limitation the 9 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | * sell copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY 19 | * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 21 | * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include 25 | 26 | #define MULTIBOOT_MAGIC 0x2BADB002 27 | 28 | /* Flags to be set in the 'flags' member of the multiboot info structure. */ 29 | #define MULTIBOOT_INFO_MEMORY 0x00000001 30 | #define MULTIBOOT_INFO_BOOTDEV 0x00000002 31 | #define MULTIBOOT_INFO_CMDLINE 0x00000004 32 | #define MULTIBOOT_INFO_MODS 0x00000008 33 | #define MULTIBOOT_INFO_AOUT_SYMS 0x00000010 34 | #define MULTIBOOT_INFO_ELF_SHDR 0x00000020 35 | #define MULTIBOOT_INFO_MEM_MAP 0x00000040 36 | #define MULTIBOOT_INFO_DRIVE_INFO 0x00000080 37 | #define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100 38 | #define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200 39 | #define MULTIBOOT_INFO_APM_TABLE 0x00000400 40 | #define MULTIBOOT_INFO_VBE_INFO 0x00000800 41 | #define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000 42 | 43 | #define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 44 | #define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 45 | #define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 46 | 47 | #define MULTIBOOT_MEMORY_AVAILABLE 1 48 | #define MULTIBOOT_MEMORY_RESERVED 2 49 | #define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 50 | #define MULTIBOOT_MEMORY_NVS 4 51 | #define MULTIBOOT_MEMORY_BADRAM 5 52 | 53 | struct multiboot_aout_symbol_table { 54 | uint32_t tabsize; 55 | uint32_t strsize; 56 | uint32_t addr; 57 | uint32_t reserved; 58 | }; 59 | 60 | struct multiboot_elf_section_header_table { 61 | uint32_t num; 62 | uint32_t size; 63 | uint32_t addr; 64 | uint32_t shndx; 65 | }; 66 | 67 | struct multiboot_info { 68 | uint32_t flags; 69 | 70 | uint32_t mem_lower; 71 | uint32_t mem_upper; 72 | 73 | uint32_t boot_device; 74 | 75 | uint32_t cmdline; 76 | 77 | uint32_t mods_count; 78 | uint32_t mods_addr; 79 | 80 | union { 81 | struct multiboot_aout_symbol_table aout_sym; 82 | struct multiboot_elf_section_header_table elf_sec; 83 | } u; 84 | 85 | uint32_t mmap_length; 86 | uint32_t mmap_addr; 87 | 88 | uint32_t drives_length; 89 | uint32_t drives_addr; 90 | 91 | uint32_t config_table; 92 | 93 | uint32_t boot_loader_name; 94 | 95 | uint32_t apm_table; 96 | 97 | uint32_t vbe_control_info; 98 | uint32_t vbe_mode_info; 99 | uint16_t vbe_mode; 100 | uint16_t vbe_interface_seg; 101 | uint16_t vbe_interface_off; 102 | uint16_t vbe_interface_len; 103 | 104 | uint64_t framebuffer_addr; 105 | uint32_t framebuffer_pitch; 106 | uint32_t framebuffer_width; 107 | uint32_t framebuffer_height; 108 | uint8_t framebuffer_bpp; 109 | uint8_t framebuffer_type; 110 | union { 111 | struct { 112 | uint32_t framebuffer_palette_addr; 113 | uint16_t framebuffer_palette_num_colors; 114 | }; 115 | struct { 116 | uint8_t framebuffer_red_field_position; 117 | uint8_t framebuffer_red_mask_size; 118 | uint8_t framebuffer_green_field_position; 119 | uint8_t framebuffer_green_mask_size; 120 | uint8_t framebuffer_blue_field_position; 121 | uint8_t framebuffer_blue_mask_size; 122 | }; 123 | }; 124 | }; 125 | 126 | struct multiboot_mmap_entry { 127 | uint32_t size; 128 | uint64_t addr; 129 | uint64_t len; 130 | uint32_t type; 131 | } __attribute__((packed)); 132 | 133 | struct multiboot_mod_list { 134 | uint32_t mod_start; 135 | uint32_t mod_end; 136 | 137 | uint32_t cmdline; 138 | 139 | uint32_t pad; 140 | }; 141 | 142 | void multiboot_init(uint32_t magic, void *info_ptr); -------------------------------------------------------------------------------- /kernel/psf.c: -------------------------------------------------------------------------------- 1 | #include "psf.h" 2 | #include "kmalloc.h" 3 | 4 | #include 5 | #include 6 | 7 | void *psf_read_font(const char *filename, psf_font_t *out_header) { 8 | FILE *font_file; 9 | psf_font_t header; 10 | void *glyphs_data; 11 | 12 | font_file = fopen(filename, "r"); 13 | if (ferror(font_file)) 14 | return NULL; 15 | 16 | fread(&header, sizeof(psf_font_t), 1, font_file); 17 | if (ferror(font_file) || header.magic != PSF_FONT_MAGIC 18 | || fseek(font_file, header.header_size, SEEK_SET)) { 19 | fclose(font_file); 20 | return NULL; 21 | } 22 | 23 | uint32_t glyphs_size = header.bytes_per_glyph * header.num_glyph; 24 | glyphs_data = kmalloc(glyphs_size); 25 | if (glyphs_data == NULL) { 26 | errno = ENOMEM; 27 | fclose(font_file); 28 | return NULL; 29 | } 30 | 31 | fread(glyphs_data, glyphs_size, 1, font_file); 32 | if (ferror(font_file)) { 33 | fclose(font_file); 34 | return NULL; 35 | } 36 | fclose(font_file); 37 | 38 | *out_header = header; 39 | return glyphs_data; 40 | } -------------------------------------------------------------------------------- /kernel/psf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define PSF_FONT_MAGIC 0x864ab572 6 | 7 | typedef struct psf_font { 8 | uint32_t magic; // magic 9 | uint32_t version; // zero 10 | uint32_t header_size; // offset of bitmaps in file, 32 11 | uint32_t flags; // 0 if there's no unicode table 12 | uint32_t num_glyph; // number of glyphs 13 | uint32_t bytes_per_glyph; // size of each glyph 14 | uint32_t height; // height in pixels 15 | uint32_t width; // width in pixels 16 | } psf_font_t; 17 | 18 | void *psf_read_font(const char *filename, psf_font_t *header); -------------------------------------------------------------------------------- /kernel/shell.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void shell_init(bool fs_mounted); 6 | 7 | void shell_read(); 8 | 9 | void shell_handle_up(); 10 | 11 | void shell_handle_down(); 12 | 13 | void key_buffer_clear(); 14 | 15 | bool key_buffer_append(char c); 16 | 17 | void key_buffer_backspace(); 18 | 19 | void key_buffer_return(); -------------------------------------------------------------------------------- /kernel/stdio_impl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "kmalloc.h" 7 | 8 | #include "fatfs/ff.h" 9 | 10 | int __fatfs_to_stderr(FRESULT ret) { 11 | switch (ret) { 12 | case FR_OK: 13 | break; 14 | case FR_DISK_ERR: 15 | case FR_MKFS_ABORTED: 16 | return EIO; 17 | case FR_INT_ERR: 18 | case FR_INVALID_PARAMETER: 19 | return EINVAL; 20 | case FR_NOT_READY: 21 | case FR_INVALID_DRIVE: 22 | case FR_NOT_ENABLED: 23 | return ENODEV; 24 | case FR_NO_FILE: 25 | case FR_NO_PATH: 26 | return ENOENT; 27 | case FR_INVALID_NAME: 28 | return ENAMETOOLONG; 29 | case FR_DENIED: 30 | return ENOSPC; 31 | case FR_EXIST: 32 | case FR_LOCKED: 33 | return EACCES; 34 | case FR_INVALID_OBJECT: 35 | return EBADFD; 36 | case FR_WRITE_PROTECTED: 37 | return EROFS; 38 | case FR_NO_FILESYSTEM: 39 | return EILSEQ; 40 | case FR_TIMEOUT: 41 | return ETIME; 42 | case FR_NOT_ENOUGH_CORE: 43 | return ENOMEM; 44 | case FR_TOO_MANY_OPEN_FILES: 45 | return EMFILE; 46 | } 47 | return 0; 48 | } 49 | 50 | FILE *__fatfs_open(FILE *f, const char *filename, const char *m) { 51 | FRESULT ret; 52 | 53 | f->cookie = kmalloc(sizeof(FIL)); 54 | if (f->cookie == NULL) { 55 | errno = ENOMEM; 56 | f->flags |= F_ERR; 57 | return NULL; 58 | } 59 | 60 | uint8_t mode = FA_READ | FA_WRITE; 61 | if (strcmp("w+", m) == 0) mode |= FA_CREATE_ALWAYS; 62 | else if (f->flags & F_NOWR) mode &= ~FA_WRITE; 63 | else if (strcmp("r+", m) != 0) mode |= FA_CREATE_NEW; 64 | if (f->flags & F_NORD) mode &= ~FA_READ; 65 | if (f->flags & F_APP) mode |= FA_OPEN_APPEND; 66 | 67 | ret = f_open(f->cookie, filename, mode); 68 | if (ret != FR_OK) { 69 | errno = __fatfs_to_stderr(ret); 70 | f->flags |= F_ERR; 71 | return NULL; 72 | } 73 | 74 | return f; 75 | } 76 | 77 | size_t __fatfs_read(FILE *f, char *buf, size_t len) { 78 | FRESULT ret; 79 | size_t read; 80 | 81 | ret = f_read(f->cookie, buf, len, &read); 82 | 83 | if (ret != FR_OK) { 84 | errno = __fatfs_to_stderr(ret); 85 | f->flags |= F_ERR; 86 | return 0; 87 | } else if (read == 0) { 88 | f->flags |= F_EOF; 89 | return 0; 90 | } 91 | if (read <= len) return read; 92 | read -= len; 93 | // TODO buffer logic? 94 | //f->rpos = f->buf; 95 | //f->rend = f->buf + cnt; 96 | //if (f->buf_size) buf[len-1] = *f->rpos++; 97 | return len; 98 | } 99 | 100 | size_t __fatfs_write(FILE *f, const char *buf, size_t len) { 101 | FRESULT ret; 102 | size_t written = 0; 103 | size_t rem = f->wpos - f->wbase; 104 | 105 | if (rem) { 106 | ret = f_write(f->cookie, f->wbase, rem, &written); 107 | if (ret != FR_OK || written != rem) { 108 | errno = ret == FR_OK ? EIO : __fatfs_to_stderr(ret); 109 | f->flags |= F_ERR; 110 | return written; 111 | } 112 | } 113 | 114 | if (len) { 115 | ret = f_write(f->cookie, buf, len, &written); 116 | if (ret != FR_OK || written != len) { 117 | errno = ret == FR_OK ? EIO : __fatfs_to_stderr(ret); 118 | f->flags |= F_ERR; 119 | return written; 120 | } 121 | } 122 | 123 | f->wend = f->buf + f->buf_size; 124 | f->wpos = f->wbase = f->buf; 125 | return len; 126 | } 127 | 128 | off_t __fatfs_seek(FILE *f, const off_t offset, int origin) { 129 | FRESULT ret; 130 | FIL *fp = f->cookie; 131 | off_t ofs = offset; 132 | 133 | if (origin == SEEK_CUR) ofs += f_tell(fp); 134 | if (origin == SEEK_END) ofs += f_size(fp); 135 | ret = f_lseek(fp, (FSIZE_t) ofs); 136 | if (ret != FR_OK) { 137 | errno = __fatfs_to_stderr(ret); 138 | f->flags |= F_ERR; 139 | return EOF; 140 | } 141 | 142 | return ofs; 143 | } 144 | 145 | int __fatfs_close(FILE *f) { 146 | FRESULT ret = f_close(f->cookie); 147 | if (ret != FR_OK) { 148 | errno = __fatfs_to_stderr(ret); 149 | f->flags |= F_ERR; 150 | return EOF; 151 | } 152 | kfree(f->cookie); 153 | return 0; 154 | } 155 | 156 | FILE *fopen(const char *filename, const char *mode) { 157 | FILE *f; 158 | 159 | /* Check for valid initial mode character */ 160 | if (!strchr("rwa", *mode)) { 161 | errno = EINVAL; 162 | return NULL; 163 | } 164 | 165 | if (!(f = kmalloc(sizeof(FILE) + UNGET + BUFSIZ))) { 166 | errno = ENOMEM; 167 | return NULL; 168 | } 169 | memset(f, 0, sizeof(FILE)); 170 | 171 | /* Impose mode restrictions */ 172 | if (!strchr(mode, '+')) f->flags = (*mode == 'r') ? F_NOWR : F_NORD; 173 | 174 | /* Set append mode on fd if opened for append */ 175 | if (*mode == 'a') f->flags |= F_APP; 176 | 177 | // f->fd = fd; 178 | f->buf = (char *) f + sizeof(FILE) + UNGET; 179 | f->buf_size = BUFSIZ; 180 | 181 | /* Activate line buffered mode for terminals */ 182 | f->lbf = EOF; 183 | if (!(f->flags & F_NOWR)) f->lbf = '\n'; 184 | 185 | f->read = __fatfs_read; 186 | f->write = __fatfs_write; 187 | f->seek = __fatfs_seek; 188 | f->close = __fatfs_close; 189 | 190 | return __fatfs_open(f, filename, mode); 191 | } 192 | 193 | static int __toread(FILE *f) { 194 | f->mode |= f->mode - 1; 195 | if (f->wpos != f->wbase) f->write(f, 0, 0); 196 | f->wpos = f->wbase = f->wend = 0; 197 | if (f->flags & F_NORD) { 198 | f->flags |= F_ERR; 199 | return EOF; 200 | } 201 | f->rpos = f->rend = f->buf + f->buf_size; 202 | return feof(f) ? EOF : 0; 203 | } 204 | 205 | 206 | size_t fread(void *restrict destv, size_t size, size_t nmemb, FILE *restrict f) { 207 | char *dest = destv; 208 | size_t len = size * nmemb, l = len, k; 209 | if (!size) nmemb = 0; 210 | 211 | f->mode |= f->mode - 1; 212 | 213 | if (f->rpos != f->rend) { 214 | /* First exhaust the buffer. */ 215 | k = MIN(f->rend - f->rpos, l); 216 | memcpy(dest, f->rpos, k); 217 | f->rpos += k; 218 | dest += k; 219 | l -= k; 220 | } 221 | 222 | /* Read the remainder directly */ 223 | for (; l; l -= k, dest += k) { 224 | k = __toread(f) ? 0 : f->read(f, dest, l); 225 | if (!k) { 226 | return (len - l) / size; 227 | } 228 | } 229 | 230 | return nmemb; 231 | } 232 | 233 | int stat(const char *filename, struct stat *st) { 234 | FILINFO info; 235 | FRESULT ret = f_stat(filename, &info); 236 | if (ret != FR_OK) { 237 | errno = __fatfs_to_stderr(ret); 238 | return EOF; 239 | } 240 | 241 | st->st_size = info.fsize; 242 | return 0; 243 | } 244 | 245 | int fseek(FILE *f, off_t off, int origin) { 246 | /* Adjust relative offset for unread data in buffer, if any. */ 247 | if (origin == SEEK_CUR && f->rend) off -= f->rend - f->rpos; 248 | 249 | /* Flush write buffer, and report error on failure. */ 250 | if (f->wpos != f->wbase) { 251 | f->write(f, 0, 0); 252 | if (!f->wpos) return -1; 253 | } 254 | 255 | /* Leave writing mode */ 256 | f->wpos = f->wbase = f->wend = 0; 257 | 258 | /* Perform the underlying seek. */ 259 | if (f->seek(f, off, origin) < 0) return -1; 260 | 261 | /* If seek succeeded, file is seekable and we discard read buffer. */ 262 | f->rpos = f->rend = 0; 263 | f->flags &= ~F_EOF; 264 | 265 | return 0; 266 | } 267 | 268 | -------------------------------------------------------------------------------- /kernel/tests/fatfs.c: -------------------------------------------------------------------------------- 1 | #include "../fatfs/ff.h" 2 | #include "../kmalloc.h" 3 | 4 | #include 5 | #include 6 | 7 | bool fatfs_test() { 8 | FATFS fs; 9 | FRESULT ret; 10 | FILINFO info; 11 | FIL file; 12 | char *buff = NULL; 13 | uint32_t read = 0; 14 | 15 | printf("Mounting drive 0... "); 16 | ret = f_mount(&fs, "", 1); 17 | if (ret != FR_OK) goto fail; 18 | printf("OK\n"); 19 | 20 | ret = f_stat("README", &info); 21 | if (ret != FR_OK || !info.fsize) goto fail; 22 | 23 | printf("Opening README with size %llu... \n", info.fsize); 24 | ret = f_open(&file, "README", FA_READ); 25 | if (ret != FR_OK) goto fail; 26 | printf("OK\n"); 27 | 28 | buff = kmalloc((size_t) info.fsize + 1); 29 | if (buff == NULL) goto fail; 30 | 31 | ret = f_read(&file, buff, (uint32_t) info.fsize, &read); 32 | if (ret != FR_OK || read != info.fsize) goto fail; 33 | 34 | printf("File read successfully.\n\n"); 35 | // buff[read] = 0; 36 | // printf("%s\n", (char *) buff); 37 | 38 | goto end; 39 | 40 | fail: 41 | printf("fatfs fail %d\n", ret); 42 | 43 | end: 44 | kfree(buff); 45 | f_close(&file); 46 | f_unmount(""); 47 | return ret == FR_OK; 48 | } -------------------------------------------------------------------------------- /kernel/tests/pages.c: -------------------------------------------------------------------------------- 1 | #include "tests.h" 2 | #include "../kmalloc.h" 3 | 4 | #include 5 | #include 6 | 7 | #define ASSERT_EQ(expected, actual) if ((expected) != (actual)) { \ 8 | printf("Failed on line %d. Expected: %u. Actual: %u\n", \ 9 | __LINE__, (uint32_t) expected, (uint32_t) actual); \ 10 | return false; \ 11 | } 12 | 13 | #define ASSERT_NE(not_expected, actual) if ((not_expected) == (actual)) { \ 14 | printf("Failed on line %d. Non expected actual value: %u\n", \ 15 | __LINE__, (uint32_t) actual); \ 16 | return false; \ 17 | } 18 | 19 | extern volatile uintptr_t mmap_end; 20 | 21 | #define PAGE_SIZE 0x400000 22 | 23 | bool page_table_test() { 24 | uintptr_t mmap_before = mmap_end; 25 | printf("Before: %u\n", mmap_before); 26 | void *ptr = kmalloc(PAGE_SIZE - 0x10); 27 | ASSERT_NE(NULL, ptr); 28 | ASSERT_EQ(mmap_before + PAGE_SIZE, mmap_end); 29 | printf("After: %u\n", mmap_end); 30 | memset(ptr, 0xFF, PAGE_SIZE - 0x10); 31 | // kfree(ptr); 32 | return true; 33 | } -------------------------------------------------------------------------------- /kernel/tests/path.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define CHECK(s1, s2, len) { \ 6 | if (strncmp(s1, s2, len) != 0) { \ 7 | printf("path_test fail line %d: Expected: %s, actual: %s\n", __LINE__, s2, s1); \ 8 | return false; \ 9 | } \ 10 | } 11 | 12 | bool path_test() { 13 | char buf[512]; 14 | size_t len = sizeof(buf); 15 | 16 | path_append(buf, "/test", "123", len); 17 | CHECK(buf, "/test/123", len); 18 | 19 | path_append(buf, "/test/", "/123", len); 20 | CHECK(buf, "/123", len); 21 | 22 | path_append(buf, "/test/", "/123/test 456/../test 567", len); 23 | CHECK(buf, "/123/test 567", len); 24 | 25 | path_append(buf, "/test//", "123/", len); 26 | CHECK(buf, "/test/123/", len); 27 | 28 | path_append(buf, "/test", "..", len); 29 | CHECK(buf, "/", len); 30 | 31 | path_append(buf, "/", "..", len); 32 | CHECK(buf, "/", len); 33 | 34 | path_append(buf, "/test/..", "123", len); 35 | CHECK(buf, "/123", len); 36 | 37 | path_append(buf, "/test/", "123/..", len); 38 | CHECK(buf, "/test/", len); 39 | 40 | path_append(buf, "/test/.", "123/./456", len); 41 | CHECK(buf, "/test/123/456", len); 42 | 43 | path_append(buf, "test 1", "test 2", len); 44 | CHECK(buf, "test 1/test 2", len); 45 | 46 | path_append(buf, "/1/2/3/4/5/6/7/8/9/../9", "10/", len); 47 | CHECK(buf, "/1/2/3/4/5/6/7/8/9/10/", len); 48 | 49 | // FIXME later 50 | // path_append(buf, "/1/2/3/4/5/./6/./7/8/9/../9", "10/.", len); 51 | // CHECK(buf, "/1/2/3/4/5/6/7/8/9/10/", len); 52 | 53 | path_append(buf, "/dev/", "", len); 54 | CHECK(buf, "/dev/", len); 55 | 56 | path_append(buf, "/dev/", ".null", len); 57 | CHECK(buf, "/dev/.null", len); 58 | 59 | path_append(buf, "", ".config", len); 60 | CHECK(buf, ".config", len); 61 | 62 | path_append(buf, "", NULL, len); 63 | CHECK(buf, "", len); 64 | 65 | path_append(buf, "test", NULL, len); 66 | CHECK(buf, "test", len); 67 | 68 | path_append(buf, "/test", ".", len); 69 | CHECK(buf, "/test", len); 70 | 71 | printf("path_test: passed\n"); 72 | return true; 73 | } -------------------------------------------------------------------------------- /kernel/tests/stdio.c: -------------------------------------------------------------------------------- 1 | #include "tests.h" 2 | #include "../kmalloc.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define FAIL() { \ 10 | fail_line = __LINE__; \ 11 | goto fail; \ 12 | } 13 | 14 | const char filename[] = "README"; 15 | const char test_str[] = "fwrite"; 16 | 17 | extern int ff_abrt_line; 18 | 19 | static bool stat_test() { 20 | struct stat st; 21 | bool ret = !(stat(filename, &st) || !st.st_size); 22 | printf("stat_test: %s.\n", ret ? "passed" : "failed"); 23 | return ret; 24 | } 25 | 26 | static bool fread_test() { 27 | bool ret = true; 28 | int fail_line = 0; 29 | 30 | struct stat st; 31 | FILE *file = {0}; 32 | void *buff = NULL; 33 | 34 | if (stat(filename, &st) || !st.st_size) FAIL(); 35 | printf("Opening %s with size %llu...\n", filename, st.st_size); 36 | file = fopen(filename, "r"); 37 | if (ferror(file)) FAIL(); 38 | 39 | if ((buff = kmalloc((size_t) st.st_size + 1)) == NULL) FAIL(); 40 | size_t read = fread(buff, (uint32_t) st.st_size, 1, file); 41 | if (ferror(file) || !read) FAIL(); 42 | 43 | printf("Checking file contents...\n"); 44 | if (strncmp(buff, "mkdir", 5) != 0) FAIL(); 45 | 46 | printf("fread_test: passed.\n"); 47 | goto end; 48 | 49 | fail: 50 | ret = false; 51 | printf("fread_test: failed on line %d. (errno %d)\n", fail_line, errno); 52 | 53 | end: 54 | if (file != NULL) fclose(file); 55 | kfree(buff); 56 | return ret; 57 | } 58 | 59 | static bool fwrite_test() { 60 | bool ret = true; 61 | int fail_line = 0; 62 | 63 | struct stat st; 64 | FILE *file = {0}; 65 | void *rbuff = NULL; 66 | void *wbuff = NULL; 67 | 68 | if (stat(filename, &st) || !st.st_size) FAIL(); 69 | printf("Opening %s for updating... %lli\n", filename, st.st_size); 70 | file = fopen(filename, "r+"); 71 | if (ferror(file)) FAIL(); 72 | 73 | if ((rbuff = kmalloc((size_t) st.st_size + 1)) == NULL) FAIL(); 74 | if (!fread(rbuff, (uint32_t) st.st_size, 1, file) || ferror(file)) FAIL(); 75 | if (fseek(file, 0, SEEK_SET) || ferror(file)) FAIL(); 76 | if (!fwrite(test_str, sizeof(test_str) - 1, 1, file) || ferror(file)) FAIL(); 77 | if (fclose(file)) FAIL(); 78 | 79 | if (stat(filename, &st) || !st.st_size) FAIL(); 80 | printf("Re-open %s for updating... %lli\n", filename, st.st_size); 81 | file = fopen(filename, "r+"); 82 | if (ferror(file)) FAIL(); 83 | if ((wbuff = kmalloc(sizeof(test_str))) == NULL) FAIL(); 84 | if (fseek(file, 0, SEEK_SET) || ferror(file)) FAIL(); 85 | if (!fread(wbuff, sizeof(test_str), 1, file) || ferror(file)) FAIL(); 86 | if (strncmp(wbuff, test_str, sizeof(test_str) - 1) != 0) FAIL(); 87 | if (fseek(file, 0, SEEK_SET) || ferror(file)) FAIL(); 88 | if (!fwrite(rbuff, sizeof(test_str) - 1, 1, file) || ferror(file)) FAIL(); 89 | 90 | printf("fwrite_test: passed.\n"); 91 | goto end; 92 | 93 | fail: 94 | ret = false; 95 | printf("fwrite_test: failed on line %d. (errno %d, ff_abrt_line %d)\n", fail_line, errno, ff_abrt_line); 96 | 97 | end: 98 | if (file != NULL) { 99 | fflush(file); 100 | fclose(file); 101 | } 102 | kfree(rbuff); 103 | kfree(wbuff); 104 | return ret; 105 | } 106 | 107 | bool stdio_test() { 108 | return stat_test() && 109 | fread_test() && 110 | fwrite_test(); 111 | } -------------------------------------------------------------------------------- /kernel/tests/tests.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | bool vc_vector_run_tests(); 6 | 7 | bool fatfs_test(); 8 | 9 | bool stdio_test(); 10 | 11 | bool path_test(); 12 | 13 | bool page_table_test(); -------------------------------------------------------------------------------- /libc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project(libc) 3 | 4 | set(CMAKE_ASM_NASM_OBJECT_FORMAT elf) 5 | enable_language(ASM_NASM) 6 | 7 | set(CMAKE_C_FLAGS "-m32 -std=c11 -ffreestanding -fno-pie -fshort-enums -Wall -Werror -Wno-error=unused-variable -Wno-error=attributes") 8 | # if clang: -Wno-error=unused-command-line-argument -nobuiltininc 9 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostdinc -fno-builtin -nostdlib -nodefaultlibs") 10 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-stack-protector") # FIXME generates bad code using `mov eax, large gs:14h`? 11 | set(CMAKE_C_FLAGS_DEBUG "-gdwarf-4 -DENABLE_DWARF") 12 | if (NOT CMAKE_HOST_APPLE) 13 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fsanitize=undefined") 14 | endif() 15 | set(CMAKE_C_FLAGS_RELEASE "-Os") 16 | 17 | if (CMAKE_HOST_APPLE) 18 | set(CMAKE_C_COMPILER i386-elf-gcc) 19 | set(CMAKE_AR i386-elf-ar) 20 | set(CMAKE_RANLIB i386-elf-ranlib) 21 | endif () 22 | 23 | include_directories(${CMAKE_SOURCE_DIR}/libc) 24 | add_library(c STATIC string math vector byteswap ctype errno wchar stdio.c stdio.h 25 | stddef.h stdarg.h 26 | stdio/printf stdio/fprintf stdio/sprintf stdio/snprintf stdio/vfprintf stdio/vsprintf 27 | stdio/vsnprintf) -------------------------------------------------------------------------------- /libc/byteswap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define __bswap_16(x) \ 6 | ((uint16_t) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))) 7 | 8 | #define __bswap_32(x) \ 9 | ((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) \ 10 | | (((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24)) 11 | 12 | #define __bswap_64(x) \ 13 | ((((x) & 0xff00000000000000ull) >> 56) \ 14 | | (((x) & 0x00ff000000000000ull) >> 40) \ 15 | | (((x) & 0x0000ff0000000000ull) >> 24) \ 16 | | (((x) & 0x000000ff00000000ull) >> 8) \ 17 | | (((x) & 0x00000000ff000000ull) << 8) \ 18 | | (((x) & 0x0000000000ff0000ull) << 24) \ 19 | | (((x) & 0x000000000000ff00ull) << 40) \ 20 | | (((x) & 0x00000000000000ffull) << 56)) 21 | -------------------------------------------------------------------------------- /libc/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define _noreturn _Noreturn 8 | #define static_assert _Static_assert 9 | 10 | #ifdef __GNUC__ 11 | #define _unused __attribute__((unused)) 12 | #define _packed __attribute__((packed)) 13 | #endif 14 | 15 | #define off_t int64_t -------------------------------------------------------------------------------- /libc/ctype.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int atoi(const char *s) { 4 | int n = 0, neg = 0; 5 | while (isspace(*s)) s++; 6 | switch (*s) { 7 | case '-': 8 | neg = 1; 9 | case '+': 10 | s++; 11 | } 12 | /* Compute n as a negative number to avoid overflow on INT_MIN */ 13 | while (isdigit(*s)) 14 | n = 10 * n - (*s++ - '0'); 15 | return neg ? n : -n; 16 | } -------------------------------------------------------------------------------- /libc/ctype.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | static __inline int __isspace(int _c) 4 | { 5 | return _c == ' ' || (unsigned)_c-'\t' < 5; 6 | } 7 | 8 | #define isalpha(a) ((((unsigned)(a)|32)-'a') < 26) 9 | #define isdigit(a) (((unsigned)(a)-'0') < 10) 10 | #define islower(a) (((unsigned)(a)-'a') < 26) 11 | #define isupper(a) (((unsigned)(a)-'A') < 26) 12 | #define isprint(a) (((unsigned)(a)-0x20) < 0x5f) 13 | #define isgraph(a) (((unsigned)(a)-0x21) < 0x5e) 14 | #define isspace(a) __isspace(a) 15 | 16 | int atoi(const char *s); -------------------------------------------------------------------------------- /libc/errno.c: -------------------------------------------------------------------------------- 1 | #include "errno.h" 2 | 3 | char *strerror(int errno) { 4 | return "ERROR"; // FIXME 5 | } -------------------------------------------------------------------------------- /libc/errno.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define ENOENT 2 // No such file or directory 4 | #define EIO 4 // I/O Error 5 | #define ENOMEM 12 // Out of memory 6 | #define EACCES 13 // Permission denied 7 | #define ENODEV 19 // No such device 8 | #define EINVAL 22 // Invalid argument 9 | #define EMFILE 24 // Too many open files 10 | #define ENOSPC 28 // No space left on device 11 | #define EROFS 30 // Read-only file system 12 | #define ENAMETOOLONG 36 // File name too long 13 | #define ETIME 62 // Timer expired 14 | #define EOVERFLOW 75 // Value too large for defined data type 15 | #define EBADFD 77 // File descriptor in bad state 16 | #define EILSEQ 84 // Illegal byte sequence 17 | 18 | extern int errno; // FIXME for threading 19 | 20 | char *strerror(int errno); 21 | -------------------------------------------------------------------------------- /libc/float.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* Characteristics of floating point types, C99 5.2.4.2.2 */ 4 | 5 | #define FLT_EVAL_METHOD __FLT_EVAL_METHOD__ 6 | #define FLT_ROUNDS (__builtin_flt_rounds()) 7 | #define FLT_RADIX __FLT_RADIX__ 8 | 9 | #define FLT_MANT_DIG __FLT_MANT_DIG__ 10 | #define DBL_MANT_DIG __DBL_MANT_DIG__ 11 | #define LDBL_MANT_DIG __LDBL_MANT_DIG__ 12 | 13 | #if __STDC_VERSION__ >= 199901L || !defined(__STRICT_ANSI__) 14 | #define DECIMAL_DIG __DECIMAL_DIG__ 15 | #endif 16 | 17 | #define FLT_DIG __FLT_DIG__ 18 | #define DBL_DIG __DBL_DIG__ 19 | #define LDBL_DIG __LDBL_DIG__ 20 | 21 | #define FLT_MIN_EXP __FLT_MIN_EXP__ 22 | #define DBL_MIN_EXP __DBL_MIN_EXP__ 23 | #define LDBL_MIN_EXP __LDBL_MIN_EXP__ 24 | 25 | #define FLT_MIN_10_EXP __FLT_MIN_10_EXP__ 26 | #define DBL_MIN_10_EXP __DBL_MIN_10_EXP__ 27 | #define LDBL_MIN_10_EXP __LDBL_MIN_10_EXP__ 28 | 29 | #define FLT_MAX_EXP __FLT_MAX_EXP__ 30 | #define DBL_MAX_EXP __DBL_MAX_EXP__ 31 | #define LDBL_MAX_EXP __LDBL_MAX_EXP__ 32 | 33 | #define FLT_MAX_10_EXP __FLT_MAX_10_EXP__ 34 | #define DBL_MAX_10_EXP __DBL_MAX_10_EXP__ 35 | #define LDBL_MAX_10_EXP __LDBL_MAX_10_EXP__ 36 | 37 | #define FLT_MAX __FLT_MAX__ 38 | #define DBL_MAX __DBL_MAX__ 39 | #define LDBL_MAX __LDBL_MAX__ 40 | 41 | #define FLT_EPSILON __FLT_EPSILON__ 42 | #define DBL_EPSILON __DBL_EPSILON__ 43 | #define LDBL_EPSILON __LDBL_EPSILON__ 44 | 45 | #define FLT_MIN __FLT_MIN__ 46 | #define DBL_MIN __DBL_MIN__ 47 | #define LDBL_MIN __LDBL_MIN__ 48 | 49 | #if __STDC_VERSION__ >= 201112L || !defined(__STRICT_ANSI__) 50 | #define FLT_TRUE_MIN __FLT_DENORM_MIN__ 51 | #define DBL_TRUE_MIN __DBL_DENORM_MIN__ 52 | #define LDBL_TRUE_MIN __LDBL_DENORM_MIN__ 53 | #define FLT_DECIMAL_DIG __FLT_DECIMAL_DIG__ 54 | #define DBL_DECIMAL_DIG __DBL_DECIMAL_DIG__ 55 | #define LDBL_DECIMAL_DIG __LDBL_DECIMAL_DIG__ 56 | #define FLT_HAS_SUBNORM __FLT_HAS_DENORM__ 57 | #define DBL_HAS_SUBNORM __DBL_HAS_DENORM__ 58 | #define LDBL_HAS_SUBNORM __LDBL_HAS_DENORM__ 59 | #endif 60 | 61 | #ifdef __STDC_WANT_IEC_60559_TYPES_EXT__ 62 | #define FLT16_MANT_DIG __FLT16_MANT_DIG__ 63 | #define FLT16_DECIMAL_DIG __FLT16_DECIMAL_DIG__ 64 | #define FLT16_DIG __FLT16_DIG__ 65 | #define FLT16_MIN_EXP __FLT16_MIN_EXP__ 66 | #define FLT16_MIN_10_EXP __FLT16_MIN_10_EXP__ 67 | #define FLT16_MAX_EXP __FLT16_MAX_EXP__ 68 | #define FLT16_MAX_10_EXP __FLT16_MAX_10_EXP__ 69 | #define FLT16_MAX __FLT16_MAX__ 70 | #define FLT16_EPSILON __FLT16_EPSILON__ 71 | #define FLT16_MIN __FLT16_MIN__ 72 | #define FLT16_TRUE_MIN __FLT16_TRUE_MIN__ 73 | #endif /* __STDC_WANT_IEC_60559_TYPES_EXT__ */ -------------------------------------------------------------------------------- /libc/limits.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* Many system headers try to "help us out" by defining these. No really, we 4 | know how big each datatype is. */ 5 | #undef SCHAR_MIN 6 | #undef SCHAR_MAX 7 | #undef UCHAR_MAX 8 | #undef SHRT_MIN 9 | #undef SHRT_MAX 10 | #undef USHRT_MAX 11 | #undef INT_MIN 12 | #undef INT_MAX 13 | #undef UINT_MAX 14 | #undef LONG_MIN 15 | #undef LONG_MAX 16 | #undef ULONG_MAX 17 | 18 | #undef CHAR_BIT 19 | #undef CHAR_MIN 20 | #undef CHAR_MAX 21 | 22 | /* C90/99 5.2.4.2.1 */ 23 | #define SCHAR_MAX __SCHAR_MAX__ 24 | #define SHRT_MAX __SHRT_MAX__ 25 | #define INT_MAX __INT_MAX__ 26 | #define LONG_MAX __LONG_MAX__ 27 | 28 | #define SCHAR_MIN (-__SCHAR_MAX__-1) 29 | #define SHRT_MIN (-__SHRT_MAX__ -1) 30 | #define INT_MIN (-__INT_MAX__ -1) 31 | #define LONG_MIN (-__LONG_MAX__ -1L) 32 | 33 | #define UCHAR_MAX (__SCHAR_MAX__*2 +1) 34 | #define USHRT_MAX (__SHRT_MAX__ *2 +1) 35 | #define UINT_MAX (__INT_MAX__ *2U +1U) 36 | #define ULONG_MAX (__LONG_MAX__ *2UL+1UL) 37 | 38 | #ifndef MB_LEN_MAX 39 | #define MB_LEN_MAX 1 40 | #endif 41 | 42 | #define CHAR_BIT __CHAR_BIT__ 43 | 44 | #ifdef __CHAR_UNSIGNED__ /* -funsigned-char */ 45 | #define CHAR_MIN 0 46 | #define CHAR_MAX UCHAR_MAX 47 | #else 48 | #define CHAR_MIN SCHAR_MIN 49 | #define CHAR_MAX __SCHAR_MAX__ 50 | #endif 51 | 52 | /* C99 5.2.4.2.1: Added long long. 53 | C++11 18.3.3.2: same contents as the Standard C Library header . 54 | */ 55 | #if __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L 56 | 57 | #undef LLONG_MIN 58 | #undef LLONG_MAX 59 | #undef ULLONG_MAX 60 | 61 | #define LLONG_MAX __LONG_LONG_MAX__ 62 | #define LLONG_MIN (-__LONG_LONG_MAX__-1LL) 63 | #define ULLONG_MAX (__LONG_LONG_MAX__*2ULL+1ULL) 64 | #endif 65 | 66 | /* LONG_LONG_MIN/LONG_LONG_MAX/ULONG_LONG_MAX are a GNU extension. It's too bad 67 | that we don't have something like #pragma poison that could be used to 68 | deprecate a macro - the code should just use LLONG_MAX and friends. 69 | */ 70 | #if defined(__GNU_LIBRARY__) ? defined(__USE_GNU) : !defined(__STRICT_ANSI__) 71 | 72 | #undef LONG_LONG_MIN 73 | #undef LONG_LONG_MAX 74 | #undef ULONG_LONG_MAX 75 | 76 | #define LONG_LONG_MAX __LONG_LONG_MAX__ 77 | #define LONG_LONG_MIN (-__LONG_LONG_MAX__-1LL) 78 | #define ULONG_LONG_MAX (__LONG_LONG_MAX__*2ULL+1ULL) 79 | #endif 80 | -------------------------------------------------------------------------------- /libc/math.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #include 4 | 5 | union ldshape { 6 | long double f; 7 | struct { 8 | uint64_t m; 9 | uint16_t se; 10 | } i; 11 | }; 12 | 13 | long double frexpl(long double x, int *e) { 14 | union ldshape u = {x}; 15 | int ee = u.i.se & 0x7fff; 16 | 17 | if (!ee) { 18 | if (x) { 19 | x = frexpl(x * 0x1p120, e); 20 | *e -= 120; 21 | } else *e = 0; 22 | return x; 23 | } else if (ee == 0x7fff) { 24 | return x; 25 | } 26 | 27 | *e = ee - 0x3ffe; 28 | u.i.se &= 0x8000; 29 | u.i.se |= 0x3ffe; 30 | return u.f; 31 | } 32 | 33 | int __signbitl(long double x) { 34 | union ldshape u = {x}; 35 | return u.i.se >> 15; 36 | } 37 | 38 | int __fpclassifyl(long double x) { 39 | union ldshape u = {x}; 40 | int e = u.i.se & 0x7fff; 41 | int msb = (int) (u.i.m >> 63); 42 | if (!e && !msb) 43 | return u.i.m ? FP_SUBNORMAL : FP_ZERO; 44 | if (e == 0x7fff) { 45 | /* The x86 variant of 80-bit extended precision only admits 46 | * one representation of each infinity, with the mantissa msb 47 | * necessarily set. The version with it clear is invalid/nan. 48 | * The m68k variant, however, allows either, and tooling uses 49 | * the version with it clear. */ 50 | if (/*__BYTE_ORDER == __LITTLE_ENDIAN &&*/ !msb) 51 | return FP_NAN; 52 | return u.i.m << 1 ? FP_NAN : FP_INFINITE; 53 | } 54 | if (!msb) 55 | return FP_NAN; 56 | return FP_NORMAL; 57 | } -------------------------------------------------------------------------------- /libc/math.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define MAX(a, b) \ 4 | ({ __typeof__ (a) _a = (a); \ 5 | __typeof__ (b) _b = (b); \ 6 | _a > _b ? _a : _b; }) 7 | 8 | #define MIN(a, b) \ 9 | ({ __typeof__ (a) _a = (a); \ 10 | __typeof__ (b) _b = (b); \ 11 | _a < _b ? _a : _b; }) 12 | 13 | #define FP_NAN 0 14 | #define FP_INFINITE 1 15 | #define FP_ZERO 2 16 | #define FP_SUBNORMAL 3 17 | #define FP_NORMAL 4 18 | 19 | int __fpclassify(double); 20 | int __fpclassifyf(float); 21 | int __fpclassifyl(long double); 22 | 23 | static inline unsigned __FLOAT_BITS(float __f) { 24 | union { 25 | float __f; 26 | unsigned __i; 27 | } __u; 28 | __u.__f = __f; 29 | return __u.__i; 30 | } 31 | 32 | static inline unsigned long long __DOUBLE_BITS(double __f) { 33 | union { 34 | double __f; 35 | unsigned long long __i; 36 | } __u; 37 | __u.__f = __f; 38 | return __u.__i; 39 | } 40 | 41 | #define isfinite(x) ( \ 42 | sizeof(x) == sizeof(float) ? (__FLOAT_BITS(x) & 0x7fffffff) < 0x7f800000 : \ 43 | sizeof(x) == sizeof(double) ? (__DOUBLE_BITS(x) & -1ULL>>1) < 0x7ffULL<<52 : \ 44 | __fpclassifyl(x) > FP_INFINITE) 45 | 46 | int __signbit(double); 47 | int __signbitf(float); 48 | int __signbitl(long double); 49 | 50 | #define signbit(x) ( \ 51 | sizeof(x) == sizeof(float) ? (int)(__FLOAT_BITS(x)>>31) : \ 52 | sizeof(x) == sizeof(double) ? (int)(__DOUBLE_BITS(x)>>63) : \ 53 | __signbitl(x) ) 54 | 55 | long double frexpl(long double x, int *e); -------------------------------------------------------------------------------- /libc/stdarg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef __builtin_va_list va_list; 4 | 5 | #define va_start(ap, param) __builtin_va_start(ap, param) 6 | #define va_end(ap) __builtin_va_end(ap) 7 | #define va_arg(ap, type) __builtin_va_arg(ap, type) 8 | #define va_copy(dest, src) __builtin_va_copy(dest, src) 9 | -------------------------------------------------------------------------------- /libc/stdbool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define bool _Bool 4 | #define true 1 5 | #define false 0 -------------------------------------------------------------------------------- /libc/stddef.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define NULL ((void *) 0) 6 | 7 | typedef __PTRDIFF_TYPE__ ptrdiff_t; 8 | typedef uint32_t size_t; // FIXME __SIZE_TYPE__ wrong on macOS? 9 | typedef __WCHAR_TYPE__ wchar_t; 10 | -------------------------------------------------------------------------------- /libc/stdint.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // All 32-bit x86 for now 4 | 5 | typedef signed char int8_t; 6 | typedef unsigned char uint8_t; 7 | typedef signed short int int16_t; 8 | typedef unsigned short int uint16_t; 9 | typedef signed int int32_t; 10 | typedef unsigned int uint32_t; 11 | typedef signed long long int int64_t; 12 | typedef unsigned long long int uint64_t; 13 | 14 | typedef long long int intmax_t; 15 | typedef unsigned long long int uintmax_t; 16 | 17 | typedef signed char int_fast8_t; 18 | typedef unsigned char uint_fast8_t; 19 | typedef int int_fast16_t; 20 | typedef unsigned int uint_fast16_t; 21 | typedef int int_fast32_t; 22 | typedef unsigned int uint_fast32_t; 23 | typedef long long int int_fast64_t; 24 | typedef unsigned long long int uint_fast64_t; 25 | 26 | typedef int intptr_t; 27 | typedef unsigned int uintptr_t; 28 | 29 | typedef int32_t off_t; 30 | 31 | /* Signed. */ 32 | #define INT8_C(c) c 33 | #define INT16_C(c) c 34 | #define INT32_C(c) c 35 | #define INT64_C(c) c ## LL 36 | 37 | /* Unsigned. */ 38 | #define UINT8_C(c) c 39 | #define UINT16_C(c) c 40 | #define UINT32_C(c) c ## U 41 | #define UINT64_C(c) c ## ULL 42 | 43 | /* Maximal type. */ 44 | #define INTMAX_C(c) c ## LL 45 | #define UINTMAX_C(c) c ## ULL 46 | 47 | /* Minimum of signed integral types. */ 48 | #define INT8_MIN (-128) 49 | #define INT16_MIN (-32767-1) 50 | #define INT32_MIN (-2147483647-1) 51 | #define INT64_MIN (-INT64_C(9223372036854775807)-1) 52 | 53 | /* Maximum of signed integral types. */ 54 | #define INT8_MAX (127) 55 | #define INT16_MAX (32767) 56 | #define INT32_MAX (2147483647) 57 | #define INT64_MAX (INT64_C(9223372036854775807)) 58 | 59 | /* Maximum of unsigned integral types. */ 60 | #define UINT8_MAX (255) 61 | #define UINT16_MAX (65535) 62 | #define UINT32_MAX (4294967295U) 63 | #define UINT64_MAX (UINT64_C(18446744073709551615)) 64 | 65 | /* Values to test for integral types holding `void *' pointer. */ 66 | #define INTPTR_MIN (-2147483647-1) 67 | #define INTPTR_MAX (2147483647) 68 | #define UINTPTR_MAX (4294967295U) 69 | 70 | /* Minimum for largest signed integral type. */ 71 | #define INTMAX_MIN (-INT64_C(9223372036854775807)-1) 72 | /* Maximum for largest signed integral type. */ 73 | #define INTMAX_MAX (INT64_C(9223372036854775807)) 74 | 75 | /* Maximum for largest unsigned integral type. */ 76 | #define UINTMAX_MAX (UINT64_C(18446744073709551615)) 77 | 78 | /* Limits of `wchar_t'. */ 79 | #define WCHAR_MIN __WCHAR_MIN 80 | #define WCHAR_MAX __WCHAR_MAX -------------------------------------------------------------------------------- /libc/stdio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // FIXME 7 | #include "../kernel/kmalloc.h" 8 | 9 | int __towrite(FILE *f) { 10 | f->mode |= f->mode - 1; 11 | if (f->flags & F_NOWR) { 12 | f->flags |= F_ERR; 13 | return EOF; 14 | } 15 | 16 | /* Clear read buffer (easier than summoning nasal demons) */ 17 | f->rpos = f->rend = 0; 18 | 19 | /* Activate write through the buffer. */ 20 | f->wpos = f->wbase = f->buf; 21 | f->wend = f->buf + f->buf_size; 22 | 23 | return 0; 24 | } 25 | 26 | size_t __fwritex(const char *restrict s, size_t l, FILE *restrict f) { 27 | size_t i = 0; 28 | 29 | if (!f->wend && __towrite(f)) return 0; 30 | 31 | if (l > f->wend - f->wpos) return f->write(f, s, l); 32 | 33 | if (f->lbf >= 0) { 34 | /* Match /^(.*\n|)/ */ 35 | for (i = l; i && s[i - 1] != '\n'; i--); 36 | if (i) { 37 | if (f->write(f, s, i) < i) 38 | return i; 39 | s += i; 40 | l -= i; 41 | } 42 | } 43 | 44 | memcpy(f->wpos, s, l); 45 | f->wpos += l; 46 | return l + i; 47 | } 48 | 49 | size_t fwrite(const void *restrict src, size_t size, size_t count, FILE *restrict f) { 50 | size_t k, l = size * count; 51 | if (!l) return l; 52 | k = __fwritex(src, l, f); 53 | return k == l ? count : k / size; 54 | } 55 | 56 | int fflush(FILE *f) { 57 | /* If writing, flush output */ 58 | if (f->wpos != f->wbase) { 59 | f->write(f, 0, 0); 60 | if (!f->wpos) { 61 | return EOF; 62 | } 63 | } 64 | 65 | /* If reading, sync position, per POSIX */ 66 | if (f->rpos != f->rend) f->seek(f, f->rpos - f->rend, SEEK_CUR); 67 | 68 | /* Clear read and write modes */ 69 | f->wpos = f->wbase = f->wend = 0; 70 | f->rpos = f->rend = 0; 71 | 72 | return 0; 73 | } 74 | 75 | int fclose(FILE *f) { 76 | int r; 77 | int perm; 78 | 79 | if (!(perm = f->flags & F_PERM)) { 80 | if (f->prev) f->prev->next = f->next; 81 | if (f->next) f->next->prev = f->prev; 82 | } 83 | 84 | r = fflush(f); 85 | r |= f->close(f); 86 | 87 | // free(f->getln_buf); FIXME not implemented 88 | if (!perm) kfree(f); 89 | 90 | return r; 91 | } 92 | 93 | long ftell(FILE *f) { 94 | off_t pos = f->seek(f, 0, 95 | (f->flags & F_APP) && f->wpos != f->wbase 96 | ? SEEK_END : SEEK_CUR); 97 | if (pos >= 0) { 98 | /* Adjust for data in buffer. */ 99 | if (f->rend) 100 | pos += f->rpos - f->rend; 101 | else if (f->wbase) 102 | pos += f->wpos - f->wbase; 103 | } 104 | if (pos > LONG_MAX) { 105 | errno = EOVERFLOW; 106 | return -1; 107 | } 108 | return (long) pos; 109 | } 110 | -------------------------------------------------------------------------------- /libc/stdio.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #define EOF (-1) 7 | 8 | #define F_PERM 1 9 | #define F_NORD 4 10 | #define F_NOWR 8 11 | #define F_EOF 16 12 | #define F_ERR 32 13 | #define F_SVB 64 14 | #define F_APP 128 15 | 16 | #define SEEK_SET 0 17 | #define SEEK_CUR 1 18 | #define SEEK_END 2 19 | 20 | // _IO_FILE definitions 21 | #define BUFSIZ 1024 22 | #define UNGET 8 23 | 24 | // Unsigned numbers 25 | #define PRIu32 "%u" 26 | #define PRIu64 "%llu" 27 | 28 | // Numbers as hex (ex. uint32_t) 29 | #define PRIx32 "%Xh" 30 | #define PRIx64 "%llXh" 31 | 32 | // Numbers as zero-padded hex (ex. uint32_t) 33 | #define PRIX32 "%08Xh" 34 | #define PRIX64 "%016llXh" 35 | #define PRIX64S "%08llXh" // 64-bit w/ 32-bit padding 36 | 37 | // Numerical pointers as zero-padded hex (ex. uintptr_t) 38 | #define PRIXUPTR "0x%08X" 39 | #define PRIXUPTR64 "0x%016llX" 40 | #define PRIXUPTR64S "0x%08llX" // 64-bit w/ 32-bit padding 41 | 42 | // Pointer value as zero-padded hex (ex. void *) 43 | #define PRIXPTR "%010P" 44 | 45 | typedef struct _IO_FILE FILE; 46 | 47 | struct _IO_FILE { 48 | unsigned flags; 49 | char *rpos, *rend; 50 | char *wend, *wpos, *wbase; 51 | 52 | size_t (*read)(FILE *, char *, size_t); 53 | 54 | size_t (*write)(FILE *, const char *, size_t); 55 | 56 | off_t (*seek)(FILE *, off_t, int); 57 | 58 | int (*close)(FILE *); 59 | 60 | char *buf; 61 | size_t buf_size; 62 | FILE *prev, *next; 63 | int fd; 64 | signed char mode; // 'r' or 'w' I guess 65 | signed char lbf; // Line buffer (format?) 66 | int lock; 67 | void *cookie; 68 | off_t off; 69 | }; 70 | 71 | // TODO flesh out 72 | struct stat { 73 | off_t st_size; 74 | }; 75 | 76 | extern FILE *stdin; 77 | extern FILE *stdout; 78 | extern FILE *stderr; 79 | 80 | // --- Internal 81 | 82 | int __towrite(FILE *f); 83 | 84 | size_t __fwritex(const char *restrict s, size_t l, FILE *restrict f); 85 | 86 | 87 | // --- File 88 | 89 | size_t fread(void *restrict dest, size_t size, size_t count, FILE *restrict f); 90 | 91 | size_t fwrite(const void *restrict src, size_t size, size_t count, FILE *restrict f); 92 | 93 | int fflush(FILE *f); 94 | 95 | FILE *fopen(const char *filename, const char *mode); 96 | 97 | int fclose(FILE *f); 98 | 99 | // int fstat(int fd, struct stat *st); FIXME once fds are implemented 100 | 101 | int stat(const char *filename, struct stat *st); 102 | 103 | int fseek(FILE *f, off_t off, int origin); 104 | 105 | long ftell(FILE *f); 106 | 107 | #define ferror(f) (f == NULL || !!(f->flags & F_ERR)) 108 | 109 | #define feof(f) (!!(f->flags & F_EOF)) 110 | 111 | // --- Print 112 | 113 | int printf(const char *restrict fmt, ...); 114 | 115 | int vprintf(const char *restrict fmt, va_list ap); 116 | 117 | int fprintf(FILE *restrict f, const char *restrict fmt, ...); 118 | 119 | int sprintf(char *restrict s, const char *restrict fmt, ...); 120 | 121 | int snprintf(char *restrict s, size_t n, const char *restrict fmt, ...); 122 | 123 | int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap); 124 | 125 | int vsprintf(char *restrict s, const char *restrict fmt, va_list ap); 126 | 127 | int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list ap); -------------------------------------------------------------------------------- /libc/stdio/fprintf.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int fprintf(FILE *restrict f, const char *restrict fmt, ...) { 4 | int ret; 5 | va_list ap; 6 | va_start(ap, fmt); 7 | ret = vfprintf(f, fmt, ap); 8 | va_end(ap); 9 | return ret; 10 | } -------------------------------------------------------------------------------- /libc/stdio/printf.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int printf(const char *restrict fmt, ...) { 4 | int ret; 5 | va_list ap; 6 | va_start(ap, fmt); 7 | ret = vfprintf(stdout, fmt, ap); 8 | va_end(ap); 9 | return ret; 10 | } -------------------------------------------------------------------------------- /libc/stdio/snprintf.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int snprintf(char *restrict s, size_t n, const char *restrict fmt, ...) { 4 | int ret; 5 | va_list ap; 6 | va_start(ap, fmt); 7 | ret = vsnprintf(s, n, fmt, ap); 8 | va_end(ap); 9 | return ret; 10 | } -------------------------------------------------------------------------------- /libc/stdio/sprintf.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int sprintf(char *restrict s, const char *restrict fmt, ...) { 4 | int ret; 5 | va_list ap; 6 | va_start(ap, fmt); 7 | ret = vsprintf(s, fmt, ap); 8 | va_end(ap); 9 | return ret; 10 | } 11 | -------------------------------------------------------------------------------- /libc/stdio/vprintf.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int vprintf(const char *restrict fmt, va_list ap) { 4 | return vfprintf(stdout, fmt, ap); 5 | } -------------------------------------------------------------------------------- /libc/stdio/vsnprintf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct cookie { 7 | char *s; 8 | size_t n; 9 | }; 10 | 11 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) 12 | 13 | static size_t sn_write(FILE *f, const char *s, size_t l) { 14 | struct cookie *c = f->cookie; 15 | size_t k = MIN(c->n, f->wpos - f->wbase); 16 | if (k) { 17 | memcpy(c->s, f->wbase, k); 18 | c->s += k; 19 | c->n -= k; 20 | } 21 | k = MIN(c->n, l); 22 | if (k) { 23 | memcpy(c->s, s, k); 24 | c->s += k; 25 | c->n -= k; 26 | } 27 | *c->s = 0; 28 | f->wpos = f->wbase = f->buf; 29 | /* pretend to succeed, even if we discarded extra data */ 30 | return l; 31 | } 32 | 33 | int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list ap) { 34 | char buf[1]; 35 | char dummy[1]; 36 | struct cookie c = {.s = n ? s : dummy, .n = n ? n - 1 : 0}; 37 | FILE f = { 38 | .lbf = EOF, 39 | .write = sn_write, 40 | .lock = -1, 41 | .buf = buf, 42 | .cookie = &c, 43 | }; 44 | 45 | if (n > INT_MAX) { 46 | errno = EOVERFLOW; 47 | return -1; 48 | } 49 | 50 | *c.s = 0; 51 | return vfprintf(&f, fmt, ap); 52 | } -------------------------------------------------------------------------------- /libc/stdio/vsprintf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int vsprintf(char *restrict s, const char *restrict fmt, va_list ap) { 5 | return vsnprintf(s, INT_MAX, fmt, ap); 6 | } 7 | -------------------------------------------------------------------------------- /libc/string.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | #include "stdio.h" 3 | 4 | #include 5 | 6 | // FIXME 7 | #include "../kernel/kmalloc.h" 8 | 9 | #define _ALIGN (sizeof(size_t)) 10 | #define _ONES ((size_t) - 1 / UCHAR_MAX) 11 | #define _HIGHS (_ONES * (UCHAR_MAX / 2 + 1)) 12 | #define _HASZERO(x) (((x) - _ONES) & ~(x) & _HIGHS) 13 | #define _SS (sizeof(size_t)) 14 | 15 | // One measly byte at a time... 16 | void *memcpy(void *restrict destination, const void *restrict source, size_t num) { 17 | char *s1 = (char *) destination; 18 | const char *s2 = (const char *) source; 19 | 20 | while (num--) { 21 | *s1++ = *s2++; 22 | } 23 | 24 | return destination; 25 | } 26 | 27 | void *memmove(void *destination, const void *source, size_t num) { 28 | char *dest = (char *) destination; 29 | const char *src = (const char *) source; 30 | if (dest <= src) { 31 | while (num--) *dest++ = *src++; 32 | } else { 33 | src += num; 34 | dest += num; 35 | while (num--) *--dest = *--src; 36 | } 37 | return destination; 38 | } 39 | 40 | void *memset(void *const ptr, const int value, size_t num) { 41 | const unsigned char b = (unsigned char) value; 42 | unsigned char *p = (unsigned char *) ptr; 43 | 44 | while (num--) { 45 | *p++ = b; 46 | } 47 | 48 | return ptr; 49 | } 50 | 51 | int memcmp(const void *const s1, const void *const s2, size_t n) { 52 | const unsigned char *p1 = s1; 53 | const unsigned char *p2 = s2; 54 | 55 | while (n--) { 56 | const int r = *p1++ - *p2++; 57 | if (r) return r; 58 | } 59 | 60 | return 0; 61 | } 62 | 63 | __attribute__((no_sanitize("alignment"))) 64 | void *memchr(const void *src, int c, size_t n) { 65 | const unsigned char *s = src; 66 | c = (unsigned char) c; 67 | #ifdef __GNUC__ 68 | for (; ((uintptr_t) s & _ALIGN) && n && *s != c; s++, n--); 69 | if (n && *s != c) { 70 | typedef size_t __attribute__((__may_alias__)) word; 71 | const word *w; 72 | size_t k = _ONES * c; 73 | for (w = (const void *) s; n >= _SS && !_HASZERO(*w ^ k); w++, n -= _SS); 74 | s = (const void *) w; 75 | } 76 | #endif 77 | for (; n && *s != c; s++, n--); 78 | return n ? (void *) s : 0; 79 | } 80 | 81 | size_t strlen(const char *str) { 82 | const char *a = str; 83 | const size_t *w; 84 | for (; (uintptr_t) str % _ALIGN; str++) if (!*str) return str - a; 85 | for (w = (const void *) str; !_HASZERO(*w); w++); 86 | for (str = (const void *) w; *str; str++); 87 | return str - a; 88 | } 89 | 90 | size_t strnlen(const char *s, size_t n) { 91 | const char *p = memchr(s, 0, n); 92 | return p ? p - s : n; 93 | } 94 | 95 | int strcmp(const char *const str1, const char *const str2) { 96 | const unsigned char *p1 = (unsigned char *) str1; 97 | const unsigned char *p2 = (unsigned char *) str2; 98 | 99 | while (*p1 != '\0' && *p1 == *p2) { 100 | p1++, p2++; 101 | } 102 | 103 | return *p1 - *p2; 104 | } 105 | 106 | int strncmp(const char *str1, const char *str2, size_t num) { 107 | while (*str1 && num && (*str1 == *str2)) { 108 | ++str1; 109 | ++str2; 110 | --num; 111 | } 112 | return num == 0 ? 0 : *(unsigned char *) str1 - *(unsigned char *) str2; 113 | } 114 | 115 | char *strcpy(char *destination, const char *source) { 116 | char *rc = destination; 117 | while ((*destination++ = *source++)); 118 | return rc; 119 | } 120 | 121 | char *strncpy(char *restrict s1, const char *restrict s2, size_t n) { 122 | char *rc = s1; 123 | while ((n > 0) && (*s1++ = *s2++)) --n; 124 | while (n-- > 1) *s1++ = '\0'; 125 | return rc; 126 | } 127 | 128 | char *strdup(const char *str) { 129 | size_t len = strlen(str) + 1; 130 | char *new = kmalloc(len); 131 | if (new == NULL) return NULL; 132 | return memcpy(new, str, len); 133 | } 134 | 135 | __attribute__((no_sanitize("alignment"))) 136 | char *__strchrnul(const char *s, int c) { 137 | c = (unsigned char) c; 138 | if (!c) return (char *) s + strlen(s); 139 | 140 | #ifdef __GNUC__ 141 | typedef size_t __attribute__((__may_alias__)) word; 142 | const word *w; 143 | for (; (uintptr_t) s % _ALIGN; s++) 144 | if (!*s || *(unsigned char *) s == c) return (char *) s; 145 | size_t k = _ONES * c; 146 | for (w = (void *) s; !_HASZERO(*w) && !_HASZERO(*w ^ k); w++); 147 | s = (void *) w; 148 | #endif 149 | for (; *s && *(unsigned char *) s != c; s++); 150 | return (char *) s; 151 | } 152 | 153 | char *strchr(const char *s, int c) { 154 | char *r = __strchrnul(s, c); 155 | return *(unsigned char *) r == (unsigned char) c ? r : 0; 156 | } 157 | 158 | size_t strlcpy(char *d, const char *s, size_t n) { 159 | char *d0 = d; 160 | size_t *wd; 161 | 162 | if (!n--) goto finish; 163 | #ifdef __GNUC__ 164 | typedef size_t __attribute__((__may_alias__)) word; 165 | const word *ws; 166 | if (((uintptr_t) s & _ALIGN) == ((uintptr_t) d & _ALIGN)) { 167 | for (; ((uintptr_t) s & _ALIGN) && n && (*d = *s); n--, s++, d++); 168 | if (n && *s) { 169 | wd = (void *) d; 170 | ws = (const void *) s; 171 | for (; n >= sizeof(size_t) && !_HASZERO(*ws); 172 | n -= sizeof(size_t), ws++, wd++) 173 | *wd = *ws; 174 | d = (void *) wd; 175 | s = (const void *) ws; 176 | } 177 | } 178 | #endif 179 | for (; n && (*d = *s); n--, s++, d++); 180 | *d = 0; 181 | finish: 182 | return d - d0 + strlen(s); 183 | } 184 | 185 | 186 | #define PATH_LOOKAHEAD(p, i, c) ((i < len) && (p[i] == c)) 187 | 188 | // FIXME insane crazy stupid code but it works, I guess 189 | void path_append(char *dest, const char *path, const char *app, size_t len) { 190 | size_t i = 0, out_idx = 0, dir_idx = 0; 191 | 192 | // Skip existing path if necessary 193 | if (app != NULL && app[0] == '/') goto append; 194 | 195 | while (i < len && out_idx < len && path[i] != 0) { 196 | if (path[i] == '/') { 197 | if (PATH_LOOKAHEAD(path, i + 1, '.')) { 198 | if (PATH_LOOKAHEAD(path, i + 2, '.') 199 | && (PATH_LOOKAHEAD(path, i + 3, '/') 200 | || PATH_LOOKAHEAD(path, i + 3, 0))) { 201 | out_idx = dir_idx + 1; 202 | i += 3; 203 | while (PATH_LOOKAHEAD(path, i, '/')) i++; 204 | continue; 205 | } else if (PATH_LOOKAHEAD(path, i + 2, '/') 206 | || PATH_LOOKAHEAD(path, i + 2, 0)) { 207 | i += 2; 208 | continue; 209 | } 210 | } else if (PATH_LOOKAHEAD(path, i + 1, '/')) { 211 | i++; 212 | continue; 213 | } 214 | dir_idx = out_idx; 215 | } 216 | 217 | dest[out_idx] = path[i]; 218 | i++; 219 | out_idx++; 220 | } 221 | 222 | i = 0; 223 | if (app == NULL || app[0] == 0) goto close; 224 | 225 | // Check for leading . or .. 226 | if (app[i] == '.') { 227 | if (PATH_LOOKAHEAD(app, i + 1, '/')) { 228 | i += 2; 229 | } else if (PATH_LOOKAHEAD(app, i + 1, 0)) { 230 | goto close; 231 | } else if (PATH_LOOKAHEAD(app, i + 1, '.') 232 | && (PATH_LOOKAHEAD(app, i + 2, '/') 233 | || PATH_LOOKAHEAD(app, i + 2, 0))) { 234 | out_idx = dir_idx + 1; 235 | i += 2; 236 | } 237 | } 238 | 239 | if (out_idx && dest[out_idx - 1] != '/' && out_idx < len) dest[dir_idx = out_idx++] = '/'; // Add trailing slash 240 | while (i < len && app[i] == '/') i++; // Skip leading slash(es) 241 | 242 | append: 243 | while (i < len && out_idx < len && app[i] != 0) { 244 | if (app[i] == '/') { 245 | if (PATH_LOOKAHEAD(app, i + 1, '.')) { 246 | if (PATH_LOOKAHEAD(app, i + 2, '.') 247 | && (PATH_LOOKAHEAD(app, i + 3, '/') 248 | || PATH_LOOKAHEAD(app, i + 3, 0))) { 249 | out_idx = dir_idx + 1; 250 | i += 3; 251 | while (PATH_LOOKAHEAD(app, i, '/')) i++; 252 | continue; 253 | } else if (PATH_LOOKAHEAD(app, i + 2, '/') 254 | || PATH_LOOKAHEAD(app, i + 2, 0)) { 255 | i += 2; 256 | continue; 257 | } 258 | } else if (PATH_LOOKAHEAD(app, i + 1, '/')) { 259 | i++; 260 | continue; 261 | } 262 | dir_idx = out_idx; 263 | } 264 | 265 | dest[out_idx] = app[i]; 266 | i++; 267 | out_idx++; 268 | } 269 | 270 | close: 271 | dest[out_idx] = 0; 272 | } -------------------------------------------------------------------------------- /libc/string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define ALIGN(x, a) __ALIGN_MASK(x,(__typeof__(x))(a)-1) 6 | #define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) 7 | 8 | void *memcpy(void *restrict destination, const void *restrict source, size_t num); 9 | 10 | void *memmove(void *destination, const void *source, size_t num); 11 | 12 | void *memset(void *ptr, int value, size_t num); 13 | 14 | int memcmp(const void *s1, const void *s2, size_t n); 15 | 16 | void *memchr(const void *src, int c, size_t n); 17 | 18 | size_t strlen(const char *str); 19 | 20 | size_t strnlen(const char *s, size_t n); 21 | 22 | int strcmp(const char *str1, const char *str2); 23 | 24 | int strncmp(const char *str1, const char *str2, size_t num); 25 | 26 | char *strcpy(char *destination, const char *source); 27 | 28 | char *strncpy(char *restrict s1, const char *restrict s2, size_t n); 29 | 30 | char *strdup(const char *str); 31 | 32 | char *strchr(const char *s, int c); 33 | 34 | size_t strlcpy(char *d, const char *s, size_t n); 35 | 36 | void path_append(char *dest, const char *path, const char *app, size_t len); -------------------------------------------------------------------------------- /libc/vector.c: -------------------------------------------------------------------------------- 1 | #include "vector.h" 2 | #include "math.h" 3 | 4 | #include 5 | 6 | // FIXME 7 | #include "../kernel/kmalloc.h" 8 | 9 | #define GROWTH_FACTOR 1.5 10 | #define DEFAULT_COUNT_OF_ELEMENETS 8 11 | #define MINIMUM_COUNT_OF_ELEMENTS 2 12 | 13 | // ---------------------------------------------------------------------------- 14 | 15 | // vc_vector structure 16 | 17 | struct vc_vector { 18 | size_t count; 19 | size_t element_size; 20 | size_t reserved_size; 21 | char *data; 22 | vc_vector_deleter *deleter; 23 | }; 24 | 25 | // ---------------------------------------------------------------------------- 26 | 27 | // auxillary methods 28 | 29 | bool vc_vector_realloc(vc_vector *vector, size_t new_count) { 30 | const size_t new_size = new_count * vector->element_size; 31 | char *new_data = (char *) krealloc(vector->data, new_size); 32 | if (!new_data) { 33 | return false; 34 | } 35 | 36 | vector->reserved_size = new_size; 37 | vector->data = new_data; 38 | return true; 39 | } 40 | 41 | // [first_index, last_index) 42 | void vc_vector_call_deleter(vc_vector *vector, size_t first_index, size_t last_index) { 43 | for (size_t i = first_index; i < last_index; ++i) { 44 | vector->deleter(vc_vector_at(vector, i)); 45 | } 46 | } 47 | 48 | void vc_vector_call_deleter_all(vc_vector *vector) { 49 | vc_vector_call_deleter(vector, 0, vc_vector_count(vector)); 50 | } 51 | 52 | // ---------------------------------------------------------------------------- 53 | 54 | // Contol 55 | 56 | vc_vector *vc_vector_create(size_t count_elements, size_t size_of_element, vc_vector_deleter *deleter) { 57 | vc_vector *v = (vc_vector *) kmalloc(sizeof(vc_vector)); 58 | if (v != NULL) { 59 | v->data = NULL; 60 | v->count = 0; 61 | v->element_size = size_of_element; 62 | v->deleter = deleter; 63 | 64 | if (count_elements < MINIMUM_COUNT_OF_ELEMENTS) { 65 | count_elements = DEFAULT_COUNT_OF_ELEMENETS; 66 | } 67 | 68 | if (size_of_element < 1 || 69 | !vc_vector_realloc(v, count_elements)) { 70 | kfree(v); 71 | v = NULL; 72 | } 73 | } 74 | 75 | return v; 76 | } 77 | 78 | vc_vector *vc_vector_create_copy(const vc_vector *vector) { 79 | vc_vector *new_vector = vc_vector_create(vector->reserved_size / vector->count, 80 | vector->element_size, 81 | vector->deleter); 82 | if (!new_vector) { 83 | return new_vector; 84 | } 85 | 86 | if (memcpy(vector->data, 87 | new_vector->data, 88 | new_vector->element_size * vector->count) == NULL) { 89 | vc_vector_release(new_vector); 90 | new_vector = NULL; 91 | return new_vector; 92 | } 93 | 94 | new_vector->count = vector->count; 95 | return new_vector; 96 | } 97 | 98 | void vc_vector_release(vc_vector *vector) { 99 | if (vector->deleter != NULL) { 100 | vc_vector_call_deleter_all(vector); 101 | } 102 | 103 | if (vector->reserved_size != 0) { 104 | kfree(vector->data); 105 | } 106 | 107 | kfree(vector); 108 | } 109 | 110 | bool vc_vector_is_equals(vc_vector *vector1, vc_vector *vector2) { 111 | const size_t size_vector1 = vc_vector_size(vector1); 112 | if (size_vector1 != vc_vector_size(vector2)) { 113 | return false; 114 | } 115 | 116 | return memcmp(vector1->data, vector2->data, size_vector1) == 0; 117 | } 118 | 119 | float vc_vector_get_growth_factor() { 120 | return GROWTH_FACTOR; 121 | } 122 | 123 | size_t vc_vector_get_default_count_of_elements() { 124 | return DEFAULT_COUNT_OF_ELEMENETS; 125 | } 126 | 127 | size_t vc_vector_struct_size() { 128 | return sizeof(vc_vector); 129 | } 130 | 131 | // ---------------------------------------------------------------------------- 132 | 133 | // Element access 134 | 135 | void *vc_vector_at(vc_vector *vector, size_t index) { 136 | return vector->data + index * vector->element_size; 137 | } 138 | 139 | void *vc_vector_front(vc_vector *vector) { 140 | return vector->data; 141 | } 142 | 143 | void *vc_vector_back(vc_vector *vector) { 144 | return vector->data + (vector->count - 1) * vector->element_size; 145 | } 146 | 147 | void *vc_vector_data(vc_vector *vector) { 148 | return vector->data; 149 | } 150 | 151 | // ---------------------------------------------------------------------------- 152 | 153 | // Iterators 154 | 155 | void *vc_vector_begin(vc_vector *vector) { 156 | return vector->data; 157 | } 158 | 159 | void *vc_vector_end(vc_vector *vector) { 160 | return vector->data + vector->element_size * vector->count; 161 | } 162 | 163 | void *vc_vector_next(vc_vector *vector, void *i) { 164 | return i + vector->element_size; 165 | } 166 | 167 | // ---------------------------------------------------------------------------- 168 | 169 | // Capacity 170 | 171 | bool vc_vector_empty(vc_vector *vector) { 172 | return vector->count == 0; 173 | } 174 | 175 | size_t vc_vector_count(const vc_vector *vector) { 176 | return vector->count; 177 | } 178 | 179 | size_t vc_vector_size(const vc_vector *vector) { 180 | return vector->count * vector->element_size; 181 | } 182 | 183 | size_t vc_vector_max_count(const vc_vector *vector) { 184 | return vector->reserved_size / vector->element_size; 185 | } 186 | 187 | size_t vc_vector_max_size(const vc_vector *vector) { 188 | return vector->reserved_size; 189 | } 190 | 191 | bool vc_vector_reserve_count(vc_vector *vector, size_t new_count) { 192 | if (new_count < vector->count) { 193 | return false; 194 | } else if (!new_count) { 195 | // Shrink to fit 196 | new_count = MAX(1, vector->count); 197 | } 198 | 199 | size_t new_size = vector->element_size * new_count; 200 | if (new_size == vector->reserved_size) { 201 | return true; 202 | } 203 | 204 | return vc_vector_realloc(vector, new_count); 205 | } 206 | 207 | bool vc_vector_reserve_size(vc_vector *vector, size_t new_size) { 208 | return vc_vector_reserve_count(vector, new_size / vector->element_size); 209 | } 210 | 211 | // ---------------------------------------------------------------------------- 212 | 213 | // Modifiers 214 | 215 | void vc_vector_clear(vc_vector *vector) { 216 | if (vector->deleter != NULL) { 217 | vc_vector_call_deleter_all(vector); 218 | } 219 | 220 | vector->count = 0; 221 | } 222 | 223 | bool vc_vector_insert(vc_vector *vector, size_t index, const void *value) { 224 | if (vc_vector_max_count(vector) < vector->count + 1) { 225 | if (!vc_vector_realloc(vector, (uint32_t) (vc_vector_max_count(vector) * GROWTH_FACTOR))) { 226 | return false; 227 | } 228 | } 229 | 230 | if (!memmove(vc_vector_at(vector, index + 1), 231 | vc_vector_at(vector, index), 232 | vector->element_size * (vector->count - index))) { 233 | 234 | return false; 235 | } 236 | 237 | if (memcpy(vc_vector_at(vector, index), 238 | value, vector->element_size) == NULL) { 239 | return false; 240 | } 241 | 242 | ++vector->count; 243 | return true; 244 | } 245 | 246 | bool vc_vector_erase(vc_vector *vector, size_t index) { 247 | if (vector->deleter != NULL) { 248 | vector->deleter(vc_vector_at(vector, index)); 249 | } 250 | 251 | if (!memmove(vc_vector_at(vector, index), 252 | vc_vector_at(vector, index + 1), 253 | vector->element_size * (vector->count - index))) { 254 | return false; 255 | } 256 | 257 | vector->count--; 258 | return true; 259 | } 260 | 261 | bool vc_vector_erase_range(vc_vector *vector, size_t first_index, size_t last_index) { 262 | if (vector->deleter != NULL) { 263 | vc_vector_call_deleter(vector, first_index, last_index); 264 | } 265 | 266 | if (!memmove(vc_vector_at(vector, first_index), 267 | vc_vector_at(vector, last_index), 268 | vector->element_size * (vector->count - last_index))) { 269 | return false; 270 | } 271 | 272 | vector->count -= last_index - first_index; 273 | return true; 274 | } 275 | 276 | bool vc_vector_append(vc_vector *vector, const void *values, size_t count) { 277 | const size_t count_new = count + vc_vector_count(vector); 278 | 279 | if (vc_vector_max_count(vector) < count_new) { 280 | size_t max_count_to_reserved = (uint32_t) (vc_vector_max_count(vector) * GROWTH_FACTOR); 281 | while (count_new > max_count_to_reserved) { 282 | max_count_to_reserved = (uint32_t) (max_count_to_reserved * GROWTH_FACTOR); 283 | } 284 | 285 | if (!vc_vector_realloc(vector, max_count_to_reserved)) { 286 | return false; 287 | } 288 | } 289 | 290 | if (memcpy(vector->data + vector->count * vector->element_size, 291 | values, vector->element_size * count) == NULL) { 292 | return false; 293 | } 294 | 295 | vector->count = count_new; 296 | return true; 297 | } 298 | 299 | bool vc_vector_push_back(vc_vector *vector, const void *value) { 300 | if (!vc_vector_append(vector, value, 1)) { 301 | return false; 302 | } 303 | 304 | return true; 305 | } 306 | 307 | bool vc_vector_pop_back(vc_vector *vector) { 308 | if (vector->deleter != NULL) { 309 | vector->deleter(vc_vector_back(vector)); 310 | } 311 | 312 | vector->count--; 313 | return true; 314 | } 315 | 316 | bool vc_vector_replace(vc_vector *vector, size_t index, const void *value) { 317 | if (vector->deleter != NULL) { 318 | vector->deleter(vc_vector_at(vector, index)); 319 | } 320 | 321 | return memcpy(vc_vector_at(vector, index), 322 | value, 323 | vector->element_size) != NULL; 324 | } 325 | 326 | bool vc_vector_replace_multiple(vc_vector *vector, size_t index, const void *values, size_t count) { 327 | if (vector->deleter != NULL) { 328 | vc_vector_call_deleter(vector, index, index + count); 329 | } 330 | 331 | return memcpy(vc_vector_at(vector, index), 332 | values, 333 | vector->element_size * count) != NULL; 334 | } -------------------------------------------------------------------------------- /libc/vector.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | typedef struct vc_vector vc_vector; 6 | 7 | typedef void (vc_vector_deleter)(void *); 8 | 9 | // ---------------------------------------------------------------------------- 10 | // Control 11 | // ---------------------------------------------------------------------------- 12 | 13 | // Constructs an empty vector with an reserver size for count_elements. 14 | vc_vector *vc_vector_create(size_t count_elements, size_t size_of_element, vc_vector_deleter *deleter); 15 | 16 | // Constructs a copy of an existing vector. 17 | vc_vector *vc_vector_create_copy(const vc_vector *vector); 18 | 19 | // Releases the vector. 20 | void vc_vector_release(vc_vector *vector); 21 | 22 | // Compares vector content 23 | bool vc_vector_is_equals(vc_vector *vector1, vc_vector *vector2); 24 | 25 | // Returns constant value of the vector growth factor. 26 | float vc_vector_get_growth_factor(); 27 | 28 | // Returns constant value of the vector default count of elements. 29 | size_t vc_vector_get_default_count_of_elements(); 30 | 31 | // Returns constant value of the vector struct size. 32 | size_t vc_vector_struct_size(); 33 | 34 | // ---------------------------------------------------------------------------- 35 | // Element access 36 | // ---------------------------------------------------------------------------- 37 | 38 | // Returns the item at index position in the vector. 39 | void *vc_vector_at(vc_vector *vector, size_t index); 40 | 41 | // Returns the first item in the vector. 42 | void *vc_vector_front(vc_vector *vector); 43 | 44 | // Returns the last item in the vector. 45 | void *vc_vector_back(vc_vector *vector); 46 | 47 | // Returns a pointer to the data stored in the vector. The pointer can be used to access and modify the items in the vector. 48 | void *vc_vector_data(vc_vector *vector); 49 | 50 | // ---------------------------------------------------------------------------- 51 | // Iterators 52 | // ---------------------------------------------------------------------------- 53 | 54 | // Returns a pointer to the first item in the vector. 55 | void *vc_vector_begin(vc_vector *vector); 56 | 57 | // Returns a pointer to the imaginary item after the last item in the vector. 58 | void *vc_vector_end(vc_vector *vector); 59 | 60 | // Returns a pointer to the next element of vector after 'i'. 61 | void *vc_vector_next(vc_vector *vector, void *i); 62 | 63 | // ---------------------------------------------------------------------------- 64 | // Capacity 65 | // ---------------------------------------------------------------------------- 66 | 67 | // Returns true if the vector is empty; otherwise returns false. 68 | bool vc_vector_empty(vc_vector *vector); 69 | 70 | // Returns the number of elements in the vector. 71 | size_t vc_vector_count(const vc_vector *vector); 72 | 73 | // Returns the size (in bytes) of occurrences of value in the vector. 74 | size_t vc_vector_size(const vc_vector *vector); 75 | 76 | // Returns the maximum number of elements that the vector can hold. 77 | size_t vc_vector_max_count(const vc_vector *vector); 78 | 79 | // Returns the maximum size (in bytes) that the vector can hold. 80 | size_t vc_vector_max_size(const vc_vector *vector); 81 | 82 | // Resizes the container so that it contains n elements. 83 | bool vc_vector_reserve_count(vc_vector *vector, size_t new_count); 84 | 85 | // Resizes the container so that it contains new_size / element_size elements. 86 | bool vc_vector_reserve_size(vc_vector *vector, size_t new_size); 87 | 88 | // ---------------------------------------------------------------------------- 89 | // Modifiers 90 | // ---------------------------------------------------------------------------- 91 | 92 | // Removes all elements from the vector (without reallocation). 93 | void vc_vector_clear(vc_vector *vector); 94 | 95 | // The container is extended by inserting a new element at position. 96 | bool vc_vector_insert(vc_vector *vector, size_t index, const void *value); 97 | 98 | // Removes from the vector a single element by 'index' 99 | bool vc_vector_erase(vc_vector *vector, size_t index); 100 | 101 | // Removes from the vector a range of elements '[first_index, last_index)'. 102 | bool vc_vector_erase_range(vc_vector *vector, size_t first_index, size_t last_index); 103 | 104 | // Inserts multiple values at the end of the vector. 105 | bool vc_vector_append(vc_vector *vector, const void *values, size_t count); 106 | 107 | // Inserts value at the end of the vector. 108 | bool vc_vector_push_back(vc_vector *vector, const void *value); 109 | 110 | // Removes the last item in the vector. 111 | bool vc_vector_pop_back(vc_vector *vector); 112 | 113 | // Replace value by index in the vector. 114 | bool vc_vector_replace(vc_vector *vector, size_t index, const void *value); 115 | 116 | // Replace multiple values by index in the vector. 117 | bool vc_vector_replace_multiple(vc_vector *vector, size_t index, const void *values, size_t count); 118 | -------------------------------------------------------------------------------- /libc/wchar.c: -------------------------------------------------------------------------------- 1 | #include "wchar.h" 2 | #include "stdio.h" 3 | #include "errno.h" 4 | 5 | #define MB_CUR_MAX 1 // UTF-8 6 | 7 | size_t wcrtomb(char *restrict s, wchar_t wc) { 8 | if (!s) return 1; 9 | if ((unsigned) wc < 0x80) { 10 | *s = (char) wc; 11 | return 1; 12 | } else if (MB_CUR_MAX == 1) { 13 | if (!IS_CODEUNIT(wc)) { 14 | errno = EILSEQ; 15 | return (size_t) -1; 16 | } 17 | *s = (char) wc; 18 | return 1; 19 | } else { 20 | // utf-8 shit... 21 | } 22 | } 23 | 24 | int wctomb(char *s, wchar_t wc) { 25 | if (!s) return 0; 26 | return (int) wcrtomb(s, wc); 27 | } -------------------------------------------------------------------------------- /libc/wchar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define IS_CODEUNIT(c) ((unsigned)(c)-0xdf80 < 0x80) 6 | 7 | typedef __WCHAR_TYPE__ wchar_t; 8 | 9 | int wctomb(char *s, wchar_t wc); 10 | 11 | size_t wcrtomb(char *__restrict, wchar_t); -------------------------------------------------------------------------------- /linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | OUTPUT_FORMAT(elf32-i386) 3 | 4 | SECTIONS { 5 | /* The kernel will live at 3GB + 1MB in the virtual 6 | address space, which will be mapped to 1MB in the 7 | physical address space. */ 8 | . = 0xC0100000; 9 | 10 | /* First put the multiboot header, as it is required to be put very early 11 | early in the image or the bootloader won't recognize the file format. 12 | Next we'll put the .text section. */ 13 | .text : AT(ADDR(.text) - 0xC0000000) 14 | { 15 | *(.multiboot) 16 | *(.text) 17 | } 18 | 19 | /* Read-only data. */ 20 | .rodata ALIGN(4K) : AT(ADDR(.rodata) - 0xC0000000) 21 | { 22 | *(.rodata) 23 | } 24 | 25 | /* Read-write data (initialized) */ 26 | .data ALIGN(4K) : AT(ADDR(.data) - 0xC0000000) 27 | { 28 | *(.data) 29 | } 30 | 31 | /* Read-write data (uninitialized) and stack */ 32 | .bss ALIGN(4K) : AT(ADDR(.bss) - 0xC0000000) 33 | { 34 | _sbss = .; 35 | *(COMMON) 36 | *(.bss) 37 | _ebss = .; 38 | } 39 | } -------------------------------------------------------------------------------- /mkhd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | if [ ! -d "$1" ]; then 3 | echo "Pass build directory as first arg" >&2 4 | exit 1 5 | fi 6 | 7 | rm -f hd.img hd.dmg 8 | if [ "$(uname)" == "Darwin" ]; then 9 | mkdir -p tmp/bin 10 | cp "$1/kernel.bin" tmp/kernel.bin 11 | cp "README" tmp/README 12 | if [ -d "$1/bin" ]; then 13 | gfind "$1/bin" -type f -executable -exec cp {} tmp/bin \; 14 | fi 15 | cp -R assets "tmp/" 16 | 17 | hdiutil create -size 10m -fs exfat -srcfolder tmp hd 18 | qemu-img convert hd.dmg -O qcow2 hd.img 19 | rm -r tmp # hd.dmg 20 | else 21 | truncate -s 100M hd.img 22 | mkfs -t exfat hd.img 23 | LDEV="$(udisksctl loop-setup -f hd.img | cut -d' ' -f5 | head -c-2)" 24 | MPAT="$(udisksctl mount -b "$LDEV" | cut -d' ' -f4 | head -c-2)" 25 | mkdir "$MPAT/bin" 26 | cp "$1/kernel.bin" "$MPAT/kernel.bin" 27 | cp "README" "$MPAT/README" 28 | if [ -d "$1/bin" ]; then 29 | find "$1/bin" -type f -executable -exec cp {} "$MPAT/bin" \; 30 | fi 31 | cp -R assets "$MPAT/" 32 | sync 33 | udisksctl unmount -b "$LDEV" 34 | udisksctl loop-delete -b "$LDEV" 35 | fi -------------------------------------------------------------------------------- /mkiso.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | if [ ! -f "$1" ]; then 3 | echo "Pass kernel as first arg" >&2 4 | exit 1 5 | fi 6 | 7 | mkdir -p iso/boot/grub 8 | cp "$1" iso/boot/kernel.bin 9 | cat > iso/boot/grub/grub.cfg <> 22) ; 768 10 | 11 | section .data 12 | align 0x1000 13 | boot_page_directory: 14 | ; 4MiB lower-half kernel page 15 | dd 0x83 16 | times (KERNEL_PAGE_NUMBER - 1) dd 0 17 | 18 | ; 4MiB higher-half kernel page 19 | dd 0x83 20 | times (1024 - KERNEL_PAGE_NUMBER - 1) dd 0 21 | 22 | section .multiboot 23 | align 4 24 | ; header 25 | dd MAGIC 26 | dd FLAGS 27 | dd CHECKSUM 28 | 29 | ; address tag 30 | dd 0 ; header_addr 31 | dd 0 ; load_addr 32 | dd 0 ; load_end_addr 33 | dd 0 ; bss_end_addr 34 | dd 0 ; entry_addr 35 | 36 | ; graphics tag 37 | dd 0 ; mode_type 38 | dd 800 ; width 39 | dd 600 ; height 40 | dd 32 ; depth 41 | 42 | ; Create bootstrap stack 43 | section .bss 44 | align 16 45 | stack_bottom: 46 | resb 0x4000 ; 16 KiB 47 | stack_top: 48 | 49 | section .text 50 | global _start:function (_start.end - _start) 51 | _start: 52 | mov ecx, (boot_page_directory - KERNEL_VIRTUAL_BASE) 53 | mov cr3, ecx ; Load boot_page_directory into CR3 54 | 55 | mov ecx, cr4 56 | or ecx, (1 << 4) ; Set PSE bit in CR4 to enable 4MB pages. 57 | mov cr4, ecx 58 | 59 | mov ecx, cr0 60 | or ecx, (1 << 31) ; Set PG bit in CR0 to enable paging. 61 | mov cr0, ecx 62 | 63 | lea ecx, [.start_higher_half] ; Far jump 64 | jmp ecx 65 | 66 | .start_higher_half: 67 | ; Unmap lower-half kernel page 68 | mov dword [boot_page_directory], 0 69 | invlpg [0] 70 | 71 | ; Set up stack 72 | mov esp, stack_top 73 | 74 | ; Save multiboot information 75 | push ebx ; multiboot_info 76 | push eax ; multiboot_magic 77 | 78 | ; Enable SSE 79 | mov eax, cr0 80 | and ax, ~(1 << 2) ; clr CR0.EM 81 | or ax, (1 << 1) ; set CR0.MP 82 | mov cr0, eax 83 | mov eax, cr4 84 | or ax, (3 << 9) ; set CR4.OSFXSR | CR4.OSXMMEXCPT 85 | mov cr4, eax 86 | 87 | ; Initialize GDT & IDT 88 | extern init_descriptor_tables 89 | call init_descriptor_tables 90 | 91 | ; Enter kernel 92 | extern kernel_main 93 | call kernel_main 94 | 95 | cli 96 | .hang: 97 | hlt 98 | jmp .hang 99 | .end: 100 | --------------------------------------------------------------------------------